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