github.com/tunabay/go-bitarray@v1.3.1/buffer.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  	"fmt"
     9  )
    10  
    11  // Buffer is a bit array buffer whose contents can be updated by partial reading
    12  // and writing with an offset. It is not safe for concurrent use by multiple
    13  // goroutines. The zero value for Buffer represents a zero length buffer that
    14  // can be resized and used.
    15  type Buffer struct {
    16  	b     []byte // nil only for zero length
    17  	nBits int
    18  	off   int
    19  }
    20  
    21  // NewBuffer creates a Buffer with the specified bit length.
    22  func NewBuffer(nBits int) *Buffer {
    23  	switch {
    24  	case nBits < 0:
    25  		panicf("NewBuffer: negative nBits %d.", nBits)
    26  	case nBits == 0:
    27  		return &Buffer{}
    28  	}
    29  
    30  	return &Buffer{
    31  		b:     allocByteSlice((nBits + 7) >> 3),
    32  		nBits: nBits,
    33  	}
    34  }
    35  
    36  // NewBufferFromBitArray creates a new Buffer with the same bit length and
    37  // initial content as the specified BitArray.
    38  func NewBufferFromBitArray(ba BitArrayer) *Buffer {
    39  	if ba == nil {
    40  		return &Buffer{}
    41  	}
    42  	bab := ba.BitArray()
    43  	buf := NewBuffer(bab.Len())
    44  	if 0 < buf.nBits {
    45  		copy(buf.b, bab.b)
    46  	}
    47  	return buf
    48  }
    49  
    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  
    77  // IsZero returns whether the Buffer is zero length.
    78  func (buf *Buffer) IsZero() bool {
    79  	return buf.Len() == 0
    80  }
    81  
    82  // Len returns the number of bits contained in the buffer.
    83  func (buf *Buffer) Len() int {
    84  	if buf == nil {
    85  		return 0
    86  	}
    87  	return buf.nBits
    88  }
    89  
    90  // Clone clones the Buffer with its content.
    91  func (buf *Buffer) Clone() *Buffer {
    92  	if buf.Len() == 0 {
    93  		return &Buffer{}
    94  	}
    95  	b := make([]byte, len(buf.b))
    96  	copy(b, buf.b)
    97  
    98  	return &Buffer{b: b, nBits: buf.nBits, off: buf.off}
    99  }
   100  
   101  // BitArray creates an imuurable BitArray from the current content.
   102  func (buf *Buffer) BitArray() *BitArray {
   103  	return NewFromBytes(buf.b, buf.off, buf.nBits)
   104  }
   105  
   106  // String returns the string representation of the current content.
   107  func (buf Buffer) String() string {
   108  	sb := make([]byte, buf.nBits)
   109  	for i := 0; i < buf.nBits; i++ {
   110  		sb[i] = '0' + buf.b[(buf.off+i)>>3]>>(7-(buf.off+i)&7)&1
   111  	}
   112  	return string(sb)
   113  }
   114  
   115  // Resize resizes the Buffer to the size specified by nBits. When expanding, all
   116  // bits in the new range to be extended are initialized with 0. When shrinking,
   117  // the extra bits are truncated. In either case, the align specifies whether to
   118  // 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.
   124  func (buf *Buffer) Resize(nBits int, align Alignment) {
   125  	switch {
   126  	case nBits < 0:
   127  		panicf("Resize: negative nBits %d.", nBits)
   128  	case nBits == 0:
   129  		buf.b = nil
   130  		buf.nBits = 0
   131  		buf.off = 0
   132  		return
   133  	}
   134  
   135  	b := allocByteSlice((nBits + 7) >> 3)
   136  	if buf.nBits == 0 {
   137  		buf.b = b
   138  		buf.nBits = nBits
   139  		buf.off = 0
   140  		return
   141  	}
   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)
   153  		}
   154  	}
   155  
   156  	buf.b = b
   157  	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)
   164  }
   165  
   166  // FillBitsAt sets the nBits bits starting at off to the value bit.
   167  func (buf *Buffer) FillBitsAt(off, nBits int, bit byte) {
   168  	switch {
   169  	case off < 0:
   170  		panicf("FillBitsAt: negative off %d.", off)
   171  	case nBits < 0:
   172  		panicf("FillBitsAt: negative nBits %d.", nBits)
   173  	case buf.nBits < off+nBits:
   174  		panicf("FillBitsAt: out of range: off=%d + nBits=%d > len=%d.", off, nBits, buf.nBits)
   175  	case bit&1 == 0:
   176  		clearBits(buf.b, buf.off+off, nBits)
   177  	default:
   178  		setBits(buf.b, buf.off+off, nBits)
   179  	}
   180  }
   181  
   182  // Format implements the fmt.Formatter interface to format Buffer value using
   183  // the standard fmt.Printf family functions.
   184  func (buf Buffer) Format(s fmt.State, verb rune) { buf.BitArray().Format(s, verb) }