Skip to content

Commit acd4a05

Browse files
authored
Merge pull request #4 from tunabay/edge
v1.2.0 rc
2 parents 4fa1ba8 + df96ff1 commit acd4a05

18 files changed

Lines changed: 1489 additions & 121 deletions

bitarray_slice.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ func (ba *BitArray) Slice(start, end int) *BitArray {
3838
return &BitArray{b: buf, nBits: nBits}
3939
}
4040

41+
// SliceToEnd is shorthand for Slice(start, ba.Len()) and returns the subpart
42+
// from the position specified start to the last bit.
43+
func (ba *BitArray) SliceToEnd(start int) *BitArray { return ba.Slice(start, ba.Len()) }
44+
4145
// ToWidth returns a new BitArray resized to wid bits with its contents
4246
// preserved. If wid is less than ba.Len(), some bits will be lost. If wid is
4347
// greater than be.Len(), the expanded space will be filled with 0s. In both

bitarray_slice_example_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ func ExampleBitArray_Slice() {
2020
// 1101
2121
}
2222

23+
func ExampleBitArray_SliceToEnd() {
24+
ba := bitarray.MustParse("0011-1010 01101")
25+
fmt.Printf("% b\n", ba.SliceToEnd(4))
26+
fmt.Printf("% b\n", ba.SliceToEnd(9))
27+
28+
// Output:
29+
// 10100110 1
30+
// 1101
31+
}
32+
2333
func ExampleBitArray_ToWidth() {
2434
ba := bitarray.MustParse("1010-1111 0000-11")
2535
fmt.Printf("% s\n", ba.ToWidth(7, bitarray.AlignLeft))

buffer.go

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import (
1212
// and writing with an offset. It is not safe for concurrent use by multiple
1313
// goroutines. The zero value for Buffer represents a zero length buffer that
1414
// can be resized and used.
15-
type Buffer BitArray
16-
17-
// Buffer fields:
18-
// .b []byte // nil only for zero length
19-
// .nBits int
15+
type Buffer struct {
16+
b []byte // nil only for zero length
17+
nBits int
18+
off int
19+
}
2020

2121
// NewBuffer creates a Buffer with the specified bit length.
2222
func NewBuffer(nBits int) *Buffer {
@@ -47,6 +47,33 @@ func NewBufferFromBitArray(ba BitArrayer) *Buffer {
4747
return buf
4848
}
4949

50+
// NewBufferFromByteSlice creates a new Buffer that references an existing byte
51+
// slice b. The created Buffer references b without copying it, therefore,
52+
// changes to the buffer affect b and vice versa. The length of the buffer
53+
// created will be len(b) * 8. NewBufferFromByteSlice is useful when reading or
54+
// writing a subpart of a byte slice as a bit array without copying or
55+
// bit-shifting.
56+
func NewBufferFromByteSlice(b []byte) *Buffer {
57+
return NewBufferFromByteSlicePartial(b, 0, len(b)<<3)
58+
}
59+
60+
// NewBufferFromByteSlicePartial is identical to NewBufferFromByteSlice except
61+
// that it creates a buffer with the first bit specified by off, and the length
62+
// specified by nBits.
63+
func NewBufferFromByteSlicePartial(b []byte, off, nBits int) *Buffer {
64+
switch {
65+
case off < 0:
66+
panicf("NewBufferFromByteSlice: negative off %d.", nBits)
67+
case nBits < 0:
68+
panicf("NewBufferFromByteSlice: negative nBits %d.", nBits)
69+
case len(b)<<3 < off+nBits:
70+
panicf("NewBufferFromByteSlice: out of range: off=%d, nBits=%d > len=%d.", off, nBits, len(b))
71+
case nBits == 0:
72+
return &Buffer{}
73+
}
74+
return &Buffer{b: b[off>>3:], nBits: nBits, off: off & 7}
75+
}
76+
5077
// IsZero returns whether the Buffer is zero length.
5178
func (buf *Buffer) IsZero() bool {
5279
return buf.Len() == 0
@@ -65,22 +92,22 @@ func (buf *Buffer) Clone() *Buffer {
6592
if buf.Len() == 0 {
6693
return &Buffer{}
6794
}
68-
b := allocByteSlice(len(buf.b))
69-
copy(b, buf.b)
95+
b := allocByteSlice((buf.nBits + 7) >> 3)
96+
copyBits(b, buf.b, 0, buf.off, buf.nBits)
7097

7198
return &Buffer{b: b, nBits: buf.nBits}
7299
}
73100

74101
// BitArray creates an imuurable BitArray from the current content.
75102
func (buf *Buffer) BitArray() *BitArray {
76-
return NewFromBytes(buf.b, 0, buf.nBits)
103+
return NewFromBytes(buf.b, buf.off, buf.nBits)
77104
}
78105

79106
// String returns the string representation of the current content.
80107
func (buf Buffer) String() string {
81108
sb := make([]byte, buf.nBits)
82109
for i := 0; i < buf.nBits; i++ {
83-
sb[i] = '0' + buf.b[i>>3]>>(7-i&7)&1
110+
sb[i] = '0' + buf.b[(buf.off+i)>>3]>>(7-(buf.off+i)&7)&1
84111
}
85112
return string(sb)
86113
}
@@ -89,71 +116,51 @@ func (buf Buffer) String() string {
89116
// bits in the new range to be extended are initialized with 0. When shrinking,
90117
// the extra bits are truncated. In either case, the align specifies whether to
91118
// fix the MSBs or the LSBs.
119+
//
120+
// Resize always reallocates internal memory. That is, the buffers created by
121+
// Slice method or NewBufferFromByteSlice break their relationship with the
122+
// parent buffer or slice by calling this Resize, even if nBits is equivalent to
123+
// or less than its current size.
92124
func (buf *Buffer) Resize(nBits int, align Alignment) {
93125
switch {
94126
case nBits < 0:
95127
panicf("Resize: negative nBits %d.", nBits)
96-
case nBits == buf.nBits:
97-
return
98128
case nBits == 0:
99129
buf.b = nil
100130
buf.nBits = 0
131+
buf.off = 0
101132
return
102133
}
103-
nBytes := (nBits + 7) >> 3
104134

105-
// AlignLeft
106-
if align == AlignLeft {
107-
// shrink
108-
if nBits < buf.nBits {
109-
buf.b = buf.b[:nBytes]
110-
if nBits&7 != 0 {
111-
buf.b[nBits>>3] &= 0xff << (8 - nBits&7)
112-
}
113-
buf.nBits = nBits
114-
return
115-
}
116-
117-
// extend
118-
if nBytes <= cap(buf.b) { // enough cap
119-
n := len(buf.b)
120-
buf.b = buf.b[:nBytes]
121-
for ; n < nBytes; n++ {
122-
buf.b[n] = 0
123-
}
124-
buf.nBits = nBits
125-
return
126-
}
127-
128-
newb := allocByteSlice(nBytes)
129-
copy(newb, buf.b)
130-
buf.b = newb
135+
b := allocByteSlice((nBits + 7) >> 3)
136+
if buf.nBits == 0 {
137+
buf.b = b
131138
buf.nBits = nBits
139+
buf.off = 0
132140
return
133141
}
134-
135-
// AlignRight
136-
// shrink
137-
if nBits < buf.nBits {
138-
if nBits&7 == buf.nBits&7 { // no shift
139-
buf.b = buf.b[len(buf.b)-nBytes:]
140-
buf.nBits = nBits
141-
return
142+
if align == AlignLeft {
143+
if nBits < buf.nBits { // shrink
144+
copyBits(b, buf.b, 0, buf.off, nBits)
145+
} else { // extend
146+
copyBits(b, buf.b, 0, buf.off, buf.nBits)
147+
}
148+
} else {
149+
if nBits < buf.nBits { // shrink
150+
copyBits(b, buf.b, 0, buf.off+buf.nBits-nBits, nBits)
151+
} else { // extend
152+
copyBits(b, buf.b, nBits-buf.nBits, buf.off, buf.nBits)
142153
}
143-
newb := allocByteSlice(nBytes)
144-
_ = copyBits(newb, buf.b, 0, buf.nBits-nBits, nBits)
145-
buf.b = newb
146-
buf.nBits = nBits
147-
return
148154
}
149155

150-
// extend
151-
newb := allocByteSlice(nBytes)
152-
if buf.b != nil {
153-
_ = copyBits(newb, buf.b, nBits-buf.nBits, 0, buf.nBits)
154-
}
155-
buf.b = newb
156+
buf.b = b
156157
buf.nBits = nBits
158+
buf.off = 0
159+
}
160+
161+
// FillBits sets all the bits in the buffer to the value bit, 0 or 1.
162+
func (buf *Buffer) FillBits(bit byte) {
163+
buf.FillBitsAt(0, buf.nBits, bit)
157164
}
158165

159166
// FillBitsAt sets the nBits bits starting at off to the value bit.
@@ -166,12 +173,12 @@ func (buf *Buffer) FillBitsAt(off, nBits int, bit byte) {
166173
case buf.nBits < off+nBits:
167174
panicf("FillBitsAt: out of range: off=%d + nBits=%d > len=%d.", off, nBits, buf.nBits)
168175
case bit&1 == 0:
169-
clearBits(buf.b, off, nBits)
176+
clearBits(buf.b, buf.off+off, nBits)
170177
default:
171-
setBits(buf.b, off, nBits)
178+
setBits(buf.b, buf.off+off, nBits)
172179
}
173180
}
174181

175182
// Format implements the fmt.Formatter interface to format Buffer value using
176183
// the standard fmt.Printf family functions.
177-
func (buf Buffer) Format(s fmt.State, verb rune) { BitArray(buf).Format(s, verb) }
184+
func (buf Buffer) Format(s fmt.State, verb rune) { buf.BitArray().Format(s, verb) }

buffer_bitwise.go

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44

55
package bitarray
66

7-
import (
8-
"math/bits"
9-
)
10-
117
// ToggleBitAt flips a single bit at the position specified by off in the
128
// buffer.
139
func (buf *Buffer) ToggleBitAt(off int) {
@@ -16,9 +12,9 @@ func (buf *Buffer) ToggleBitAt(off int) {
1612
panicf("ToggleBitAt: negative off %d.", off)
1713
case buf.nBits <= off:
1814
panicf("ToggleBitAt: out of range: off=%d >= len=%d.", off, buf.nBits)
19-
default:
20-
buf.b[off>>3] ^= byte(0x80) >> (off & 7)
2115
}
16+
off += buf.off
17+
buf.b[off>>3] ^= byte(0x80) >> (off & 7)
2218
}
2319

2420
// ToggleBitsAt inverts the nBits bits starting at off.
@@ -33,7 +29,7 @@ func (buf *Buffer) ToggleBitsAt(off, nBits int) {
3329
case nBits == 0:
3430
// no-op
3531
default:
36-
toggleBits(buf.b, off, nBits)
32+
toggleBits(buf.b, buf.off+off, nBits)
3733
}
3834
}
3935

@@ -53,9 +49,9 @@ func (buf *Buffer) AndAt(off int, x BitArrayer) {
5349
case bax.IsZero():
5450
// no-op
5551
case bax.b == nil:
56-
clearBits(buf.b, off, bax.nBits)
52+
clearBits(buf.b, buf.off+off, bax.nBits)
5753
default:
58-
andBits(buf.b, bax.b, off, 0, bax.nBits)
54+
andBits(buf.b, bax.b, buf.off+off, 0, bax.nBits)
5955
}
6056
}
6157

@@ -74,7 +70,7 @@ func (buf *Buffer) OrAt(off int, x BitArrayer) {
7470
case bax.IsZero(), bax.b == nil:
7571
// no-op
7672
default:
77-
orBits(buf.b, bax.b, off, 0, bax.nBits)
73+
orBits(buf.b, bax.b, buf.off+off, 0, bax.nBits)
7874
}
7975
}
8076

@@ -94,25 +90,15 @@ func (buf *Buffer) XorAt(off int, x BitArrayer) {
9490
case bax.IsZero(), bax.b == nil:
9591
// no-op
9692
default:
97-
xorBits(buf.b, bax.b, off, 0, bax.nBits)
93+
xorBits(buf.b, bax.b, buf.off+off, 0, bax.nBits)
9894
}
9995
}
10096

10197
// LeadingZeros returns the number of leading zero bits in the Buffer.
102-
func (buf *Buffer) LeadingZeros() int { return (*BitArray)(buf).LeadingZeros() }
98+
func (buf *Buffer) LeadingZeros() int { return buf.BitArray().LeadingZeros() }
10399

104100
// TrailingZeros returns the number of trailing zero bits in the Buffer.
105-
func (buf *Buffer) TrailingZeros() int { return (*BitArray)(buf).TrailingZeros() }
101+
func (buf *Buffer) TrailingZeros() int { return buf.BitArray().TrailingZeros() }
106102

107103
// OnesCount returns the number of one bits, population count, in the Buffer.
108-
func (buf *Buffer) OnesCount() int {
109-
if buf.IsZero() {
110-
return 0
111-
}
112-
n := 0
113-
for _, b := range buf.b {
114-
n += bits.OnesCount8(b)
115-
}
116-
117-
return n
118-
}
104+
func (buf *Buffer) OnesCount() int { return buf.BitArray().OnesCount() }

buffer_copy.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
2+
// Use of this source code is governed by the MIT license that can be found in
3+
// the LICENSE file.
4+
5+
package bitarray
6+
7+
// CopyBitsFromBytes reads nBits bits from b at the offset bOff, and write them
8+
// into the buffer at the offset off.
9+
func (buf *Buffer) CopyBitsFromBytes(off int, b []byte, bOff, nBits int) {
10+
switch {
11+
case off < 0:
12+
panicf("CopyBitsFromBytes: negative off %d.", off)
13+
case buf.nBits < off+nBits:
14+
panicf("CopyBitsFromBytes: out of range: off=%d + nBits=%d > len=%d.", off, nBits, buf.nBits)
15+
case nBits == 0:
16+
return
17+
}
18+
copyBits(buf.b, b, buf.off+off, bOff, nBits)
19+
}
20+
21+
// CopyBitsToBytes reads nBits bits of the buffer starting at the offset off,
22+
// and write them into the byte slice b at the offset bOff.
23+
func (buf *Buffer) CopyBitsToBytes(off int, b []byte, bOff, nBits int) {
24+
switch {
25+
case off < 0:
26+
panicf("CopyBitsToBytes: negative off %d.", off)
27+
case buf.nBits < off+nBits:
28+
panicf("CopyBitsToBytes: out of range: off=%d + nBits=%d > len=%d.", off, nBits, buf.nBits)
29+
case nBits == 0:
30+
return
31+
}
32+
copyBits(b, buf.b, bOff, buf.off+off, nBits)
33+
}
34+
35+
// CopyBits copies bits from src into dst. CopyBits returns the number of bits
36+
// copied, which will be the minimum of src.Len() and dst.Len().
37+
func CopyBits(dst, src *Buffer) int {
38+
nBits := dst.Len()
39+
if sLen := src.Len(); sLen < nBits {
40+
nBits = sLen
41+
}
42+
if nBits != 0 {
43+
copyBits(dst.b, src.b, dst.off, src.off, nBits)
44+
}
45+
46+
return nBits
47+
}
48+
49+
// CopyBitsN is identical to CopyBits except that it copies up to nBits bits.
50+
func CopyBitsN(dst, src *Buffer, nBits int) int {
51+
if dLen := dst.Len(); dLen < nBits {
52+
nBits = dLen
53+
}
54+
if sLen := src.Len(); sLen < nBits {
55+
nBits = sLen
56+
}
57+
if nBits != 0 {
58+
copyBits(dst.b, src.b, dst.off, src.off, nBits)
59+
}
60+
61+
return nBits
62+
}
63+
64+
// CopyBitsPartial is identical to CopyBitsN except that it reads and writes
65+
// bits starting at specified offsets rather than the first bits.
66+
func CopyBitsPartial(dst, src *Buffer, dstOff, srcOff, nBits int) int {
67+
if dLen := dst.Len() - dstOff; dLen < nBits {
68+
nBits = dLen
69+
}
70+
if sLen := src.Len() - srcOff; sLen < nBits {
71+
nBits = sLen
72+
}
73+
if nBits != 0 {
74+
copyBits(dst.b, src.b, dst.off+dstOff, src.off+srcOff, nBits)
75+
}
76+
77+
return nBits
78+
}

0 commit comments

Comments
 (0)