mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
This rewrites the tests to make them more consistent with the rest of the code base and significantly increases their coverage of the code. It also reworks the benchmarks to actually benchmark what their names claim, renames them for consistency, and make them more stable by ensuring the same prng seed is used each run to eliminate variance introduced by different values. Finally, it removes an impossible to hit condition from the bit reader and adds a couple of additional checks to harden the filters against potential misuse. This is part of the ongoing process to cleanup and improve the gcs module to the quality level required by consensus code for ultimate inclusion in header commitments.
190 lines
3.1 KiB
Go
190 lines
3.1 KiB
Go
// Copyright (c) 2018 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gcs
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
type bitWriter struct {
|
|
bytes []byte
|
|
p *byte // Pointer to last byte
|
|
next byte // Next bit to write or skip
|
|
}
|
|
|
|
// writeOne writes a one bit to the bit stream.
|
|
func (b *bitWriter) writeOne() {
|
|
if b.next == 0 {
|
|
b.bytes = append(b.bytes, 1<<7)
|
|
b.p = &b.bytes[len(b.bytes)-1]
|
|
b.next = 1 << 6
|
|
return
|
|
}
|
|
|
|
*b.p |= b.next
|
|
b.next >>= 1
|
|
}
|
|
|
|
// writeZero writes a zero bit to the bit stream.
|
|
func (b *bitWriter) writeZero() {
|
|
if b.next == 0 {
|
|
b.bytes = append(b.bytes, 0)
|
|
b.p = &b.bytes[len(b.bytes)-1]
|
|
b.next = 1 << 6
|
|
return
|
|
}
|
|
|
|
b.next >>= 1
|
|
}
|
|
|
|
// writeNBits writes n number of LSB bits of data to the bit stream in big
|
|
// endian format. Panics if n > 64.
|
|
func (b *bitWriter) writeNBits(data uint64, n uint) {
|
|
if n > 64 {
|
|
panic("gcs: cannot write more than 64 bits of a uint64")
|
|
}
|
|
|
|
data <<= 64 - n
|
|
|
|
// If byte is partially written, fill the rest
|
|
for n > 0 {
|
|
if b.next == 0 {
|
|
break
|
|
}
|
|
if data&(1<<63) != 0 {
|
|
b.writeOne()
|
|
} else {
|
|
b.writeZero()
|
|
}
|
|
n--
|
|
data <<= 1
|
|
}
|
|
|
|
if n == 0 {
|
|
return
|
|
}
|
|
|
|
// Write 8 bits at a time.
|
|
for n >= 8 {
|
|
b.bytes = append(b.bytes, byte(data>>56))
|
|
n -= 8
|
|
data <<= 8
|
|
}
|
|
|
|
// Write the remaining bits.
|
|
for n > 0 {
|
|
if data&(1<<63) != 0 {
|
|
b.writeOne()
|
|
} else {
|
|
b.writeZero()
|
|
}
|
|
n--
|
|
data <<= 1
|
|
}
|
|
}
|
|
|
|
type bitReader struct {
|
|
bytes []byte
|
|
next byte // next bit to read in bytes[0]
|
|
}
|
|
|
|
func newBitReader(bitstream []byte) bitReader {
|
|
return bitReader{
|
|
bytes: bitstream,
|
|
next: 1 << 7,
|
|
}
|
|
}
|
|
|
|
// readUnary returns the number of unread sequential one bits before the next
|
|
// zero bit. Errors with io.EOF if no zero bits are encountered.
|
|
func (b *bitReader) readUnary() (uint64, error) {
|
|
var value uint64
|
|
|
|
for {
|
|
if len(b.bytes) == 0 {
|
|
return value, io.EOF
|
|
}
|
|
|
|
for b.next != 0 {
|
|
bit := b.bytes[0] & b.next
|
|
b.next >>= 1
|
|
if bit == 0 {
|
|
return value, nil
|
|
}
|
|
value++
|
|
}
|
|
|
|
b.bytes = b.bytes[1:]
|
|
b.next = 1 << 7
|
|
}
|
|
}
|
|
|
|
// readNBits reads n number of LSB bits of data from the bit stream in big
|
|
// endian format. Panics if n > 64.
|
|
func (b *bitReader) readNBits(n uint) (uint64, error) {
|
|
if n > 64 {
|
|
panic("gcs: cannot read more than 64 bits as a uint64")
|
|
}
|
|
if n == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
if len(b.bytes) == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
var value uint64
|
|
|
|
// If byte is partially read, read the rest
|
|
if b.next != 1<<7 {
|
|
for n > 0 {
|
|
if b.next == 0 {
|
|
b.next = 1 << 7
|
|
b.bytes = b.bytes[1:]
|
|
break
|
|
}
|
|
|
|
n--
|
|
if b.bytes[0]&b.next != 0 {
|
|
value |= 1 << n
|
|
}
|
|
b.next >>= 1
|
|
}
|
|
}
|
|
|
|
if n == 0 {
|
|
return value, nil
|
|
}
|
|
|
|
// Read 8 bits at a time.
|
|
for n >= 8 {
|
|
if len(b.bytes) == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
n -= 8
|
|
value |= uint64(b.bytes[0]) << n
|
|
b.bytes = b.bytes[1:]
|
|
}
|
|
|
|
if len(b.bytes) == 0 {
|
|
if n != 0 {
|
|
return 0, io.EOF
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
// Read the remaining bits.
|
|
for n > 0 {
|
|
n--
|
|
if b.bytes[0]&b.next != 0 {
|
|
value |= 1 << n
|
|
}
|
|
b.next >>= 1
|
|
}
|
|
|
|
return value, nil
|
|
}
|