Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Unified Diff: common/data/base128/base128.go

Issue 2538553003: Add base128 encoding library. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | common/data/base128/base128_test.go » ('j') | common/data/base128/base128_test.go » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)
+}
« no previous file with comments | « no previous file | common/data/base128/base128_test.go » ('j') | common/data/base128/base128_test.go » ('J')

Powered by Google App Engine
This is Rietveld 408576698