github.com/tunabay/go-bitarray@v1.3.1/builder.go (about) 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 import ( 8 "bytes" 9 "fmt" 10 "io" 11 ) 12 13 // Builder is used to efficiently build a BitArray using Write methods. It 14 // minimizes memory copying and bit shifting. 15 // 16 // The zero value for Builder is already to use. Do not copy a non-zero Builder. 17 // It is not safe for concurrent use by multiple goroutines. 18 type Builder struct { 19 head, tail *builderChunk 20 nBits int 21 } 22 23 // NewBuilder creates a Builder with bit arrays as the initial contents. 24 func NewBuilder(bas ...BitArrayer) *Builder { 25 b := &Builder{} 26 for _, bai := range bas { 27 if bai == nil { 28 continue 29 } 30 ba := bai.BitArray() 31 if !ba.IsZero() { 32 b.append(ba.b, 0, ba.nBits, ba.b == nil) 33 } 34 } 35 36 return b 37 } 38 39 type builderChunk struct { 40 b []byte // can be nil when zf == true 41 nBits int // 0 < nBits 42 off int // off must be canonicalized to 0..7 43 zf bool // zero-filled and immutable 44 next *builderChunk 45 } 46 47 // BitArray builds an immutable BitArray from accumulated bits. References to 48 // the accumulated byte slices are copied when this BitArray method is called. 49 func (b *Builder) BitArray() *BitArray { 50 if b.nBits == 0 { 51 return zeroBitArray 52 } 53 buf := allocByteSlice((b.nBits + 7) >> 3) 54 idx, zf := 0, true 55 for c := b.head; c != nil; c = c.next { 56 if c.zf { 57 idx += c.nBits 58 continue 59 } 60 zf2 := copyBits(buf, c.b, idx, c.off, c.nBits) 61 zf = zf && zf2 62 idx += c.nBits 63 } 64 if zf { 65 return &BitArray{nBits: b.nBits} 66 } 67 68 return &BitArray{b: buf, nBits: b.nBits} 69 } 70 71 // String returns the string representation of the bit array being built. The 72 // result is the same as b.BitArray().String(). 73 func (b *Builder) String() string { 74 sb := make([]byte, b.nBits) 75 idx := 0 76 for c := b.head; c != nil; c = c.next { 77 if c.zf { 78 s := idx 79 idx += c.nBits 80 fill30(sb[s:idx]) 81 continue 82 } 83 for i := c.off; i < c.off+c.nBits; i++ { 84 sb[idx] = '0' + c.b[i>>3]>>(7-i&7)&1 85 idx++ 86 } 87 } 88 return string(sb) 89 } 90 91 func (b *Builder) append(buf []byte, off, nBits int, zf bool) { 92 if nBits == 0 { 93 return 94 } 95 c := &builderChunk{b: buf, nBits: nBits, off: off, zf: zf} 96 if b.head == nil { 97 b.head, b.tail = c, c 98 } else { 99 b.tail.next = c 100 b.tail = c 101 } 102 b.nBits += nBits 103 } 104 105 // Reset resets the builder state to empty. All the bits accumulated by writing 106 // methods are discarded. 107 func (b *Builder) Reset() { 108 b.head, b.tail, b.nBits = nil, nil, 0 109 } 110 111 // Len returns the current number of bits accumurated. 112 func (b *Builder) Len() int { 113 return b.nBits 114 } 115 116 // WriteBitsFromBytes adds the number of bits specified by nBits from the byte 117 // slice p to the Builder. It skips the off bits from the beginning of p and 118 // reads up to 8 bits from each byte from the MSB to the LSB. 119 // 120 // WriteBitsFromBytes only references the slice and offset of p, and does not 121 // copy the contents of p. Therefore, any changes to the contents of p before 122 // calling the BitArray() or String() methods are affected. Be especially 123 // careful when using a same buffer for iterations. 124 func (b *Builder) WriteBitsFromBytes(p []byte, off, nBits int) { 125 if len(p) == 0 || nBits == 0 { 126 return 127 } 128 p = p[off>>3:] 129 off &= 7 130 b.append(p[:(off+nBits+7)>>3], off, nBits, false) 131 } 132 133 // Write implements io.Writer by writing 8 * len(p) bits read from a byte slice 134 // p. Write copies p once because the io.Writer prohibits the implementation to 135 // retain p. Use WriteBitsFromBytes to avoid copying. Write always returns 136 // len(p), nil. 137 func (b *Builder) Write(p []byte) (int, error) { 138 buf := make([]byte, len(p)) 139 copy(buf, p) 140 b.append(buf, 0, len(p)<<3, false) 141 142 return len(p), nil 143 } 144 145 // WriteByte implements io.ByteWriter by writing 8 bits read from a byte c. 146 // WriteByte always returns a nil error. 147 func (b *Builder) WriteByte(c byte) error { 148 b.append([]byte{c}, 0, 8, c == 0) 149 150 return nil 151 } 152 153 // ReadFrom implements io.ReaderFrom. It reads bytes from r until io.EOF or an 154 // error, and appends the bits read to the builder. Even if an error occurs, the 155 // bits that could be read before the error are appended to the builder. 156 func (b *Builder) ReadFrom(r io.Reader) (int64, error) { 157 var buf bytes.Buffer 158 n, err := buf.ReadFrom(r) 159 if 0 < n { 160 b.append(buf.Bytes(), 0, int(n)<<3, false) 161 } 162 if err != nil { 163 return n, fmt.Errorf("read failure: %w", err) 164 } 165 166 return n, nil 167 } 168 169 // WriteBit writes a single bit to the builder. The bit should be 0 or 1, 170 // otherwise its LSB is silently used. It always returns a nil error. 171 func (b *Builder) WriteBit(bit byte) error { 172 b.append([]byte{bit}, 7, 1, bit&1 == 0) 173 174 return nil 175 } 176 177 // WriteBitArray writes a bit array to the builder. It always returns the length 178 // of the bit array and a nil error. 179 func (b *Builder) WriteBitArray(x BitArrayer) (int, error) { 180 if x == nil { 181 return 0, nil 182 } 183 bax := x.BitArray() 184 if bax.IsZero() { 185 return 0, nil 186 } 187 188 b.append(bax.b, 0, bax.nBits, bax.b == nil) 189 190 return bax.Len(), nil 191 } 192 193 // WriteByteBits adds to the Builder the bits read from a byte slice where each 194 // element contains individual bits. Each element of bits should be 0 or 1, 195 // otherwise only its LSB is used silently. WriteByteBits copies the bits from 196 // bits, so any future changes to bits will not affect the contents of Builder. 197 func (b *Builder) WriteByteBits(bits []byte) { 198 if len(bits) == 0 { 199 return 200 } 201 var zfb byte 202 buf := make([]byte, (len(bits)+7)>>3) 203 for i, bit := range bits { 204 bit &= 1 205 zfb |= bit 206 buf[i>>3] |= bit << (7 - i&7) 207 } 208 b.append(buf, 0, len(bits), zfb == 0) 209 } 210 211 // WriteBits write the bits read from a Buffer p. WriteBits copies p and is 212 // unaffected by changes to p after the call. It always returns p.Len() and nil 213 // error. 214 func (b *Builder) WriteBits(p *Buffer) (int, error) { 215 if p.IsZero() { 216 return 0, nil 217 } 218 p = p.Clone() 219 b.append(p.b, p.off, p.nBits, false) 220 221 return p.nBits, nil 222 } 223 224 /* 225 // Unwrite discards the last nBits bits of the bits already written. It is 226 // useful for removing trailing padding bits after writing using a 227 // byte-oriented method. 228 func (b *Builder) Unwrite(nBits int) {} 229 */