erigon-pulse/ethdb/encoding.go
Giulio rebuffo 32375df7af made changeSet an helper type (#314)
* made changeSet an helper type

* added comment

* removed dbutils.Add

* remove common.CopyBytes from walk

* fixes
2020-01-15 20:51:10 +00:00

143 lines
3.5 KiB
Go

package ethdb
import (
"bytes"
"encoding/binary"
"fmt"
)
// Maximum length (in bytes of encoded timestamp)
const MaxTimestampLength = 8
func encodingLen8to7(b []byte) int { //nolint
return (len(b)*8 + 6) / 7
}
// Transforms b into encoding where only
// 7 bits of each byte are used to encode the bits of b
// The most significant bit is left empty, for other purposes
func encode8to7(b []byte) []byte {
// Calculate number of bytes in the output
inbytes := len(b)
outbytes := (inbytes*8 + 6) / 7
out := make([]byte, outbytes)
for i := 0; i < outbytes; i++ {
out[i] = 0x80
}
outidx := 0
for inidx := 0; inidx < inbytes; inidx++ {
bb := b[inidx]
switch inidx % 7 {
case 0:
out[outidx] |= bb >> 1
out[outidx+1] |= (bb & 0x1) << 6
case 1:
out[outidx+1] |= (bb >> 2) & 0x3f
out[outidx+2] |= (bb & 0x3) << 5
case 2:
out[outidx+2] |= (bb >> 3) & 0x1f
out[outidx+3] |= (bb & 0x7) << 4
case 3:
out[outidx+3] |= (bb >> 4) & 0xf
out[outidx+4] |= (bb & 0xf) << 3
case 4:
out[outidx+4] |= (bb >> 5) & 0x7
out[outidx+5] |= (bb & 0x1f) << 2
case 5:
out[outidx+5] |= (bb >> 6) & 0x3
out[outidx+6] |= (bb & 0x3f) << 1
case 6:
out[outidx+6] |= bb >> 7
out[outidx+7] |= bb & 0x7f
outidx += 8
}
}
return out
}
func decode7to8(b []byte) []byte {
inbytes := len(b)
outbytes := inbytes * 7 / 8
out := make([]byte, outbytes)
inidx := 0
for outidx := 0; outidx < outbytes; outidx++ {
switch outidx % 7 {
case 0:
out[outidx] = ((b[inidx] & 0x7f) << 1) | ((b[inidx+1] >> 6) & 0x1)
case 1:
out[outidx] = ((b[inidx+1] & 0x3f) << 2) | ((b[inidx+2] >> 5) & 0x3)
case 2:
out[outidx] = ((b[inidx+2] & 0x1f) << 3) | ((b[inidx+3] >> 4) & 0x7)
case 3:
out[outidx] = ((b[inidx+3] & 0xf) << 4) | ((b[inidx+4] >> 3) & 0xf)
case 4:
out[outidx] = ((b[inidx+4] & 0x7) << 5) | ((b[inidx+5] >> 2) & 0x1f)
case 5:
out[outidx] = ((b[inidx+5] & 0x3) << 6) | ((b[inidx+6] >> 1) & 0x3f)
case 6:
out[outidx] = ((b[inidx+6] & 0x1) << 7) | (b[inidx+7] & 0x7f)
inidx += 8
}
}
return out
}
// addToChangeSet is not part the ChangeSet API, and it is only used in the test settings.
// In the production settings, ChangeSets encodings are never modified.
// In production settings (mutation.PutS) we always first populate ChangeSet object,
// then encode it once, and then only work with the encoding
func addToChangeSet(b []byte, key []byte, value []byte) ([]byte, error) {
var m int
var n int
if len(b) == 0 {
m = len(key)
n = 0
} else {
n = int(binary.BigEndian.Uint32(b[0:4]))
m = int(binary.BigEndian.Uint32(b[4:8]))
if len(key) != m {
return nil, fmt.Errorf("wrong key size in ChangeSet: expected %d, actual %d", m, len(key))
}
}
pos := 4
var buffer bytes.Buffer
// Encode n
intArr := make([]byte, 4)
binary.BigEndian.PutUint32(intArr, uint32(n+1))
buffer.Write(intArr)
// KeySize should be the same
if n == 0 {
binary.BigEndian.PutUint32(intArr, uint32(len(key)))
buffer.Write(intArr)
} else {
buffer.Write(b[pos : pos+4])
}
pos += 4
// append key
if n == 0 {
buffer.Write(key)
pos += len(key)
} else {
buffer.Write(b[pos : pos+n*m])
buffer.Write(key)
pos += n * m
}
// Append Index
if n == 0 {
binary.BigEndian.PutUint32(intArr, uint32(len(value)))
buffer.Write(intArr)
} else {
buffer.Write(b[pos : pos+4*n])
pos += 4 * n
prev := int(binary.BigEndian.Uint32(b[pos-4 : pos]))
binary.BigEndian.PutUint32(intArr, uint32(prev+len(value)))
buffer.Write(intArr)
buffer.Write(b[pos:])
}
// Append Value
buffer.Write(value)
return buffer.Bytes(), nil
}