Little-endian incrementBytes (#411)
* implement little-endian incrementBytes * reverse test buffers * remove unused reverseBytes
This commit is contained in:
parent
027e4045c6
commit
7edcb0099a
@ -3,38 +3,28 @@
|
||||
|
||||
package eestream
|
||||
|
||||
import "math/big"
|
||||
|
||||
// incrementBytes takes a byte slice buf and treats it like a big-endian
|
||||
// incrementBytes takes a byte slice buf and treats it like a little-endian
|
||||
// encoded unsigned integer. it adds amount to it (which must be nonnegative)
|
||||
// in place. if rollover happens (the most significant bytes don't fit
|
||||
// anymore), truncated is true.
|
||||
func incrementBytes(buf []byte, amount int64) (truncated bool,
|
||||
err error) {
|
||||
func incrementBytes(buf []byte, amount int64) (truncated bool, err error) {
|
||||
if amount < 0 {
|
||||
return false, Error.New("amount was negative")
|
||||
}
|
||||
// use math/big for the actual incrementing
|
||||
var val big.Int
|
||||
val.SetBytes(buf)
|
||||
val.Add(&val, big.NewInt(amount))
|
||||
data := val.Bytes()
|
||||
|
||||
// we went past the available memory. truncate the most significant bytes
|
||||
// off
|
||||
if len(data) > len(buf) {
|
||||
data = data[len(data)-len(buf):]
|
||||
truncated = true
|
||||
idx := 0
|
||||
for amount > 0 && idx < len(buf) {
|
||||
var inc, prev byte
|
||||
inc, amount = byte(amount), amount>>8
|
||||
|
||||
prev = buf[idx]
|
||||
buf[idx] += inc
|
||||
if buf[idx] < prev {
|
||||
amount++
|
||||
}
|
||||
|
||||
idx++
|
||||
}
|
||||
|
||||
// math/big doesn't return leading 0 bytes so add them back if they're
|
||||
// missing
|
||||
for i := len(buf) - len(data) - 1; i >= 0; i-- {
|
||||
buf[i] = 0
|
||||
}
|
||||
|
||||
// write the data out inplace
|
||||
copy(buf[len(buf)-len(data):], data[:])
|
||||
|
||||
return truncated, nil
|
||||
return amount != 0, nil
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestIncrementBytes(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
for i, test := range []struct {
|
||||
inbuf []byte
|
||||
amount int64
|
||||
err bool
|
||||
@ -26,38 +26,44 @@ func TestIncrementBytes(t *testing.T) {
|
||||
{[]byte{0}, 254, false, []byte{0xfe}, false},
|
||||
{[]byte{1}, 254, false, []byte{0xff}, false},
|
||||
{[]byte{0}, 255, false, []byte{0xff}, false},
|
||||
{[]byte{0, 0, 1}, 3, false, []byte{0, 0, 4}, false},
|
||||
{[]byte{1, 0, 0}, 3, false, []byte{4, 0, 0}, false},
|
||||
{[]byte{0}, 256, false, []byte{0}, true},
|
||||
{[]byte{0}, 257, false, []byte{1}, true},
|
||||
{[]byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 1,
|
||||
false, []byte{0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
|
||||
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 1,
|
||||
false, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
|
||||
{[]byte{0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff}, 1,
|
||||
false, []byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0}, false},
|
||||
{[]byte{0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0, 0xff, 0xfe}, 0xff0001,
|
||||
false, []byte{0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
false},
|
||||
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xfe}, 0xff0002,
|
||||
false, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
|
||||
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xfe}, 0xff0003,
|
||||
false, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, true},
|
||||
{
|
||||
[]byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe"), 1, false,
|
||||
[]byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"), false},
|
||||
{
|
||||
[]byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), 1, false,
|
||||
[]byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), true},
|
||||
{
|
||||
[]byte("\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xfe"), 1, false,
|
||||
[]byte("\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe"), false},
|
||||
{
|
||||
[]byte("\xfe\xff\x00\xff\xff\xfe\xff\xff\xff\xfe"), 0xff0001, false,
|
||||
[]byte("\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xfe"), false},
|
||||
{
|
||||
[]byte("\xfe\xff\x00\xff\xff\xff\xff\xff\xff\xff"), 0xff0002, false,
|
||||
[]byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), true},
|
||||
{
|
||||
[]byte("\xfe\xff\x00\xff\xff\xff\xff\xff\xff\xff"), 0xff0003, false,
|
||||
[]byte("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"), true},
|
||||
} {
|
||||
|
||||
trunc, err := incrementBytes(test.inbuf, test.amount)
|
||||
if err != nil {
|
||||
if !test.err {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
t.Fatalf("%d: unexpected err: %v", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if test.err {
|
||||
t.Fatalf("err expected but no err happened")
|
||||
t.Fatalf("%d: err expected but no err happened", i)
|
||||
}
|
||||
if trunc != test.truncated {
|
||||
t.Fatalf("truncated rv mismatch")
|
||||
t.Fatalf("%d: truncated rv mismatch", i)
|
||||
}
|
||||
if !bytes.Equal(test.outbuf, test.inbuf) {
|
||||
t.Fatalf("result mismatch")
|
||||
t.Fatalf("%d: result mismatch\n%v\n%v", i, test.inbuf, test.outbuf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user