taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

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 }