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  */