1 /**
2  * Implementation of a bit array.
3  *
4  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d)
8  * Documentation:  https://dlang.org/phobos/dmd_root_array.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/bitarray.d
10  */
11 
12 module dmd.root.bitarray;
13 
14 import core.stdc.stdio;
15 import core.stdc..string;
16 
17 import dmd.root.rmem;
18 
19 struct BitArray
20 {
21 nothrow:
22 
23     alias Chunk_t = size_t;
24     enum ChunkSize = Chunk_t.sizeof;
25     enum BitsPerChunk = ChunkSize * 8;
26 
27     size_t length() const pure nothrow @nogc @safe
28     {
29         return len;
30     }
31 
32     void length(size_t nlen) pure nothrow
33     {
34         immutable ochunks = chunks(len);
35         immutable nchunks = chunks(nlen);
36         if (ochunks != nchunks)
37         {
38             ptr = cast(size_t*)mem.xrealloc_noscan(ptr, nchunks * ChunkSize);
39         }
40         if (nchunks > ochunks)
41            ptr[ochunks .. nchunks] = 0;
42         if (nlen & (BitsPerChunk - 1))
43            ptr[nchunks - 1] &= (cast(Chunk_t)1 << (nlen & (BitsPerChunk - 1))) - 1;
44         len = nlen;
45     }
46 
47     void opAssign(const ref BitArray b)
48     {
49         if (!len)
50             length(b.len);
51         assert(len == b.len);
52         memcpy(ptr, b.ptr, bytes(len));
53     }
54 
55     bool opIndex(size_t idx) const pure nothrow @nogc
56     {
57         import core.bitop : bt;
58 
59         assert(idx < len);
60         return !!bt(ptr, idx);
61     }
62 
63     void opIndexAssign(bool val, size_t idx) pure nothrow @nogc
64     {
65         import core.bitop : btc, bts;
66 
67         assert(idx < len);
68         if (val)
69             bts(ptr, idx);
70         else
71             btc(ptr, idx);
72     }
73 
74     bool opEquals(const ref BitArray b) const
75     {
76         return len == b.len && memcmp(ptr, b.ptr, bytes(len)) == 0;
77     }
78 
79     void zero()
80     {
81         memset(ptr, 0, bytes(len));
82     }
83 
84     /******
85      * Returns:
86      *  true if no bits are set
87      */
88     bool isZero()
89     {
90         const nchunks = chunks(len);
91         foreach (i; 0 .. nchunks)
92         {
93             if (ptr[i])
94                 return false;
95         }
96         return true;
97     }
98 
99     void or(const ref BitArray b)
100     {
101         assert(len == b.len);
102         const nchunks = chunks(len);
103         foreach (i; 0 .. nchunks)
104             ptr[i] |= b.ptr[i];
105     }
106 
107     /* Swap contents of `this` with `b`
108      */
109     void swap(ref BitArray b)
110     {
111         assert(len == b.len);
112         const nchunks = chunks(len);
113         foreach (i; 0 .. nchunks)
114         {
115             const chunk = ptr[i];
116             ptr[i] = b.ptr[i];
117             b.ptr[i] = chunk;
118         }
119     }
120 
121     ~this() pure nothrow
122     {
123         debug
124         {
125             // Stomp the allocated memory
126             const nchunks = chunks(len);
127             foreach (i; 0 .. nchunks)
128             {
129                 ptr[i] = cast(Chunk_t)0xFEFEFEFE_FEFEFEFE;
130             }
131         }
132         mem.xfree(ptr);
133         debug
134         {
135             // Set to implausible values
136             len = cast(size_t)0xFEFEFEFE_FEFEFEFE;
137             ptr = cast(size_t*)cast(size_t)0xFEFEFEFE_FEFEFEFE;
138         }
139     }
140 
141 private:
142     size_t len;         // length in bits
143     size_t *ptr;
144 
145     /// Returns: The amount of chunks used to store len bits
146     static size_t chunks(const size_t len) @nogc nothrow pure @safe
147     {
148         return (len + BitsPerChunk - 1) / BitsPerChunk;
149     }
150 
151     /// Returns: The amount of bytes used to store len bits
152     static size_t bytes(const size_t len) @nogc nothrow pure @safe
153     {
154         return chunks(len) * ChunkSize;
155     }
156 }
157 
158 unittest
159 {
160     BitArray array;
161     array.length = 20;
162     assert(array[19] == 0);
163     array[10] = 1;
164     assert(array[10] == 1);
165     array[10] = 0;
166     assert(array[10] == 0);
167     assert(array.length == 20);
168 
169     BitArray a,b;
170     assert(a != array);
171     a.length = 200;
172     assert(a != array);
173     assert(a.isZero());
174     a[100] = true;
175     b.length = 200;
176     b[100] = true;
177     assert(a == b);
178 
179     a.length = 300;
180     b.length = 300;
181     assert(a == b);
182     b[299] = true;
183     assert(a != b);
184     assert(!a.isZero());
185     a.swap(b);
186     assert(a[299] == true);
187     assert(b[299] == false);
188     a = b;
189     assert(a == b);
190 }
191 
192 
193