1 module sqlbuilder.util; 2 3 package struct BitStack 4 { 5 private enum bitsInSizeT = size_t.sizeof * 8; 6 private enum topBit = size_t(1) << (bitsInSizeT - 1); 7 private union State { 8 size_t[2] staticBits; 9 size_t[] bitarr; 10 } 11 private State state; 12 private size_t top; 13 14 @disable this(this); 15 16 @nogc @trusted nothrow /*pure*/ : 17 18 @property size_t length() const { return top & ~topBit; } 19 20 private @property bool isAllocated() const { return (top & topBit) ? true : false; } 21 22 @property private inout(size_t)[] bitarr() inout 23 { 24 return isAllocated ? state.bitarr : state.staticBits[]; 25 } 26 27 ~this() 28 { 29 import core.stdc.stdlib : free; 30 if(isAllocated) 31 { 32 free(state.bitarr.ptr); 33 state.bitarr = null; 34 top = 0; 35 } 36 } 37 38 void clear() { 39 top &= topBit; 40 } 41 42 void push(bool val) 43 { 44 import core.stdc.stdlib : realloc, malloc; 45 import core.bitop : bts, btr; 46 size_t lenNeeded = (length + bitsInSizeT) / bitsInSizeT; 47 if(bitarr.length < lenNeeded) 48 { 49 if(isAllocated) 50 { 51 state.bitarr = (cast(size_t *)realloc(state.bitarr.ptr, lenNeeded * size_t.sizeof))[0 .. lenNeeded]; 52 } 53 else 54 { 55 auto arr = (cast(size_t *)malloc(lenNeeded * size_t.sizeof))[0 .. lenNeeded]; 56 arr.ptr[0 .. state.staticBits.length] = state.staticBits[]; 57 top |= topBit;// flag as allocated 58 state.bitarr = arr; 59 assert(isAllocated); 60 } 61 } 62 if(val) 63 bts(bitarr.ptr, top); 64 else 65 btr(bitarr.ptr, top); 66 ++top; 67 } 68 69 bool peek() const 70 { 71 assert(length > 0, "Cannot peek at top of an empty stack"); 72 import core.bitop : bt; 73 return bt(bitarr.ptr, length - 1) ? true : false; 74 } 75 76 bool pop() 77 { 78 assert(length > 0, "Cannot pop top of an empty stack"); 79 import core.bitop : bt; 80 --top; 81 return bt(bitarr.ptr, length) ? true : false; 82 } 83 } 84 85 unittest 86 { 87 // test bitstack 88 BitStack bs; 89 bs.push(true); 90 bs.push(false); 91 bs.push(true); 92 bs.push(false); 93 assert(bs.length == 4); 94 assert(!bs.peek); 95 assert(!bs.pop); 96 assert(bs.length == 3); 97 assert(bs.pop); 98 assert(!bs.pop); 99 assert(bs.peek); 100 assert(bs.length == 1); 101 assert(bs.pop); 102 assert(bs.length == 0); 103 } 104