I created a type that makes working with flags much easier. Please review for issues and enhancements. It would be nice to simplify the value size code.

struct EnumToFlags(alias E)
{
import std.traits, std.conv, std.string, std.algorithm, std.array;

        static if (E.max < 8)        
                alias vtype = ubyte;
        else static if (E.max < 16)
                alias vtype = ushort;
        else static if (E.max < 32)
                alias vtype = uint;
        else static if (E.max < 64)
                alias vtype = ulong;
        else static if (E.max < 128)
                alias vtype = ucent;
else static assert("Cannot store more than 128 flags in an enum.");

        vtype value;


        template opDispatch(string Name)
        {
                enum opDispatch = 1 << __traits(getMember, E, Name);
        }


        auto opAssign(vtype e)
        {
                value = e;
        }

        bool opEquals(typeof(this) e)
        {
                if (e is this) return true;     
                return (value == e.value);
        }

        auto opBinary(string op)(typeof(this) e)
        {
                auto x = typeof(this)();
                mixin("x.value = this.value "~op~" e.value;");
                return x;
        }

        auto opUnary(string op)()
        {
                auto x = typeof(this)();
                mixin("x.value = "~op~"this.value;");
                return x;
        }

        auto opCast()
        {
                return value;
        }

        auto toString()
        {
                string s;       
                foreach(i, e; EnumMembers!E)
                {
                        if (((1 << i) & value) == 1 << i)
                                s ~= to!string(e) ~ " | ";    
                }
                if (s.length > 0)
                        s = s[0..$-3];
                return s;
        }


        this(string from)
        {                               
                char uOp = ' ';
                char Op = '=';
                char nOp = '=';
                int previdx = 0;
                value = 0;
                for(int i = 0; i < from.length; i++)
                {

                        nOp = from[i];                  
                        if (nOp == '!' || nOp == '~')                   
                        {
                                uOp = nOp;
                                previdx = i + 1;
                                continue;
                        }
                        
if (nOp == '&' || nOp == '^' || nOp == '|' || nOp == '+' || nOp == '-' || i == from.length-1)
                        {

auto v = from[previdx..(i + ((i == from.length-1) ? 1 : 0))].strip();
                                vtype x = 0;
                                foreach(j, e; EnumMembers!E)
                                        if (to!string(e) == v)
                                                x = cast(vtype)(1 << j);        
          

                                if (uOp == '!')
                                        x = !x;
                                if (uOp == '~')
                                        x = ~x;

                                switch(Op)
                                {
                                        case '&': value = cast(vtype)(value & 
x); break;
                                        case '|': value = cast(vtype)(value | 
x); break;
                                        case '+': value = cast(vtype)(value + 
x); break;
                                        case '-': value = cast(vtype)(value - 
x); break;
                                        case '^': value = cast(vtype)(value ^ 
x); break;
                                        case '=': value = cast(vtype)(x); break;
                                        default: assert("Invalid EnumFlags operation 
`"~Op~"`.");
                                }

                                previdx = i + 1;
                                Op = nOp;
                                uOp = ' ';
                        }
                }

        }

        alias value this;
};

Possibly the to and from string stuff can be improved? Simply apply to a pre-existing enum.

Reply via email to