diff options
Diffstat (limited to 'gcc/d/dmd/common/bitfields.d')
-rw-r--r-- | gcc/d/dmd/common/bitfields.d | 78 |
1 files changed, 61 insertions, 17 deletions
diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d index 01aa56d..72cb3e7 100644 --- a/gcc/d/dmd/common/bitfields.d +++ b/gcc/d/dmd/common/bitfields.d @@ -1,12 +1,12 @@ /** * A library bitfields utility * - * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2025 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) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/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 + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/common/bitfields.d */ module dmd.common.bitfields; @@ -20,43 +20,79 @@ module dmd.common.bitfields; extern (D) string generateBitFields(S, T)() if (__traits(isUnsigned, T)) { + import core.bitop: bsr; + string result = "extern (C++) pure nothrow @nogc @safe final {"; - enum structName = __traits(identifier, S); - string initialValue = ""; + struct BitInfo + { + int[] offset; + int[] size; + T initialValue; + int totalSize; + } + + // Iterate over members to compute bit offset and bit size for each of them + enum BitInfo bitInfo = () { + BitInfo result; + int bitOffset = 0; + foreach (size_t i, mem; __traits(allMembers, S)) + { + alias memType = typeof(__traits(getMember, S, mem)); + enum int bitSize = bsr(memType.max | 1) + 1; + result.offset ~= bitOffset; + result.size ~= bitSize; + result.initialValue |= cast(T) __traits(getMember, S.init, mem) << bitOffset; + bitOffset += bitSize; + } + result.totalSize = bitOffset; + return result; + } (); + + alias TP = typeof(T.init + 0u); // type that `T` gets promoted to, uint or ulong + enum string toString(TP i) = i.stringof; // compile time 'integer to string' + + static assert(bitInfo.totalSize <= T.sizeof * 8, + "sum of bit field size "~toString!(bitInfo.totalSize)~" exceeds storage type `"~T.stringof~"`"); + 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~")"; + enum typeName = typeof(__traits(getMember, S, mem)).stringof; + enum shift = toString!(bitInfo.offset[i]); + enum sizeMask = toString!((1 << bitInfo.size[i]) - 1); // 0x01 for bool, 0xFF for ubyte etc. result ~= " - /// set or get the corresponding "~structName~" member - bool "~mem~"() const scope { return !!(bitFields & "~mask~"); } - /// ditto - bool "~mem~"(bool v) + "~typeName~" "~mem~"() const scope { return cast("~typeName~") ((bitFields >>> "~shift~") & "~sizeMask~"); } + "~typeName~" "~mem~"("~typeName~" v) scope { - v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~"); + bitFields &= ~("~sizeMask~" << "~shift~"); + bitFields |= v << "~shift~"; return v; }"; - - initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue; } - return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n"; + enum TP initVal = bitInfo.initialValue; + return result ~ "\n}\n private "~T.stringof~" bitFields = " ~ toString!(initVal) ~ ";\n"; } /// unittest { + enum E + { + a, b, c, + } + static struct B { bool x; bool y; + E e = E.c; bool z = 1; + private ubyte w = 77; } static struct S { - mixin(generateBitFields!(B, ubyte)); + mixin(generateBitFields!(B, ushort)); } S s; @@ -69,5 +105,13 @@ unittest s.y = true; assert(s.y); assert(!s.x); + + assert(s.e == E.c); + s.e = E.a; + assert(s.e == E.a); + assert(s.z); + assert(s.w == 77); + s.w = 3; + assert(s.w == 3); } |