blob: bba61ad371545e72fab759b674977e2e6f51a0a1 [file] [log] [blame]
/**
* A library bitfields utility
*
* Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
* Authors: Dennis Korpel
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d)
* Documentation: https://dlang.org/phobos/dmd_common_bitfields.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/bitfields.d
*/
module dmd.common.bitfields;
/**
* Generate code for bit fields inside a struct/class body
* Params:
* S = type of a struct with only boolean fields, which should become bit fields
* T = type of bit fields variable, must have enough bits to store all booleans
* Returns: D code with a bit fields variable and getter / setter functions
*/
extern (D) string generateBitFields(S, T)()
if (__traits(isUnsigned, T))
{
string result = "extern (C++) pure nothrow @nogc @safe final {";
enum structName = __traits(identifier, S);
string initialValue = "";
foreach (size_t i, mem; __traits(allMembers, S))
{
static assert(is(typeof(__traits(getMember, S, mem)) == bool));
static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
enum mask = "(1 << "~i.stringof~")";
result ~= "
/// set or get the corresponding "~structName~" member
bool "~mem~"() const scope { return !!(bitFields & "~mask~"); }
/// ditto
bool "~mem~"(bool v)
{
v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
return v;
}";
initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue;
}
return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n";
}
///
unittest
{
static struct B
{
bool x;
bool y;
bool z = 1;
}
static struct S
{
mixin(generateBitFields!(B, ubyte));
}
S s;
assert(!s.x);
s.x = true;
assert(s.x);
s.x = false;
assert(!s.x);
s.y = true;
assert(s.y);
assert(!s.x);
assert(s.z);
}