Wolfgang Thallergcc 15.1.0ada185d1 year agoHistory
4699 lines · 121.9 KB · D
RawDownload
// 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t