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

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: 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 unified diff | Download patch
« no previous file with comments | « common/cmpbin/float_test.go ('k') | common/cmpbin/number_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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. Returns the number of bytes
58 // written. Only returns an error if the underlying ByteWriter returns an error.
59 func WriteInt(w io.ByteWriter, val int64) (int, 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. Returns the number of bytes written.
72 // Only returns an error if the underlying ByteWriter returns an error.
73 func WriteUint(w io.ByteWriter, mag uint64) (int, error) {
74 return writeSignMag(w, mag, 0)
75 }
76
77 // ReadInt decodes a cmpbin-encoded number from a ByteReader. It returns the
78 // decoded value and the number of bytes read. The error may be
79 // Err{Over,Under}flow if the number is out of bounds. It may also return an
80 // error if the ByteReader returns an error.
81 func ReadInt(r io.ByteReader) (ret int64, n int, err error) {
82 pos, sigs, mag, n, err := readSignMag(r)
83 if err != nil {
84 return
85 }
86 if pos {
87 if sigs > 63 {
88 err = ErrOverflow
89 } else {
90 ret = int64(mag)
91 }
92 } else {
93 if mag > uint64(-math.MinInt64) {
94 err = ErrUnderflow
95 } else {
96 ret = int64(-mag)
97 }
98 }
99 return
100 }
101
102 // ReadUint decodes a cmpbin-encoded positive number from a ByteReader. It
103 // returns the decoded value and the number of bytes read. The erorr may be
104 // Err{Over,Under}flow if the number is out of bounds. It may also return an
105 // error if the ByteReader returns an error.
106 func ReadUint(r io.ByteReader) (mag uint64, n int, err error) {
107 pos, _, mag, n, err := readSignMag(r)
108 if err != nil {
109 return
110 }
111 if !pos {
112 err = ErrUnderflow
113 }
114 return
115 }
116
117 func writeSignMag(w io.ByteWriter, mag uint64, inv byte) (n int, err error) {
118 sigs := uint64Log2(mag)
119
120 wb := func(b byte) error {
121 n++
122 return w.WriteByte(b)
123 }
124
125 if err = wb(byte(0x80|(sigs-1)) ^ inv); err != nil {
126 return
127 }
128
129 for sigs > 8 {
130 sigs -= 8
131
132 if err = wb(byte(mag>>sigs) ^ inv); err != nil {
133 return
134 }
135 }
136 if sigs != 0 {
137 if err = wb(byte(mag<<(8-sigs)) ^ inv); err != nil {
138 return
139 }
140 }
141
142 return
143 }
144
145 func readSignMag(r io.ByteReader) (positive bool, sigs uint, mag uint64, n int, err error) {
146 var inv byte
147
148 rb := func() (byte, error) {
149 n++
150 return r.ReadByte()
151 }
152
153 b0, err := rb()
154 if err != nil {
155 return
156 }
157 positive = true
158 if b0&0x80 == 0 {
159 positive = false
160 inv = 0xff
161 }
162
163 sigs = uint((b0^inv)&0x7f) + 1
164 if sigs > 64 {
165 err = ErrOverflow
166 return
167 }
168
169 numBytes := int((sigs+7)>>3) + 1
170
171 var b byte
172 shift := uint(64 - 8)
173 for i := 1; i < numBytes; i++ {
174 b, err = rb()
175 if err != nil {
176 return
177 }
178 mag |= uint64(b^inv) << shift
179 shift -= 8
180 }
181 mag >>= 64 - sigs
182
183 return
184 }
OLDNEW
« 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