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 }