EnumToFlags
JS via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Jun 29 19:39:22 PDT 2016
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.
More information about the Digitalmars-d-learn
mailing list