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

Unified Diff: common/cmpbin/number.go

Issue 1219323002: Rename funnybase and add more serializations. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@master
Patch Set: fixes Created 5 years, 5 months 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 | « common/cmpbin/float_test.go ('k') | common/cmpbin/number_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: common/cmpbin/number.go
diff --git a/common/cmpbin/number.go b/common/cmpbin/number.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3ac311958c3aaef2331ab367b6292d04832e258
--- /dev/null
+++ b/common/cmpbin/number.go
@@ -0,0 +1,184 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package cmpbin
+
+import (
+ "errors"
+ "io"
+ "math"
+)
+
+// MaxIntLenN is the maximum length of a cmpbin-encoded N-bit integer
+// (signed or unsigned).
+const (
+ MaxIntLen16 = 3
+ MaxIntLen32 = 5
+ MaxIntLen64 = 9
+)
+
+// ErrOverflow is returned when reading an number which is too large for the
+// destination type (either uint64 or int64)
+var ErrOverflow = errors.New("cmpbin: varint overflows")
+
+// ErrUnderflow is returned when reading an number which is too small for the
+// destination type (either uint64 or int64)
+var ErrUnderflow = errors.New("cmpbin: uvarint underflows")
+
+var paddingMasks = [...]uint64{
+ 0xFFFFFFFF00000000,
+ 0xFFFF0000,
+ 0xFF00,
+ 0xF0,
+ 0xC,
+ 0x2,
+ 0x1,
+}
+
+// Calculate the log2 of the unsigned value v.
+//
+// This is used to find the position of the highest-set bit in v.
+//
+// from https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+// 32 bit implementation extended to 64 bits
+func uint64Log2(v uint64) uint {
+ log := uint(0)
+ for i, m := range paddingMasks {
+ if v&m != 0 {
+ shift := uint(1<<uint(len(paddingMasks)-2)) >> uint(i)
+ v >>= shift
+ log |= shift
+ }
+ }
+ return log + 1
+}
+
+// WriteInt val as a cmpbin Int to the ByteWriter. Returns the number of bytes
+// written. Only returns an error if the underlying ByteWriter returns an error.
+func WriteInt(w io.ByteWriter, val int64) (int, error) {
+ var inv byte
+ if val < 0 {
+ inv = 0xff
+ }
+ mag := uint64(val)
+ if inv != 0 {
+ mag = -mag
+ }
+ return writeSignMag(w, mag, inv)
+}
+
+// WriteUint writes mag to the ByteWriter. Returns the number of bytes written.
+// Only returns an error if the underlying ByteWriter returns an error.
+func WriteUint(w io.ByteWriter, mag uint64) (int, error) {
+ return writeSignMag(w, mag, 0)
+}
+
+// ReadInt decodes a cmpbin-encoded number from a ByteReader. It returns the
+// decoded value and the number of bytes read. The error may be
+// Err{Over,Under}flow if the number is out of bounds. It may also return an
+// error if the ByteReader returns an error.
+func ReadInt(r io.ByteReader) (ret int64, n int, err error) {
+ pos, sigs, mag, n, err := readSignMag(r)
+ if err != nil {
+ return
+ }
+ if pos {
+ if sigs > 63 {
+ err = ErrOverflow
+ } else {
+ ret = int64(mag)
+ }
+ } else {
+ if mag > uint64(-math.MinInt64) {
+ err = ErrUnderflow
+ } else {
+ ret = int64(-mag)
+ }
+ }
+ return
+}
+
+// ReadUint decodes a cmpbin-encoded positive number from a ByteReader. It
+// returns the decoded value and the number of bytes read. The erorr may be
+// Err{Over,Under}flow if the number is out of bounds. It may also return an
+// error if the ByteReader returns an error.
+func ReadUint(r io.ByteReader) (mag uint64, n int, err error) {
+ pos, _, mag, n, err := readSignMag(r)
+ if err != nil {
+ return
+ }
+ if !pos {
+ err = ErrUnderflow
+ }
+ return
+}
+
+func writeSignMag(w io.ByteWriter, mag uint64, inv byte) (n int, err error) {
+ sigs := uint64Log2(mag)
+
+ wb := func(b byte) error {
+ n++
+ return w.WriteByte(b)
+ }
+
+ if err = wb(byte(0x80|(sigs-1)) ^ inv); err != nil {
+ return
+ }
+
+ for sigs > 8 {
+ sigs -= 8
+
+ if err = wb(byte(mag>>sigs) ^ inv); err != nil {
+ return
+ }
+ }
+ if sigs != 0 {
+ if err = wb(byte(mag<<(8-sigs)) ^ inv); err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+func readSignMag(r io.ByteReader) (positive bool, sigs uint, mag uint64, n int, err error) {
+ var inv byte
+
+ rb := func() (byte, error) {
+ n++
+ return r.ReadByte()
+ }
+
+ b0, err := rb()
+ if err != nil {
+ return
+ }
+ positive = true
+ if b0&0x80 == 0 {
+ positive = false
+ inv = 0xff
+ }
+
+ sigs = uint((b0^inv)&0x7f) + 1
+ if sigs > 64 {
+ err = ErrOverflow
+ return
+ }
+
+ numBytes := int((sigs+7)>>3) + 1
+
+ var b byte
+ shift := uint(64 - 8)
+ for i := 1; i < numBytes; i++ {
+ b, err = rb()
+ if err != nil {
+ return
+ }
+ mag |= uint64(b^inv) << shift
+ shift -= 8
+ }
+ mag >>= 64 - sigs
+
+ return
+}
« no previous file with comments | « common/cmpbin/float_test.go ('k') | common/cmpbin/number_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698