Chromium Code Reviews| Index: common/data/base128/base128.go |
| diff --git a/common/data/base128/base128.go b/common/data/base128/base128.go |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f80ce36105f6e91f7b302154636fbcff302d7a92 |
| --- /dev/null |
| +++ b/common/data/base128/base128.go |
| @@ -0,0 +1,113 @@ |
| +// Copyright 2016 The LUCI Authors. All rights reserved. |
| +// Use of this source code is governed under the Apache License, Version 2.0 |
| +// that can be found in the LICENSE file. |
| + |
| +// Package base128 implements base128 encoding and decoding. |
| +// |
| +// Encoded results are UTF8-safe, and will retain the same memcmp sorting |
| +// properties of the input data. |
| +package base128 |
| + |
| +import "errors" |
| + |
| +var ( |
| + // ErrLength is returned from the Decode* methods if the input has an |
| + // impossible length. |
| + ErrLength = errors.New("base128: invalid length base128 string") |
| + |
| + // ErrBit is returned from the Decode* methods if the input has a byte with |
| + // the high-bit set (e.g. 0x80). This will never be the case for strings |
| + // produced from the Encode* methods in this package. |
| + ErrBit = errors.New("base128: high bit set in base128 string") |
| +) |
| + |
| +// Encode encodes src into EncodedLen(len(src)) bytes of dst. As a convenience, |
| +// it returns the number of bytes written to dst, but this value is always |
| +// EncodedLen(len(src)). |
| +// |
| +// Encode implements base128 encoding. |
| +func Encode(dst, src []byte) int { |
| + ret := EncodedLen(len(src)) |
| + if cap(dst) < ret { |
|
dnj
2016/11/29 02:03:13
I think capacity is misleading, and can lead to in
iannucci
2016/11/29 02:14:55
Done.
|
| + panic("dst has insufficient capacity") |
| + } |
| + dst = dst[:0] |
| + whichByte := 0 |
|
dnj
2016/11/29 02:03:13
nit: Just make this a uint, and cycle 1..7 instead
iannucci
2016/11/29 02:14:55
Done.
|
| + bufByte := byte(0) |
| + for _, v := range src { |
| + dst = append(dst, bufByte|(v>>uint(whichByte+1))) |
| + bufByte = (v&(1<<uint(whichByte+1)) - 1) << uint(6-whichByte) |
| + if whichByte == 6 { |
| + dst = append(dst, bufByte) |
| + bufByte = 0 |
|
dnj
2016/11/29 02:03:13
Instead of using modulus below, just reset whichby
iannucci
2016/11/29 02:14:55
Done.
|
| + } |
| + whichByte = (whichByte + 1) % 7 |
|
dnj
2016/11/29 02:03:13
whichByte += 1
iannucci
2016/11/29 02:14:55
Done.
|
| + } |
| + dst = append(dst, bufByte) |
| + return ret |
| +} |
| + |
| +// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual |
| +// number of bytes written to dst. |
| +// |
| +// If Decode encounters invalid input, it returns an error describing the |
| +// failure. |
| +func Decode(dst, src []byte) (int, error) { |
| + dLen := DecodedLen(len(src)) |
| + if EncodedLen(dLen) != len(src) { |
| + return 0, ErrLength |
| + } |
| + if cap(dst) < dLen { |
|
dnj
2016/11/29 02:03:13
Same RE cap, uint comments, etc.
iannucci
2016/11/29 02:14:55
Done.
|
| + panic("dst has insufficient capacity") |
| + } |
| + dst = dst[:0] |
| + whichByte := 0 |
| + bufByte := byte(0) |
| + for _, v := range src { |
| + if (v & 0x80) != 0 { |
| + return len(dst), ErrBit |
| + } |
| + if whichByte > 0 { |
| + dst = append(dst, bufByte|(v>>uint(7-whichByte))) |
| + } |
| + bufByte = v << uint(whichByte+1) |
| + whichByte = (whichByte + 1) % 8 |
| + } |
| + return len(dst), nil |
| +} |
| + |
| +// DecodeString returns the bytes represented by the base128 string s. |
| +func DecodeString(s string) ([]byte, error) { |
| + src := []byte(s) |
| + dst := make([]byte, DecodedLen(len(src))) |
|
dnj
2016/11/29 02:03:13
Doing "DecodedLen" calculation twice here. Fall th
iannucci
2016/11/29 02:14:55
meh
|
| + _, err := Decode(dst, src) |
|
dnj
2016/11/29 02:03:13
nit: if _, err := ...; err != nil {}
iannucci
2016/11/29 02:14:55
Done.
|
| + if err != nil { |
| + return nil, err |
| + } |
| + return dst, nil |
| +} |
| + |
| +// DecodedLen returns the number of bytes `encLen` encoded bytes decodes to. |
| +func DecodedLen(encLen int) int { |
| + ret := (encLen / 8) * 7 |
|
dnj
2016/11/29 02:03:13
Consider:
func DecodedLen(v int) int {
return (v
iannucci
2016/11/29 02:14:55
Done.
|
| + if v := encLen % 8; v > 0 { |
| + ret += v - 1 |
| + } |
| + return ret |
| +} |
| + |
| +// EncodedLen returns the number of bytes that `dataLen` bytes will encode to. |
| +func EncodedLen(dataLen int) int { |
| + pre := ((dataLen * 8) - 1) |
|
dnj
2016/11/29 02:03:13
Consider:
func EncodedLen(v int) int {
return (((
iannucci
2016/11/29 02:14:55
Done.
|
| + if pre < 0 { |
| + return 0 |
| + } |
| + return (pre / 7) + 1 |
| +} |
| + |
| +// EncodeToString returns the base128 encoding of src. |
| +func EncodeToString(src []byte) string { |
| + dst := make([]byte, EncodedLen(len(src))) |
|
dnj
2016/11/29 02:03:13
nit: you're calculating EncodedLen twice in Encode
iannucci
2016/11/29 02:14:55
meh
|
| + Encode(dst, src) |
| + return string(dst) |
| +} |