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