bit-manipulationdbitphobos

Manipulating Bits of Any Value Type


Has anybody cooked up some generic functions that extend core.bitop bitmanipulations to work on any value type?

Something like

bool getBit(T)(in T a, int bitnum); // bt
T setBit(T)(in T a, int bitnum); // bts
auto ref setBitInPlace(T)(ref T a, int bitnum);

I know this is relatively easy to implement so that's why I'm curious to why its not already Phobos.

Update:

Here's my first try at this:

bool getBit(T, I)(in T a, I bitnum) @safe pure nothrow if (isIntegral!T &&
                                                           isIntegral!I) {
    return a & (((cast(I)1) << bitnum)) ? true : false;
}

bool getBit(T, I)(in T a, I bitnum) @trusted pure nothrow if ((!(isIntegral!T)) &&
                                                              isIntegral!I) {
    enum nBits = 8*T.sizeof;
    static      if (nBits ==  8) alias I = ubyte;
    else static if (nBits == 16) alias I = ushort;
    else static if (nBits == 32) alias I = uint;
    else static if (nBits == 64) alias I = ulong;
    return (*(cast(I*)&a)).getBit(bitnum); // reuse integer variant
}
alias bt = getBit;

My idea is to make getBit work on all types that have value semantics. That's why I need the cast (I think). Is there a traits to check if a type has value semantics or not?

Also is there a trait to check if a type supports a specific operation such as bitwise and &? I could always use __traits(compiles, ...) but standardization is good.

To make it even better I guess I need an explicit overload for T's that support bit manipulations in order to make this variant @safe right? In my generic solution above I need the cast and that's @unsafe.

See also: http://forum.dlang.org/thread/tekrnzkemcbujbivvfpv@forum.dlang.org#post-tekrnzkemcbujbivvfpv:40forum.dlang.org


Solution

  • Is there a traits to check if a type has value semantics or not?

    There is no trait for value types, at least not in the documentation However, I have checked for value types before using the "is expression":

    import std.stdio;
    
    struct Foo {}
    
    auto fn(T)(T type)
    {
        static if (is(T == struct)) {
            writeln(T.stringof ~ " is a value type");   
        } else if (is(T == class)) {
            writeln(T.stringof ~ " is a reference type");   
        } else {
            writeln(T.stringof ~ " is something else"); 
        }
    }
    
    void main()
    {
        Foo f;
    
        fn(f);
        fn(new Object());
        fn(1);
    }
    

    Also is there a trait to check if a type supports a specific operation such as bitwise and &?

    Other than the trait for compiles, this can also be achieved with an is expression. This is similar to how it is currently done for ranges, for example:

    import std.stdio;
    
    struct Foo {
        auto opBinary(string op)(Foo rhs) 
            if (op == "&")
        {
            return rhs.init; // dummy implementation
        }
    };
    
    template canUseBitOps(T)
    {
        enum bool canUseBitOps = is(typeof(
        (inout int = 0)
        {
            T t1 = T.init;
            T t2 = T.init;
            auto r = t1 & t2;
        }));
    }
    
    void main()
    {
        assert(canUseBitOps!int);
        assert(!canUseBitOps!string);
        assert(canUseBitOps!Foo);
    }