1 module bitranged; 2 3 struct BitRange 4 { 5 private { 6 // storage of bits 7 ubyte[] _bits; 8 // real capacity 9 ulong _capacity; 10 // counter of bits 11 ulong _counter; 12 13 // get nth bit of byte 14 ubyte bitOf(ubyte value, ubyte n) 15 { 16 return (value >> n) & 1; 17 } 18 19 // nearest power of two 20 ulong cpl2(ulong x) 21 { 22 if (x == 0) 23 { 24 return 0; 25 } 26 27 x -= 1UL; 28 29 x = x | (x >> 1UL); 30 x = x | (x >> 2UL); 31 x = x | (x >> 4UL); 32 x = x | (x >> 8UL); 33 x = x | (x >> 16UL); 34 x = x | (x >> 32UL); 35 36 return (x == ulong.max) ? ulong.max : (x + 1UL); 37 } 38 39 // get indexes of byte and bit in bit array 40 auto indices(ulong index) 41 { 42 auto numberOfByte = index >> 3; 43 auto numberOfBit = 0x07u - cast(ubyte) (index - (numberOfByte << 3)); 44 45 return [numberOfByte, numberOfBit]; 46 } 47 48 // set bit to 1 49 ubyte setBit(ubyte value, ubyte n) 50 { 51 return cast(ubyte) (value | (1 << n)); 52 } 53 54 // deconstruct value to little-endian byte array 55 ubyte[] toLEBytes(T)(T value) 56 { 57 if (T.sizeof <= 1) 58 { 59 return [cast(ubyte) value]; 60 } 61 else 62 { 63 ubyte[] bytes; 64 65 T MASK = cast(T) 0xff; 66 T NSHIFTS = (T.sizeof - 1) << 3; 67 68 foreach (i; 0..T.sizeof) 69 { 70 bytes ~= cast(ubyte) ((value & (MASK << NSHIFTS)) >> NSHIFTS); 71 NSHIFTS -= 8; 72 } 73 74 return bytes; 75 } 76 } 77 78 // set bit to 0 79 ubyte unsetBit(ubyte value, ubyte n) 80 { 81 return cast(ubyte) (value & ~(1u << n)); 82 } 83 } 84 85 this(ulong n) 86 { 87 _capacity = n; 88 _counter = 0; 89 90 if ((0 < n) & (n < 8)) 91 { 92 _bits ~= 0x00; 93 } 94 else 95 { 96 foreach (i; 0..(cpl2(n) >> 3)) 97 { 98 _bits ~= 0x00; 99 } 100 } 101 } 102 103 ubyte[] asBytes() 104 { 105 return _bits; 106 } 107 108 bool empty() 109 { 110 return (_counter == _capacity); 111 } 112 113 void fromString(string s) 114 { 115 auto length = s.length; 116 auto size = (length < 8) ? 1 : cpl2(length) >> 3; 117 118 _bits = []; 119 120 foreach (_; 0..size) 121 { 122 _bits ~= 0x00u; 123 } 124 125 foreach (e; s) 126 { 127 if (e == 0x30) 128 { 129 this.opIndexAssign(0, _counter); 130 } 131 else 132 { 133 if (e == 0x31) 134 { 135 this.opIndexAssign(1, _counter); 136 } 137 else 138 { 139 continue; 140 } 141 } 142 _counter++; 143 } 144 145 _capacity = _counter; 146 _counter = 0; 147 } 148 149 ubyte front() 150 { 151 auto indexes = indices(_counter); 152 153 return bitOf(_bits[indexes[0]], cast(ubyte) indexes[1]); 154 } 155 156 void grow(ulong size) 157 { 158 if (size > 0) 159 { 160 if (_capacity >= size) 161 { 162 throw new Exception("Invalid size for growing BitRange. New size conflicts with real capacity of bit array."); 163 } 164 else 165 { 166 auto realSize = (size < 8) ? 1 : cpl2(size) >> 3; 167 auto newSize = realSize - _bits.length; 168 169 foreach (_; 0..newSize) 170 { 171 _bits ~= 0x00u; 172 } 173 174 _capacity = size; 175 } 176 } 177 } 178 179 ulong length() 180 { 181 return _capacity; 182 } 183 184 ubyte opIndex(size_t index) 185 { 186 auto indexes = indices(index); 187 188 return bitOf(_bits[indexes[0]], cast(ubyte) indexes[1]); 189 } 190 191 void opIndexAssign(ubyte value, size_t index) 192 { 193 auto indexes = indices(index); 194 auto currentByte = _bits[indexes[0]]; 195 196 if (value) 197 { 198 currentByte = setBit(currentByte, cast(ubyte) indexes[1]); 199 } 200 else 201 { 202 currentByte = unsetBit(currentByte, cast(ubyte) indexes[1]); 203 } 204 205 _bits[indexes[0]] = currentByte; 206 } 207 208 void popFront() 209 { 210 _counter++; 211 } 212 213 void push(T)(T value) 214 { 215 auto bytes = toLEBytes(value); 216 217 _capacity += bytes.length * 8; 218 _bits ~= bytes; 219 } 220 221 void push(T)(T[] values) 222 { 223 foreach (e; values) 224 { 225 push(e); 226 } 227 } 228 229 void shrink(ulong size) 230 { 231 if (size == 0) 232 { 233 _bits = []; 234 _capacity = 0; 235 } 236 else 237 { 238 if (size >= _capacity) 239 { 240 throw new Exception("Invalid size for shrinking BitRange. New size conflicts with real capacity of bit array."); 241 } 242 else 243 { 244 auto realSize = (size < 8) ? 1 : cpl2(size) >> 3; 245 _bits = _bits[0..realSize]; 246 _capacity = size; 247 } 248 } 249 } 250 251 string toString() 252 { 253 string bits; 254 255 foreach (i; 0.._capacity) 256 { 257 bits ~= (opIndex(i) == 0 ? "0" : "1"); 258 } 259 260 return bits; 261 } 262 }