1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2009 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Sept 2009: Initial release
8 
9         since:          0.99.9
10 
11         author:         Kris
12 
13 *******************************************************************************/
14 
15 module tango.util.container.more.BitSet;
16 
17 private import core.bitop;
18 
19 /******************************************************************************
20 
21         A fixed or dynamic set of bits. Note that this does no memory 
22         allocation of its own when Size != 0, and does heap allocation 
23         when Size is zero. Thus you can have a fixed-size low-overhead 
24         'instance, or a heap oriented instance. The latter has support
25         for resizing, whereas the former does not.
26 
27         Note that leveraging intrinsics is slower when using dmd ...
28 
29 ******************************************************************************/
30 
31 struct BitSet (int Count=0) 
32 {               
33         private enum           width = size_t.sizeof * 8;
34         
35         const bool opBinary(immutable(char)[] s : "&")(size_t i)
36         {
37             return and(i);
38         }
39         
40         void opOpAssign(immutable(char)[] s : "|")(size_t i)
41         {
42             or(i);
43         }
44         
45         void opOpAssign(immutable(char)[] s : "^")(size_t i)
46         {
47             xor(i);
48         }
49 
50         static if (Count == 0)
51                    private size_t[] bits;
52                else
53                   private size_t [(Count+width-1)/width] bits;
54 
55         /**********************************************************************
56 
57                 Set the indexed bit, resizing as necessary for heap-based
58                 instances (IndexOutOfBounds for statically-sized instances)
59 
60         **********************************************************************/
61 
62         void add (size_t i)
63         {
64                 static if (Count == 0)
65                            size (i);
66                 or (i);
67         }
68 
69         /**********************************************************************
70 
71                 Test whether the indexed bit is enabled 
72 
73         **********************************************************************/
74 
75         const bool has (size_t i)
76         {
77                 auto idx = i / width;
78                 return idx < bits.length && (bits[idx] & (1 << (i % width))) != 0;
79                 //return idx < bits.length && bt(&bits[idx], i % width) != 0;
80         }
81 
82         /**********************************************************************
83 
84                 Like get() but a little faster for when you know the range
85                 is valid
86 
87         **********************************************************************/
88 
89         const bool and (size_t i)
90         {
91                 return (bits[i / width] & (1 << (i % width))) != 0;
92                 //return bt(&bits[i / width], i % width) != 0;
93         }
94 
95         /**********************************************************************
96 
97                 Turn on an indexed bit
98 
99         **********************************************************************/
100 
101         void or (size_t i)
102         {
103                 bits[i / width] |= (1 << (i % width));
104                 //bts (&bits[i / width], i % width);
105         }
106         
107         /**********************************************************************
108 
109                 Invert an indexed bit
110 
111         **********************************************************************/
112 
113         void xor (size_t i)
114         {
115                 bits[i / width] ^= (1 << (i % width));
116                 //btc (&bits[i / width], i % width);
117         }
118         
119         /**********************************************************************
120 
121                 Clear an indexed bit
122 
123         **********************************************************************/
124 
125         void clr (size_t i)
126         {
127                 bits[i / width] &= ~(1 << (i % width));
128                 //btr (&bits[i / width], i % width);
129         }
130 
131         /**********************************************************************
132 
133                 Clear all bits
134 
135         **********************************************************************/
136 
137         BitSet* clr ()
138         {
139                 bits[] = 0;
140                 return &this;
141         }
142         
143         /**********************************************************************
144 
145                 Clone this BitSet and return it
146 
147         **********************************************************************/
148 
149         @property const BitSet dup ()
150         {
151                 BitSet x;
152                 static if (Count == 0)
153                            x.bits.length = this.bits.length;
154                 x.bits[] = bits[];
155                 return x;
156         }
157 
158         /**********************************************************************
159 
160                 Return the number of bits we have room for
161 
162         **********************************************************************/
163 
164         @property const size_t size ()
165         {
166                 return width * bits.length;
167         }
168 
169         /**********************************************************************
170 
171                 Expand to include the indexed bit (dynamic only)
172 
173         **********************************************************************/
174 
175         static if (Count == 0) BitSet* size (size_t i)
176         {
177                 i = i / width;
178                 if (i >= bits.length)
179                     bits.length = i + 1;
180                 return &this;
181         }
182 }