1 /**
2  * A library bitfields utility
3  *
4  * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:   Dennis Korpel
6  * License:   $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d)
8  * Documentation: https://dlang.org/phobos/dmd_common_bitfields.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/bitfields.d
10  */
11 module dmd.common.bitfields;
12 
13 /**
14  * Generate code for bit fields inside a struct/class body
15  * Params:
16  *   S = type of a struct with only boolean fields, which should become bit fields
17  *   T = type of bit fields variable, must have enough bits to store all booleans
18  * Returns: D code with a bit fields variable and getter / setter functions
19  */
20 extern (D) string generateBitFields(S, T)()
21 if (__traits(isUnsigned, T))
22 {
23     string result = "extern (C++) pure nothrow @nogc @safe final {";
24     enum structName = __traits(identifier, S);
25 
26     string initialValue = "";
27     foreach (size_t i, mem; __traits(allMembers, S))
28     {
29         static assert(is(typeof(__traits(getMember, S, mem)) == bool));
30         static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
31         enum mask = "(1 << "~i.stringof~")";
32         result ~= "
33         /// set or get the corresponding "~structName~" member
34         bool "~mem~"() const scope { return !!(bitFields & "~mask~"); }
35         /// ditto
36         bool "~mem~"(bool v)
37         {
38             v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
39             return v;
40         }";
41 
42         initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue;
43     }
44     return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n";
45 }
46 
47 ///
48 unittest
49 {
50     static struct B
51     {
52         bool x;
53         bool y;
54         bool z = 1;
55     }
56 
57     static struct S
58     {
59         mixin(generateBitFields!(B, ubyte));
60     }
61 
62     S s;
63     assert(!s.x);
64     s.x = true;
65     assert(s.x);
66     s.x = false;
67     assert(!s.x);
68 
69     s.y = true;
70     assert(s.y);
71     assert(!s.x);
72     assert(s.z);
73 }