github.com/tunabay/go-bitarray@v1.3.1/buffer_rw.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  // BitAt returns a single bit at the specified offset as 0 or 1. It panics if
     8  // the off is out of range.
     9  func (buf *Buffer) BitAt(off int) byte {
    10  	switch {
    11  	case off < 0:
    12  		panicf("BitAt: negative off %d.", off)
    13  	case buf.nBits <= off:
    14  		panicf("BitAt: out of range: off=%d >= len=%d.", off, buf.nBits)
    15  	}
    16  
    17  	off += buf.off
    18  	return buf.b[off>>3] >> (7 - off&7) & 1
    19  }
    20  
    21  // PutBitAt writes a single bit at the position specified by off in the buffer.
    22  // The bit should be 0 or 1, otherwise its LSB is silently used.
    23  func (buf *Buffer) PutBitAt(off int, bit byte) {
    24  	switch {
    25  	case off < 0:
    26  		panicf("PutBitAt: negative off %d.", off)
    27  	case buf.nBits <= off:
    28  		panicf("PutBitAt: out of range: off=%d >= len=%d.", off, buf.nBits)
    29  	}
    30  
    31  	off += buf.off
    32  	buf.b[off>>3] = buf.b[off>>3] & ^(byte(0x80)>>(off&7)) | ((bit & 1) << (7 - off&7))
    33  }
    34  
    35  // BitArrayAt returns bits within the specified range as a BitArray.
    36  func (buf *Buffer) BitArrayAt(off, nBits int) *BitArray {
    37  	switch {
    38  	case off < 0:
    39  		panicf("BitArrayAt: negative off %d.", off)
    40  	case nBits < 0:
    41  		panicf("BitArrayAt: negative nBits %d.", nBits)
    42  	case buf.nBits < off+nBits:
    43  		panicf("BitArrayAt: out of range: off=%d + nBits=%d > len=%d.", off, nBits, buf.nBits)
    44  	case nBits == 0:
    45  		return zeroBitArray
    46  	}
    47  
    48  	return NewFromBytes(buf.b, buf.off+off, nBits)
    49  }
    50  
    51  // PutBitArrayAt writes bits from a BitArray onto the specified offset off.
    52  func (buf *Buffer) PutBitArrayAt(off int, ba BitArrayer) {
    53  	switch {
    54  	case off < 0:
    55  		panicf("PutBitArrayAt: negative off %d.", off)
    56  	case ba == nil:
    57  		return
    58  	}
    59  	bab := ba.BitArray()
    60  	switch {
    61  	case buf.nBits < off+bab.nBits:
    62  		panicf("PutBitArrayAt: out of range: off=%d + ba.len=%d > len=%d.", off, bab.nBits, buf.nBits)
    63  	case bab.IsZero():
    64  		return
    65  	case bab.b == nil:
    66  		clearBits(buf.b, buf.off+off, bab.nBits)
    67  		return
    68  	}
    69  	_ = copyBits(buf.b, bab.b, buf.off+off, 0, bab.nBits)
    70  }
    71  
    72  // ByteAt reads 8 bits starting at the offset off and returns them as a single
    73  // byte. Note that off is in bits, not bytes. If the off is not a multiple of 8,
    74  // 8 bits across a byte boundary are returned.
    75  func (buf *Buffer) ByteAt(off int) byte {
    76  	switch {
    77  	case off < 0:
    78  		panicf("ByteAt: negative off %d.", off)
    79  	case buf.nBits < off+8:
    80  		panicf("ByteAt: out of range: off=%d + 8 > len=%d.", off, buf.nBits)
    81  	}
    82  	off += buf.off
    83  	i, f := off>>3, off&7
    84  	if f == 0 {
    85  		return buf.b[i]
    86  	}
    87  	return buf.b[i]<<f | buf.b[i+1]>>(8-f)
    88  }
    89  
    90  // PutByteAt writes 8 bits of b to the position specified by off in the buffer.
    91  // Note that off is in bits, not bytes. If the off is not a multiple of 8, it
    92  // writes 8 bits across a byte boundary.
    93  func (buf *Buffer) PutByteAt(off int, b byte) {
    94  	switch {
    95  	case off < 0:
    96  		panicf("PutByteAt: negative off %d.", off)
    97  	case buf.nBits < off+8:
    98  		panicf("PutByteAt: out of range: off=%d + 8 > len=%d.", off, buf.nBits)
    99  	}
   100  	copyBits(buf.b, []byte{b}, buf.off+off, 0, 8)
   101  }
   102  
   103  // RawBytes returns all the bits of the buffer as a byte slice. The caller must
   104  // not change the contents of the returned byte slice. The slice returned may or
   105  // may not reference to the internal buffer itself of buf, depending on whether
   106  // bit-shifting is needed of not. Also, if buf.Len() is not a multiple of 8, the
   107  // bits after the last bit in the slice returned are undefined. The main purpose
   108  // of RawBytes is to efficiently pass bit data to other byte-oriented APIs. In
   109  // general, it is recommended to use the safer Bytes() instead.
   110  func (buf *Buffer) RawBytes() []byte {
   111  	if buf.off&7 == 0 {
   112  		return buf.b[buf.off>>3 : (buf.off+buf.nBits+7)>>3]
   113  	}
   114  	return buf.Bytes()
   115  }
   116  
   117  // Bytes returns all the bits of the buffer as a byte slice. If buf.Len() is not
   118  // a multiple of 8, it will be padded with 0.
   119  func (buf *Buffer) Bytes() []byte {
   120  	b := make([]byte, (buf.nBits+7)>>3)
   121  	copyBits(b, buf.b, 0, buf.off, buf.nBits)
   122  	return b
   123  }
   124  
   125  // BytesAt reads 8 * nBytes bits starting at the offset off and returns them as
   126  // a byte slice. Note that off is in bits, not bytes. If the off is not a
   127  // multiple of 8, it returns a properly shifted byte slice.
   128  func (buf *Buffer) BytesAt(off, nBytes int) []byte {
   129  	nBits := nBytes << 3
   130  	switch {
   131  	case off < 0:
   132  		panicf("ByteAt: negative off %d.", off)
   133  	case nBytes < 0:
   134  		panicf("ByteAt: negative nBytes %d.", nBytes)
   135  	case buf.nBits < off+nBits:
   136  		panicf("BytesAt: out of range: off=%d + 8 * nBytes=%d > len=%d.", off, nBytes, buf.nBits)
   137  	case nBytes == 0:
   138  		return []byte{}
   139  	}
   140  	ret := make([]byte, nBytes)
   141  	copyBits(ret, buf.b, 0, buf.off+off, nBits)
   142  
   143  	return ret
   144  }
   145  
   146  // PutBytesAt writes 8 * len(b) bits of b to the position specified by off in
   147  // the buffer. Note that off is in bits, not bytes. If the off is not a multiple
   148  // of 8, it writes bytes across byte boundaries of the buffer.
   149  func (buf *Buffer) PutBytesAt(off int, b []byte) {
   150  	nBits := len(b) << 3
   151  	switch {
   152  	case off < 0:
   153  		panicf("PutByteAt: negative off %d.", off)
   154  	case buf.nBits < off+nBits:
   155  		panicf("PutByteAt: out of range: off=%d + 8 * b.len=%d > len=%d.", off, len(b), buf.nBits)
   156  	case len(b) == 0:
   157  		return
   158  	}
   159  	copyBits(buf.b, b, buf.off+off, 0, nBits)
   160  }