1 module libd.datastructures.bitkeeper; 2 3 import libd.datastructures._bitinfo; 4 import libd.util.errorhandling; 5 import libd.util.maths : alignTo; 6 7 struct BitKeeperSlice 8 { 9 package size_t startByte; 10 package ubyte startBit; 11 package size_t bitCount; 12 13 invariant(startBit >= 0 && startBit < 8); 14 invariant(startByte + startBit + bitCount == 0 || bitCount > 0); 15 16 @property @safe @nogc 17 size_t bitIndex() nothrow pure const 18 { 19 return (this.startByte * 8) + this.startBit; 20 } 21 } 22 23 struct BitKeeper 24 { 25 private ubyte[] _bytes; 26 private size_t _maxBitsToUse; 27 private size_t _bitsInUse; 28 29 @disable this(this){} 30 31 @safe @nogc nothrow: 32 33 this(ubyte[] bytes, size_t maxBitsToUse) 34 { 35 this._bytes = bytes; 36 this._maxBitsToUse = maxBitsToUse; 37 assert(this._maxBitsToUse/8 <= bytes.length, "Not enough bytes were provided for the given maxBitsToUse value."); 38 } 39 40 SimpleResult!BitKeeperSlice alloc(size_t bitCount) 41 { 42 assert(this._bytes !is null, "This BitKeeper hasn't been initialised."); 43 if(bitCount == 0) 44 return typeof(return)(raise("BitCount cannot be 0.")); 45 else if(bitCount >= this._maxBitsToUse - this._bitsInUse) 46 return typeof(return)(raise("Not enough total bits available.")); 47 48 for(size_t i = 0; i < this._bytes.length; i++) 49 { 50 const byte_ = this._bytes[i]; 51 if(byte_ == 0xFF) 52 continue; 53 54 const info = BIT_INFO[byte_]; 55 if(info.largestBitRangeCount >= bitCount) 56 { 57 const range = BitRange(info.bitRangeForSize[bitCount-1].start, cast(ubyte)bitCount); 58 const mask = rangeToMask(range); 59 this._bytes[i] |= mask; 60 return typeof(return)(BitKeeperSlice( 61 i, range.start, bitCount 62 )); 63 } 64 else if(info.flags & BitInfoFlags.hasSuffixZero) 65 { 66 const startByte = i; 67 const startRange = info.bitRangeForSuffix; 68 auto remainingBits = bitCount - startRange.count; 69 assert(remainingBits < bitCount); 70 71 i++; 72 while(true) 73 { 74 if(i >= this._bytes.length) 75 return typeof(return)(raise("Cannot find a long enough, continous range of bits.")); 76 77 const nextByte = this._bytes[i]; 78 const nextByteInfo = BIT_INFO[nextByte]; 79 80 if(nextByte == 0) 81 { 82 if(remainingBits <= 8) 83 { 84 const range = BitRange(0, cast(ubyte)remainingBits); 85 const mask = rangeToMask(range); 86 this._bytes[i] |= mask; 87 // Fallthrough to end 88 } 89 else 90 { 91 i++; 92 remainingBits -= 8; 93 continue; 94 } 95 } 96 else if 97 ( 98 !(nextByteInfo.flags & BitInfoFlags.hasPrefixZero) 99 || nextByteInfo.bitRangeForPrefix.count < remainingBits 100 || nextByte == 0xFF 101 ) 102 { 103 i--; // Negate the for loop's next i++ 104 break; // Failed match, try again with further bytes. 105 } 106 else 107 this._bytes[i] |= rangeToMask(BitRange(0, cast(ubyte)remainingBits)); 108 109 const inbetweenBytes = i - startByte; 110 if(inbetweenBytes >= 2) 111 { 112 foreach(byteI; 1..inbetweenBytes) 113 this._bytes[startByte+byteI] = 0xFF; 114 } 115 this._bytes[startByte] |= rangeToMask(startRange); 116 this._bitsInUse += bitCount; 117 return typeof(return)(BitKeeperSlice( 118 startByte, startRange.start, bitCount 119 )); 120 } 121 } 122 } 123 124 return typeof(return)(raise("Cannot find a long enough, continous range of bits.")); 125 } 126 127 void free(BitKeeperSlice slice) 128 { 129 const startByteBitsFromStartToEnd = 8 - slice.startBit; 130 if(startByteBitsFromStartToEnd > slice.bitCount) // Slice is only in a single byte. 131 { 132 this._bytes[slice.startByte] &= ~cast(int)rangeToMask(BitRange(slice.startBit, cast(ubyte)slice.bitCount)); 133 return; 134 } // Slice is multi-byte. 135 136 this._bytes[slice.startByte] &= ~cast(int)rangeToMask(BitRange(slice.startBit, cast(ubyte)startByteBitsFromStartToEnd)); 137 138 // Clear the inbetween full bytes. 139 auto byteI = slice.startByte+1; 140 auto remainingBits = slice.bitCount - startByteBitsFromStartToEnd; 141 while(remainingBits >= 8) 142 { 143 this._bytes[byteI++] = 0; 144 remainingBits -= 8; 145 } 146 147 // Clear the end byte. 148 this._bytes[byteI] &= ~cast(int)rangeToMask(BitRange(0, cast(ubyte)remainingBits)); 149 this._bitsInUse -= slice.bitCount; 150 } 151 152 size_t capacityInBits() pure const 153 { 154 return this._maxBitsToUse; 155 } 156 157 size_t lengthInBits() pure const 158 { 159 return this._bitsInUse; 160 } 161 } 162 /// 163 @("BitKeeper") 164 unittest 165 { 166 ubyte[3] buffer; 167 auto bits = BitKeeper(buffer[0..$], 3*8); 168 169 // NOTE: User code can't manually create BitKeeperSlices like the unittest can. 170 171 // Single-byte 172 assert(bits.alloc(1).assumeValid == BitKeeperSlice(0, 0, 1)); 173 assert(buffer[0] == 1); 174 bits.free(BitKeeperSlice(0, 0, 1)); 175 assert(buffer[0] == 0); 176 assert(bits.alloc(1).assumeValid == BitKeeperSlice(0, 0, 1)); 177 assert(bits.alloc(3).assumeValid == BitKeeperSlice(0, 1, 3)); 178 assert(buffer[0] == 0b0000_1111); 179 bits.free(BitKeeperSlice(0, 1, 2)); 180 assert(buffer[0] == 0b0000_1001); 181 assert(bits.alloc(1).assumeValid == BitKeeperSlice(0, 1, 1)); 182 assert(bits.alloc(2).assumeValid == BitKeeperSlice(0, 4, 2)); 183 assert(buffer[0] == 0b0011_1011); 184 buffer[0] = 0; 185 186 // Two bytes 187 assert(bits.alloc(7).assumeValid == BitKeeperSlice(0, 0, 7)); 188 assert(bits.alloc(3).assumeValid == BitKeeperSlice(0, 7, 3)); 189 assert(buffer[0] == 0xFF); 190 assert(buffer[1] == 0b0000_0011); 191 bits.free(BitKeeperSlice(0, 7, 2)); 192 assert(buffer[0] == 0b0111_1111); 193 assert(buffer[1] == 0b0000_0010); 194 assert(bits.alloc(3).assumeValid == BitKeeperSlice(1, 2, 3)); 195 assert(buffer[0] == 0b0111_1111); 196 assert(buffer[1] == 0b0001_1110); 197 buffer[0..2] = 0; 198 199 // Multi-byte 200 assert(bits.alloc(18).assumeValid == BitKeeperSlice(0, 0, 18)); 201 assert(buffer[0] == 0xFF); 202 assert(buffer[1] == 0xFF); 203 assert(buffer[2] == 0b0000_0011); 204 bits.free(BitKeeperSlice(0, 0, 18)); 205 assert(buffer[0] == 0); 206 assert(buffer[1] == 0); 207 assert(buffer[2] == 0); 208 } 209 210 private: 211 212 @safe @nogc 213 ubyte rangeToMask(const BitRange range) nothrow pure 214 { 215 return BIT_MASKS[(range.start * 10) + range.count]; 216 }