Little-endian incrementBytes (#411)

* implement little-endian incrementBytes

* reverse test buffers

* remove unused reverseBytes
This commit is contained in:
Egon Elbre 2018-10-03 11:55:42 +03:00 committed by Kaloyan Raev
parent 027e4045c6
commit 7edcb0099a
2 changed files with 40 additions and 44 deletions

View File

@ -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
}

View File

@ -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)
}
}
}