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

Side by Side 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: Address comments 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package cmpbin
6
7 import (
8 "errors"
9 "io"
10 "math"
11 )
12
13 // MaxIntLenN is the maximum length of a cmpbin-encoded N-bit integer
14 // (signed or unsigned).
15 const (
16 MaxIntLen16 = 3
17 MaxIntLen32 = 5
18 MaxIntLen64 = 9
19 )
20
21 // ErrOverflow is returned when reading an number which is too large for the
22 // destination type (either uint64 or int64)
23 var ErrOverflow = errors.New("cmpbin: varint overflows")
24
25 // ErrUnderflow is returned when reading an number which is too small for the
26 // destination type (either uint64 or int64)
27 var ErrUnderflow = errors.New("cmpbin: uvarint underflows")
28
29 var paddingMasks = [...]uint64{
30 0xFFFFFFFF00000000,
31 0xFFFF0000,
32 0xFF00,
33 0xF0,
34 0xC,
35 0x2,
36 0x1,
37 }
38
39 // Calculate the log2 of the unsigned value v.
40 //
41 // This is used to find the position of the highest-set bit in v.
42 //
43 // from https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
44 // 32 bit implementation extended to 64 bits
45 func uint64Log2(v uint64) uint {
46 log := uint(0)
47 for i, m := range paddingMasks {
48 if v&m != 0 {
49 shift := uint(1<<uint(len(paddingMasks)-2)) >> uint(i)
50 v >>= shift
51 log |= shift
52 }
53 }
54 return log + 1
55 }
56
57 // WriteInt val as a cmpbin Int to the ByteWriter. Will only return an error if
58 // the underlying ByteWriter returns an error.
59 func WriteInt(w io.ByteWriter, val int64) (n int, err error) {
60 var inv byte
61 if val < 0 {
62 inv = 0xff
63 }
64 mag := uint64(val)
65 if inv != 0 {
66 mag = -mag
67 }
68 return writeSignMag(w, mag, inv)
69 }
70
71 // WriteUint writes mag to the ByteWriter. Will only return an error if the
72 // underlying ByteWriter returns an error.
73 func WriteUint(w io.ByteWriter, mag uint64) (n int, err error) {
74 return writeSignMag(w, mag, 0)
75 }
76
77 // ReadInt decodes a cmpbin-encoded number from a ByteReader. It returns
78 // err{Over,Under}flow if the number is out of bounds. It may also return an
79 // error if the ByteReader returns an error.
80 func ReadInt(r io.ByteReader) (ret int64, n int, err error) {
81 pos, sigs, mag, n, err := readSignMag(r)
82 if err != nil {
83 return
84 }
85 if pos {
86 if sigs > 63 {
87 err = ErrOverflow
88 } else {
89 ret = int64(mag)
90 }
91 } else {
92 if mag > uint64(-math.MinInt64) {
93 err = ErrUnderflow
94 } else {
95 ret = int64(-mag)
96 }
97 }
98 return
99 }
100
101 // ReadUint decodes a cmpbin-encoded positive number from a ByteReader. It
102 // returns err{Over,Under}flow if the number is out of bounds. It may also
103 // return an error if the ByteReader returns an error.
104 func ReadUint(r io.ByteReader) (mag uint64, n int, err error) {
105 pos, _, mag, n, err := readSignMag(r)
106 if err != nil {
107 return
108 }
109 if !pos {
110 err = ErrUnderflow
111 }
112 return
113 }
114
115 func writeSignMag(w io.ByteWriter, mag uint64, inv byte) (n int, err error) {
116 sigs := uint64Log2(mag)
117
118 wb := func(b byte) error {
119 n++
120 return w.WriteByte(b)
121 }
122
123 if err = wb(byte(0x80|(sigs-1)) ^ inv); err != nil {
124 return
125 }
126
127 for sigs > 8 {
128 sigs -= 8
129
130 if err = wb(byte(mag>>sigs) ^ inv); err != nil {
131 return
132 }
133 }
134 if sigs != 0 {
135 if err = wb(byte(mag<<(8-sigs)) ^ inv); err != nil {
136 return
137 }
138 }
139
140 return
141 }
142
143 func readSignMag(r io.ByteReader) (positive bool, sigs uint, mag uint64, n int, err error) {
144 var inv byte
145
146 rb := func() (byte, error) {
147 n++
148 return r.ReadByte()
149 }
150
151 b0, err := rb()
152 if err != nil {
153 return
154 }
155 positive = true
156 if b0&0x80 == 0 {
157 positive = false
158 inv = 0xff
159 }
160
161 sigs = uint((b0^inv)&0x7f) + 1
162 if sigs > 64 {
163 err = ErrOverflow
164 return
165 }
166
167 numBytes := int((sigs+7)>>3) + 1
168
169 var b byte
170 shift := uint(64 - 8)
171 for i := 1; i < numBytes; i++ {
172 b, err = rb()
173 if err != nil {
174 return
175 }
176 mag |= uint64(b^inv) << shift
177 shift -= 8
178 }
179 mag >>= 64 - sigs
180
181 return
182 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698