// Written in the D programming language. /**Bit-level manipulation facilities. $(SCRIPT inhibitQuickIndex = 1;)$(DIVC quickindex,$(BOOKTABLE,$(TR $(TH Category) $(TH Functions))$(TR $(TD Bit constructs) $(TD $(LREF BitArray) $(LREF bitfields) $(LREF bitsSet)))$(TR $(TD Endianness conversion) $(TD $(LREF bigEndianToNative) $(LREF littleEndianToNative) $(LREF nativeToBigEndian) $(LREF nativeToLittleEndian) $(LREF swapEndian)))$(TR $(TD Integral ranges) $(TD $(LREF append) $(LREF peek) $(LREF read) $(LREF write)))$(TR $(TD Floating-Point manipulation) $(TD $(LREF DoubleRep) $(LREF FloatRep)))$(TR $(TD Tagging) $(TD $(LREF taggedClassRef) $(LREF taggedPointer))))) Copyright: Copyright The D Language Foundation 2007 - 2011.License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).Authors: $(HTTP digitalmars.com, Walter Bright), $(HTTP erdani.org, Andrei Alexandrescu), $(HTTP jmdavisprog.com, Jonathan M Davis), Alex Rønne Petersen, Damian Ziemba, Amaury SECHETSource: $(PHOBOSSRC std/bitmanip.d)*//* Copyright The D Language Foundation 2007 - 2012.Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)*/module std.bitmanip; import std.range.primitives;public import std.system : Endian;import std.traits; private string myToString(ulong n) pure @safe{ import core.internal.string : UnsignedStringBuf, unsignedToTempString; UnsignedStringBuf buf; auto s = unsignedToTempString(n, buf); // pure allows implicit cast to string return s ~ (n > uint.max ? "UL" : "U");} @safe pure unittest{ assert(myToString(5) == "5U"); assert(myToString(uint.max) == "4294967295U"); assert(myToString(uint.max + 1UL) == "4294967296UL");} private template createAccessors( string store, T, string name, size_t len, size_t offset){ static if (!name.length) { // No need to create any accessor enum createAccessors = ""; } else static if (len == 0) { // Fields of length 0 are always zero enum createAccessors = "enum "~T.stringof~" "~name~" = 0;\n"; } else { enum ulong maskAllElse = ((~0uL) >> (64 - len)) << offset; enum TSize = 8 * T.sizeof; enum SignShift = TSize - len; static if (T.min < 0) { enum long minVal = -(1uL << (len - 1)); enum ulong maxVal = (1uL << (len - 1)) - 1; enum RightShiftOp = ">>="; } else { enum ulong minVal = 0; enum ulong maxVal = (~0uL) >> (64 - len); enum RightShiftOp = ">>>="; } static if (is(T : bool)) { enum createAccessors = // getter "@property bool " ~ name ~ "() @safe pure nothrow @nogc const { return " ~"("~store~" & "~myToString(maskAllElse)~") != 0;}\n" // setter ~"@property void " ~ name ~ "(bool v) @safe pure nothrow @nogc { " ~"if (v) "~store~" |= "~myToString(maskAllElse)~";" ~"else "~store~" &= cast(typeof("~store~"))(-1-cast(typeof("~store~"))"~myToString(maskAllElse)~");}\n"; } else { // getter enum createAccessors = "@property "~T.stringof~" "~name~"() @safe pure nothrow @nogc const {" ~ "auto result = cast("~T.stringof~") (" ~ store ~ " >>" ~ myToString(offset) ~ ");" ~ "result <<= " ~ myToString(SignShift) ~ ";" ~ "result " ~ RightShiftOp ~ myToString(SignShift) ~ ";" ~ " return result;}\n" // setter ~"@property void "~name~"("~T.stringof~" v) @safe pure nothrow @nogc { " ~"assert(v >= "~name~`_min, "Value is smaller than the minimum value of bitfield '`~name~`'"); ` ~"assert(v <= "~name~`_max, "Value is greater than the maximum value of bitfield '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (-1-cast(typeof("~store~"))"~myToString(maskAllElse)~"))" ~" | ((cast(typeof("~store~")) v << "~myToString(offset)~")" ~" & "~myToString(maskAllElse)~"));}\n" // constants ~"enum "~T.stringof~" "~name~"_min = cast("~T.stringof~")" ~myToString(minVal)~"; " ~" enum "~T.stringof~" "~name~"_max = cast("~T.stringof~")" ~myToString(maxVal)~"; "; } }} private template createStoreName(Ts...){ static if (Ts.length < 2) enum createStoreName = "_bf"; else enum createStoreName = "_" ~ Ts[1] ~ createStoreName!(Ts[3 .. $]);} private template createStorageAndFields(Ts...){ enum Name = createStoreName!Ts; enum Size = sizeOfBitField!Ts; static if (Size == ubyte.sizeof * 8) alias StoreType = ubyte; else static if (Size == ushort.sizeof * 8) alias StoreType = ushort; else static if (Size == uint.sizeof * 8) alias StoreType = uint; else static if (Size == ulong.sizeof * 8) alias StoreType = ulong; else { static assert(false, "Field widths must sum to 8, 16, 32, or 64, not " ~ Size.stringof); alias StoreType = ulong; // just to avoid another error msg } enum createStorageAndFields = "private " ~ StoreType.stringof ~ " " ~ Name ~ ";" ~ createFields!(Name, 0, Ts);} private template createFields(string store, size_t offset, Ts...){ static if (Ts.length > 0) enum createFields = createAccessors!(store, Ts[0], Ts[1], Ts[2], offset) ~ createFields!(store, offset + Ts[2], Ts[3 .. $]); else enum createFields = "";} private ulong getBitsForAlign(ulong a){ ulong bits = 0; while ((a & 0x01) == 0) { bits++; a >>= 1; } assert(a == 1, "alignment is not a power of 2"); return bits;} private template createReferenceAccessor(string store, T, ulong bits, string name){ enum storage = "private void* " ~ store ~ "_ptr;\n"; enum storage_accessor = "@property ref size_t " ~ store ~ "() return @trusted pure nothrow @nogc const { " ~ "return *cast(size_t*) &" ~ store ~ "_ptr;}\n" ~ "@property void " ~ store ~ "(size_t v) @trusted pure nothrow @nogc { " ~ "" ~ store ~ "_ptr = cast(void*) v;}\n"; enum mask = (1UL << bits) - 1; // getter enum ref_accessor = "@property "~T.stringof~" "~name~"() @trusted pure nothrow @nogc const { auto result = " ~ "("~store~" & "~myToString(~mask)~"); " ~ "return cast("~T.stringof~") cast(void*) result;}\n" // setter ~"@property void "~name~"("~T.stringof~" v) @trusted pure nothrow @nogc { " ~"assert(((cast(typeof("~store~")) cast(void*) v) & "~myToString(mask) ~`) == 0, "Value not properly aligned for '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (cast(typeof("~store~")) "~myToString(mask)~"))" ~" | ((cast(typeof("~store~")) cast(void*) v) & (cast(typeof("~store~")) "~myToString(~mask)~")));}\n"; enum createReferenceAccessor = storage ~ storage_accessor ~ ref_accessor;} private template sizeOfBitField(T...){ static if (T.length < 2) enum sizeOfBitField = 0; else enum sizeOfBitField = T[2] + sizeOfBitField!(T[3 .. $]);} private template createTaggedReference(T, ulong a, string name, Ts...){ static assert( sizeOfBitField!Ts <= getBitsForAlign(a), "Fields must fit in the bits know to be zero because of alignment." ); enum StoreName = createStoreName!(T, name, 0, Ts); enum createTaggedReference = createReferenceAccessor!(StoreName, T, sizeOfBitField!Ts, name) ~ createFields!(StoreName, 0, Ts, size_t, "", T.sizeof * 8 - sizeOfBitField!Ts);} /**Allows creating `bitfields` inside `structs`, `classes` and `unions`. A `bitfield` consists of one or more entries with a fixed number ofbits reserved for each of the entries. The types of the entries canbe `bool`s, integral types or enumerated types, arbitrarily mixed.The most efficient type to store in `bitfields` is `bool`, followedby unsigned types, followed by signed types. Each non-`bool` entry of the `bitfield` will be represented by thenumber of bits specified by the user. The minimum and the maximumnumbers that represent this domain can be queried by using the nameof the variable followed by `_min` or `_max`. Limitation: The number of bits in a `bitfield` is limited to 8, 16,32 or 64. If padding is needed, an entry should be explicitlyallocated with an empty name. Implementation_details: `Bitfields` are internally stored in an`ubyte`, `ushort`, `uint` or `ulong` depending on the number of bitsused. The bits are filled in the order given by the parameters,starting with the lowest significant bit. The name of the (private)variable used for saving the `bitfield` is created by concatenatingall of the variable names, each preceded by an underscore, anda suffix `_bf`. Params: T = A list of template parameters divided into chunks of 3 items. Each chunk consists (in this order) of a type, a name and a number. Together they define an entry of the `bitfield`: a variable of the given type and name, which can hold as many bits as the number denotes. Returns: A string that can be used in a `mixin` to add the `bitfield`. See_Also: $(REF BitFlags, std,typecons)*/string bitfields(T...)(){ static assert(T.length % 3 == 0, "Wrong number of arguments (" ~ T.length.stringof ~ "): Must be a multiple of 3"); static foreach (i, ARG; T) { static if (i % 3 == 0) static assert(is (typeof({ARG tmp = cast (ARG)0; if (ARG.min < 0) {} }())), "Integral type or `bool` expected, found " ~ ARG.stringof); // would be nice to check for valid variable names too static if (i % 3 == 1) static assert(is (typeof(ARG) : string), "Variable name expected, found " ~ ARG.stringof); static if (i % 3 == 2) { static assert(is (typeof({ulong tmp = ARG;}())), "Integral value expected, found " ~ ARG.stringof); static if (T[i-1] != "") { static assert(!is (T[i-2] : bool) || ARG <= 1, "Type `bool` is only allowed for single-bit fields"); static assert(ARG >= 0 && ARG <= T[i-2].sizeof * 8, "Wrong size of bitfield: " ~ ARG.stringof); } } } return createStorageAndFields!T;} /**Create a `bitfield` pack of eight bits, which fit inone `ubyte`. The `bitfields` are allocated starting from theleast significant bit, i.e. `x` occupies the two least significant bitsof the `bitfields` storage.*/@safe unittest{ struct A { int a; mixin(bitfields!( uint, "x", 2, int, "y", 3, uint, "z", 2, bool, "flag", 1)); } A obj; obj.x = 2; obj.z = obj.x; assert(obj.x == 2); assert(obj.y == 0); assert(obj.z == 2); assert(obj.flag == false);} /**The sum of all bit lengths in one `bitfield` instantiationmust be exactly 8, 16, 32, or 64. If padding is needed, just allocateone bitfield with an empty name.*/@safe unittest{ struct A { mixin(bitfields!( bool, "flag1", 1, bool, "flag2", 1, uint, "", 6)); } A a; assert(a.flag1 == 0); a.flag1 = 1; assert(a.flag1 == 1); a.flag1 = 0; assert(a.flag1 == 0);} /// enums can be used too@safe unittest{ enum ABC { A, B, C } struct EnumTest { mixin(bitfields!( ABC, "x", 2, bool, "y", 1, ubyte, "z", 5)); }} @safe pure nothrow @nogcunittest{ // Degenerate bitfields tests mixed with range tests // https://issues.dlang.org/show_bug.cgi?id=8474 // https://issues.dlang.org/show_bug.cgi?id=11160 struct Test1 { mixin(bitfields!(uint, "a", 32, uint, "b", 4, uint, "c", 4, uint, "d", 8, uint, "e", 16,)); static assert(Test1.b_min == 0); static assert(Test1.b_max == 15); } struct Test2 { mixin(bitfields!(bool, "a", 0, ulong, "b", 64)); static assert(Test2.b_min == ulong.min); static assert(Test2.b_max == ulong.max); } struct Test1b { mixin(bitfields!(bool, "a", 0, int, "b", 8)); } struct Test2b { mixin(bitfields!(int, "a", 32, int, "b", 4, int, "c", 4, int, "d", 8, int, "e", 16,)); static assert(Test2b.b_min == -8); static assert(Test2b.b_max == 7); } struct Test3b { mixin(bitfields!(bool, "a", 0, long, "b", 64)); static assert(Test3b.b_min == long.min); static assert(Test3b.b_max == long.max); } struct Test4b { mixin(bitfields!(long, "a", 32, int, "b", 32)); } // Sign extension tests Test2b t2b; Test4b t4b; t2b.b = -5; assert(t2b.b == -5); t2b.d = -5; assert(t2b.d == -5); t2b.e = -5; assert(t2b.e == -5); t4b.a = -5; assert(t4b.a == -5L);} // https://issues.dlang.org/show_bug.cgi?id=6686@safe unittest{ union S { ulong bits = ulong.max; mixin (bitfields!( ulong, "back", 31, ulong, "front", 33) ); } S num; num.bits = ulong.max; num.back = 1; assert(num.bits == 0xFFFF_FFFF_8000_0001uL);} // https://issues.dlang.org/show_bug.cgi?id=5942@safe unittest{ struct S { mixin(bitfields!( int, "a" , 32, int, "b" , 32 )); } S data; data.b = 42; data.a = 1; assert(data.b == 42);} @safe unittest{ struct Test { mixin(bitfields!(bool, "a", 1, uint, "b", 3, short, "c", 4)); } @safe void test() pure nothrow { Test t; t.a = true; t.b = 5; t.c = 2; assert(t.a); assert(t.b == 5); assert(t.c == 2);Lines 1–500 of 4699. Load more
// Written in the D programming language. /** Bit-level manipulation facilities. $(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex, $(BOOKTABLE, $(TR $(TH Category) $(TH Functions)) $(TR $(TD Bit constructs) $(TD $(LREF BitArray) $(LREF bitfields) $(LREF bitsSet) )) $(TR $(TD Endianness conversion) $(TD $(LREF bigEndianToNative) $(LREF littleEndianToNative) $(LREF nativeToBigEndian) $(LREF nativeToLittleEndian) $(LREF swapEndian) )) $(TR $(TD Integral ranges) $(TD $(LREF append) $(LREF peek) $(LREF read) $(LREF write) )) $(TR $(TD Floating-Point manipulation) $(TD $(LREF DoubleRep) $(LREF FloatRep) )) $(TR $(TD Tagging) $(TD $(LREF taggedClassRef) $(LREF taggedPointer) )) )) Copyright: Copyright The D Language Foundation 2007 - 2011. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP digitalmars.com, Walter Bright), $(HTTP erdani.org, Andrei Alexandrescu), $(HTTP jmdavisprog.com, Jonathan M Davis), Alex Rønne Petersen, Damian Ziemba, Amaury SECHET Source: $(PHOBOSSRC std/bitmanip.d) */ /* Copyright The D Language Foundation 2007 - 2012. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ module std.bitmanip; import std.range.primitives; public import std.system : Endian; import std.traits; private string myToString(ulong n) pure @safe { import core.internal.string : UnsignedStringBuf, unsignedToTempString; UnsignedStringBuf buf; auto s = unsignedToTempString(n, buf); // pure allows implicit cast to string return s ~ (n > uint.max ? "UL" : "U"); } @safe pure unittest { assert(myToString(5) == "5U"); assert(myToString(uint.max) == "4294967295U"); assert(myToString(uint.max + 1UL) == "4294967296UL"); } private template createAccessors( string store, T, string name, size_t len, size_t offset) { static if (!name.length) { // No need to create any accessor enum createAccessors = ""; } else static if (len == 0) { // Fields of length 0 are always zero enum createAccessors = "enum "~T.stringof~" "~name~" = 0;\n"; } else { enum ulong maskAllElse = ((~0uL) >> (64 - len)) << offset; enum TSize = 8 * T.sizeof; enum SignShift = TSize - len; static if (T.min < 0) { enum long minVal = -(1uL << (len - 1)); enum ulong maxVal = (1uL << (len - 1)) - 1; enum RightShiftOp = ">>="; } else { enum ulong minVal = 0; enum ulong maxVal = (~0uL) >> (64 - len); enum RightShiftOp = ">>>="; } static if (is(T : bool)) { enum createAccessors = // getter "@property bool " ~ name ~ "() @safe pure nothrow @nogc const { return " ~"("~store~" & "~myToString(maskAllElse)~") != 0;}\n" // setter ~"@property void " ~ name ~ "(bool v) @safe pure nothrow @nogc { " ~"if (v) "~store~" |= "~myToString(maskAllElse)~";" ~"else "~store~" &= cast(typeof("~store~"))(-1-cast(typeof("~store~"))"~myToString(maskAllElse)~");}\n"; } else { // getter enum createAccessors = "@property "~T.stringof~" "~name~"() @safe pure nothrow @nogc const {" ~ "auto result = cast("~T.stringof~") (" ~ store ~ " >>" ~ myToString(offset) ~ ");" ~ "result <<= " ~ myToString(SignShift) ~ ";" ~ "result " ~ RightShiftOp ~ myToString(SignShift) ~ ";" ~ " return result;}\n" // setter ~"@property void "~name~"("~T.stringof~" v) @safe pure nothrow @nogc { " ~"assert(v >= "~name~`_min, "Value is smaller than the minimum value of bitfield '`~name~`'"); ` ~"assert(v <= "~name~`_max, "Value is greater than the maximum value of bitfield '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (-1-cast(typeof("~store~"))"~myToString(maskAllElse)~"))" ~" | ((cast(typeof("~store~")) v << "~myToString(offset)~")" ~" & "~myToString(maskAllElse)~"));}\n" // constants ~"enum "~T.stringof~" "~name~"_min = cast("~T.stringof~")" ~myToString(minVal)~"; " ~" enum "~T.stringof~" "~name~"_max = cast("~T.stringof~")" ~myToString(maxVal)~"; "; } } } private template createStoreName(Ts...) { static if (Ts.length < 2) enum createStoreName = "_bf"; else enum createStoreName = "_" ~ Ts[1] ~ createStoreName!(Ts[3 .. $]); } private template createStorageAndFields(Ts...) { enum Name = createStoreName!Ts; enum Size = sizeOfBitField!Ts; static if (Size == ubyte.sizeof * 8) alias StoreType = ubyte; else static if (Size == ushort.sizeof * 8) alias StoreType = ushort; else static if (Size == uint.sizeof * 8) alias StoreType = uint; else static if (Size == ulong.sizeof * 8) alias StoreType = ulong; else { static assert(false, "Field widths must sum to 8, 16, 32, or 64, not " ~ Size.stringof); alias StoreType = ulong; // just to avoid another error msg } enum createStorageAndFields = "private " ~ StoreType.stringof ~ " " ~ Name ~ ";" ~ createFields!(Name, 0, Ts); } private template createFields(string store, size_t offset, Ts...) { static if (Ts.length > 0) enum createFields = createAccessors!(store, Ts[0], Ts[1], Ts[2], offset) ~ createFields!(store, offset + Ts[2], Ts[3 .. $]); else enum createFields = ""; } private ulong getBitsForAlign(ulong a) { ulong bits = 0; while ((a & 0x01) == 0) { bits++; a >>= 1; } assert(a == 1, "alignment is not a power of 2"); return bits; } private template createReferenceAccessor(string store, T, ulong bits, string name) { enum storage = "private void* " ~ store ~ "_ptr;\n"; enum storage_accessor = "@property ref size_t " ~ store ~ "() return @trusted pure nothrow @nogc const { " ~ "return *cast(size_t*) &" ~ store ~ "_ptr;}\n" ~ "@property void " ~ store ~ "(size_t v) @trusted pure nothrow @nogc { " ~ "" ~ store ~ "_ptr = cast(void*) v;}\n"; enum mask = (1UL << bits) - 1; // getter enum ref_accessor = "@property "~T.stringof~" "~name~"() @trusted pure nothrow @nogc const { auto result = " ~ "("~store~" & "~myToString(~mask)~"); " ~ "return cast("~T.stringof~") cast(void*) result;}\n" // setter ~"@property void "~name~"("~T.stringof~" v) @trusted pure nothrow @nogc { " ~"assert(((cast(typeof("~store~")) cast(void*) v) & "~myToString(mask) ~`) == 0, "Value not properly aligned for '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (cast(typeof("~store~")) "~myToString(mask)~"))" ~" | ((cast(typeof("~store~")) cast(void*) v) & (cast(typeof("~store~")) "~myToString(~mask)~")));}\n"; enum createReferenceAccessor = storage ~ storage_accessor ~ ref_accessor; } private template sizeOfBitField(T...) { static if (T.length < 2) enum sizeOfBitField = 0; else enum sizeOfBitField = T[2] + sizeOfBitField!(T[3 .. $]); } private template createTaggedReference(T, ulong a, string name, Ts...) { static assert( sizeOfBitField!Ts <= getBitsForAlign(a), "Fields must fit in the bits know to be zero because of alignment." ); enum StoreName = createStoreName!(T, name, 0, Ts); enum createTaggedReference = createReferenceAccessor!(StoreName, T, sizeOfBitField!Ts, name) ~ createFields!(StoreName, 0, Ts, size_t, "", T.sizeof * 8 - sizeOfBitField!Ts); } /** Allows creating `bitfields` inside `structs`, `classes` and `unions`. A `bitfield` consists of one or more entries with a fixed number of bits reserved for each of the entries. The types of the entries can be `bool`s, integral types or enumerated types, arbitrarily mixed. The most efficient type to store in `bitfields` is `bool`, followed by unsigned types, followed by signed types. Each non-`bool` entry of the `bitfield` will be represented by the number of bits specified by the user. The minimum and the maximum numbers that represent this domain can be queried by using the name of the variable followed by `_min` or `_max`. Limitation: The number of bits in a `bitfield` is limited to 8, 16, 32 or 64. If padding is needed, an entry should be explicitly allocated with an empty name. Implementation_details: `Bitfields` are internally stored in an `ubyte`, `ushort`, `uint` or `ulong` depending on the number of bits used. The bits are filled in the order given by the parameters, starting with the lowest significant bit. The name of the (private) variable used for saving the `bitfield` is created by concatenating all of the variable names, each preceded by an underscore, and a suffix `_bf`. Params: T = A list of template parameters divided into chunks of 3 items. Each chunk consists (in this order) of a type, a name and a number. Together they define an entry of the `bitfield`: a variable of the given type and name, which can hold as many bits as the number denotes. Returns: A string that can be used in a `mixin` to add the `bitfield`. See_Also: $(REF BitFlags, std,typecons) */ string bitfields(T...)() { static assert(T.length % 3 == 0, "Wrong number of arguments (" ~ T.length.stringof ~ "): Must be a multiple of 3"); static foreach (i, ARG; T) { static if (i % 3 == 0) static assert(is (typeof({ARG tmp = cast (ARG)0; if (ARG.min < 0) {} }())), "Integral type or `bool` expected, found " ~ ARG.stringof); // would be nice to check for valid variable names too static if (i % 3 == 1) static assert(is (typeof(ARG) : string), "Variable name expected, found " ~ ARG.stringof); static if (i % 3 == 2) { static assert(is (typeof({ulong tmp = ARG;}())), "Integral value expected, found " ~ ARG.stringof); static if (T[i-1] != "") { static assert(!is (T[i-2] : bool) || ARG <= 1, "Type `bool` is only allowed for single-bit fields"); static assert(ARG >= 0 && ARG <= T[i-2].sizeof * 8, "Wrong size of bitfield: " ~ ARG.stringof); } } } return createStorageAndFields!T; } /** Create a `bitfield` pack of eight bits, which fit in one `ubyte`. The `bitfields` are allocated starting from the least significant bit, i.e. `x` occupies the two least significant bits of the `bitfields` storage. */ @safe unittest { struct A { int a; mixin(bitfields!( uint, "x", 2, int, "y", 3, uint, "z", 2, bool, "flag", 1)); } A obj; obj.x = 2; obj.z = obj.x; assert(obj.x == 2); assert(obj.y == 0); assert(obj.z == 2); assert(obj.flag == false); } /** The sum of all bit lengths in one `bitfield` instantiation must be exactly 8, 16, 32, or 64. If padding is needed, just allocate one bitfield with an empty name. */ @safe unittest { struct A { mixin(bitfields!( bool, "flag1", 1, bool, "flag2", 1, uint, "", 6)); } A a; assert(a.flag1 == 0); a.flag1 = 1; assert(a.flag1 == 1); a.flag1 = 0; assert(a.flag1 == 0); } /// enums can be used too @safe unittest { enum ABC { A, B, C } struct EnumTest { mixin(bitfields!( ABC, "x", 2, bool, "y", 1, ubyte, "z", 5)); } } @safe pure nothrow @nogc unittest { // Degenerate bitfields tests mixed with range tests // https://issues.dlang.org/show_bug.cgi?id=8474 // https://issues.dlang.org/show_bug.cgi?id=11160 struct Test1 { mixin(bitfields!(uint, "a", 32, uint, "b", 4, uint, "c", 4, uint, "d", 8, uint, "e", 16,)); static assert(Test1.b_min == 0); static assert(Test1.b_max == 15); } struct Test2 { mixin(bitfields!(bool, "a", 0, ulong, "b", 64)); static assert(Test2.b_min == ulong.min); static assert(Test2.b_max == ulong.max); } struct Test1b { mixin(bitfields!(bool, "a", 0, int, "b", 8)); } struct Test2b { mixin(bitfields!(int, "a", 32, int, "b", 4, int, "c", 4, int, "d", 8, int, "e", 16,)); static assert(Test2b.b_min == -8); static assert(Test2b.b_max == 7); } struct Test3b { mixin(bitfields!(bool, "a", 0, long, "b", 64)); static assert(Test3b.b_min == long.min); static assert(Test3b.b_max == long.max); } struct Test4b { mixin(bitfields!(long, "a", 32, int, "b", 32)); } // Sign extension tests Test2b t2b; Test4b t4b; t2b.b = -5; assert(t2b.b == -5); t2b.d = -5; assert(t2b.d == -5); t2b.e = -5; assert(t2b.e == -5); t4b.a = -5; assert(t4b.a == -5L); } // https://issues.dlang.org/show_bug.cgi?id=6686 @safe unittest { union S { ulong bits = ulong.max; mixin (bitfields!( ulong, "back", 31, ulong, "front", 33) ); } S num; num.bits = ulong.max; num.back = 1; assert(num.bits == 0xFFFF_FFFF_8000_0001uL); } // https://issues.dlang.org/show_bug.cgi?id=5942 @safe unittest { struct S { mixin(bitfields!( int, "a" , 32, int, "b" , 32 )); } S data; data.b = 42; data.a = 1; assert(data.b == 42); } @safe unittest { struct Test { mixin(bitfields!(bool, "a", 1, uint, "b", 3, short, "c", 4)); } @safe void test() pure nothrow { Test t; t.a = true; t.b = 5; t.c = 2; assert(t.a); assert(t.b == 5); assert(t.c == 2);