bitset.go (6062B)
1 // go-qrcode 2 // Copyright 2014 Tom Harwood 3 4 // Package bitset implements an append only bit array. 5 // 6 // To create a Bitset and append some bits: 7 // // Bitset Contents 8 // b := bitset.New() // {} 9 // b.AppendBools(true, true, false) // {1, 1, 0} 10 // b.AppendBools(true) // {1, 1, 0, 1} 11 // b.AppendValue(0x02, 4) // {1, 1, 0, 1, 0, 0, 1, 0} 12 // 13 // To read values: 14 // 15 // len := b.Len() // 8 16 // v := b.At(0) // 1 17 // v = b.At(1) // 1 18 // v = b.At(2) // 0 19 // v = b.At(8) // 0 20 package bitset 21 22 import ( 23 "bytes" 24 "fmt" 25 "log" 26 ) 27 28 const ( 29 b0 = false 30 b1 = true 31 ) 32 33 // Bitset stores an array of bits. 34 type Bitset struct { 35 // The number of bits stored. 36 numBits int 37 38 // Storage for individual bits. 39 bits []byte 40 } 41 42 // New returns an initialised Bitset with optional initial bits v. 43 func New(v ...bool) *Bitset { 44 b := &Bitset{numBits: 0, bits: make([]byte, 0)} 45 b.AppendBools(v...) 46 47 return b 48 } 49 50 // Clone returns a copy. 51 func Clone(from *Bitset) *Bitset { 52 return &Bitset{numBits: from.numBits, bits: from.bits[:]} 53 } 54 55 // Substr returns a substring, consisting of the bits from indexes start to end. 56 func (b *Bitset) Substr(start int, end int) *Bitset { 57 if start > end || end > b.numBits { 58 log.Panicf("Out of range start=%d end=%d numBits=%d", start, end, b.numBits) 59 } 60 61 result := New() 62 result.ensureCapacity(end - start) 63 64 for i := start; i < end; i++ { 65 if b.At(i) { 66 result.bits[result.numBits/8] |= 0x80 >> uint(result.numBits%8) 67 } 68 result.numBits++ 69 } 70 71 return result 72 } 73 74 // NewFromBase2String constructs and returns a Bitset from a string. The string 75 // consists of '1', '0' or ' ' characters, e.g. "1010 0101". The '1' and '0' 76 // characters represent true/false bits respectively, and ' ' characters are 77 // ignored. 78 // 79 // The function panics if the input string contains other characters. 80 func NewFromBase2String(b2string string) *Bitset { 81 b := &Bitset{numBits: 0, bits: make([]byte, 0)} 82 83 for _, c := range b2string { 84 switch c { 85 case '1': 86 b.AppendBools(true) 87 case '0': 88 b.AppendBools(false) 89 case ' ': 90 default: 91 log.Panicf("Invalid char %c in NewFromBase2String", c) 92 } 93 } 94 95 return b 96 } 97 98 // AppendBytes appends a list of whole bytes. 99 func (b *Bitset) AppendBytes(data []byte) { 100 for _, d := range data { 101 b.AppendByte(d, 8) 102 } 103 } 104 105 // AppendByte appends the numBits least significant bits from value. 106 func (b *Bitset) AppendByte(value byte, numBits int) { 107 b.ensureCapacity(numBits) 108 109 if numBits > 8 { 110 log.Panicf("numBits %d out of range 0-8", numBits) 111 } 112 113 for i := numBits - 1; i >= 0; i-- { 114 if value&(1<<uint(i)) != 0 { 115 b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8) 116 } 117 118 b.numBits++ 119 } 120 } 121 122 // AppendUint32 appends the numBits least significant bits from value. 123 func (b *Bitset) AppendUint32(value uint32, numBits int) { 124 b.ensureCapacity(numBits) 125 126 if numBits > 32 { 127 log.Panicf("numBits %d out of range 0-32", numBits) 128 } 129 130 for i := numBits - 1; i >= 0; i-- { 131 if value&(1<<uint(i)) != 0 { 132 b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8) 133 } 134 135 b.numBits++ 136 } 137 } 138 139 // ensureCapacity ensures the Bitset can store an additional |numBits|. 140 // 141 // The underlying array is expanded if necessary. To prevent frequent 142 // reallocation, expanding the underlying array at least doubles its capacity. 143 func (b *Bitset) ensureCapacity(numBits int) { 144 numBits += b.numBits 145 146 newNumBytes := numBits / 8 147 if numBits%8 != 0 { 148 newNumBytes++ 149 } 150 151 if len(b.bits) >= newNumBytes { 152 return 153 } 154 155 b.bits = append(b.bits, make([]byte, newNumBytes+2*len(b.bits))...) 156 } 157 158 // Append bits copied from |other|. 159 // 160 // The new length is b.Len() + other.Len(). 161 func (b *Bitset) Append(other *Bitset) { 162 b.ensureCapacity(other.numBits) 163 164 for i := 0; i < other.numBits; i++ { 165 if other.At(i) { 166 b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8) 167 } 168 b.numBits++ 169 } 170 } 171 172 // AppendBools appends bits to the Bitset. 173 func (b *Bitset) AppendBools(bits ...bool) { 174 b.ensureCapacity(len(bits)) 175 176 for _, v := range bits { 177 if v { 178 b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8) 179 } 180 b.numBits++ 181 } 182 } 183 184 // AppendNumBools appends num bits of value value. 185 func (b *Bitset) AppendNumBools(num int, value bool) { 186 for i := 0; i < num; i++ { 187 b.AppendBools(value) 188 } 189 } 190 191 // String returns a human readable representation of the Bitset's contents. 192 func (b *Bitset) String() string { 193 var bitString string 194 for i := 0; i < b.numBits; i++ { 195 if (i % 8) == 0 { 196 bitString += " " 197 } 198 199 if (b.bits[i/8] & (0x80 >> byte(i%8))) != 0 { 200 bitString += "1" 201 } else { 202 bitString += "0" 203 } 204 } 205 206 return fmt.Sprintf("numBits=%d, bits=%s", b.numBits, bitString) 207 } 208 209 // Len returns the length of the Bitset in bits. 210 func (b *Bitset) Len() int { 211 return b.numBits 212 } 213 214 // Bits returns the contents of the Bitset. 215 func (b *Bitset) Bits() []bool { 216 result := make([]bool, b.numBits) 217 218 var i int 219 for i = 0; i < b.numBits; i++ { 220 result[i] = (b.bits[i/8] & (0x80 >> byte(i%8))) != 0 221 } 222 223 return result 224 } 225 226 // At returns the value of the bit at |index|. 227 func (b *Bitset) At(index int) bool { 228 if index >= b.numBits { 229 log.Panicf("Index %d out of range", index) 230 } 231 232 return (b.bits[index/8] & (0x80 >> byte(index%8))) != 0 233 } 234 235 // Equals returns true if the Bitset equals other. 236 func (b *Bitset) Equals(other *Bitset) bool { 237 if b.numBits != other.numBits { 238 return false 239 } 240 241 if !bytes.Equal(b.bits[0:b.numBits/8], other.bits[0:b.numBits/8]) { 242 return false 243 } 244 245 for i := 8 * (b.numBits / 8); i < b.numBits; i++ { 246 a := (b.bits[i/8] & (0x80 >> byte(i%8))) 247 b := (other.bits[i/8] & (0x80 >> byte(i%8))) 248 249 if a != b { 250 return false 251 } 252 } 253 254 return true 255 } 256 257 // ByteAt returns a byte consisting of upto 8 bits starting at index. 258 func (b *Bitset) ByteAt(index int) byte { 259 if index < 0 || index >= b.numBits { 260 log.Panicf("Index %d out of range", index) 261 } 262 263 var result byte 264 265 for i := index; i < index+8 && i < b.numBits; i++ { 266 result <<= 1 267 if b.At(i) { 268 result |= 1 269 } 270 } 271 272 return result 273 }