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 }