UDAs on enum members
apz28 via Digitalmars-d
digitalmars-d at puremagic.com
Thu Aug 31 20:54:40 PDT 2017
On Wednesday, 13 July 2016 at 11:57:21 UTC, Tomer Filiba wrote:
> It would be really nice if I could put UDAs on enum members as
> well, e.g.,
>
> enum MyEnum {
> @("SOM") SomeMember,
> @("ANO") AnotherMemberWithAVeryLongName,
> }
>
> I can think of many reasons why that would be desired, but the
> concrete one is the following: I have an interchangeable data
> format, and my enum might gain members over time. I don't care
> about the value of the member, so I don't want to number them
> myself, but I can't control where users would choose to place
> the new member, so they might cause renumbering of existing
> members, breaking the interchangeable format.
>
> So what I wanted is to assign each member a "short stable name"
> that would be used to serialize the value (using my own
> dump/load functions)... But I had to resort to a long, ugly
> switch statement, mapping members to their names and vice
> versa. The dumping function uses final-switch, so you won't
> forget to update it, but the loading one can't (it takes a
> string) so it would be easy to people to forget.
>
> Given that UDAs can be used practically everywhere (including
> struct/union members), is there an objection to make them legal
> on enum members as well?
>
> And while we're on the subject, why can't enums have methods?
> At the risk of sounding as if I like Java (I don't :) ), it's a
> really nice language feature. Back to our example:
>
> enum MyEnum {
> @("SOM") SomeMember,
> @("ANO") AnotherMemberWithAVeryLongName;
>
> string dump() {
> ... // `this` is a value, not a ref here
> }
> static MyEnum load(string name) {
> ...
> }
> }
>
> Basically just allow a semicolon at the end of the members,
> after which methods could appear. Adding members or whatever
> else Java has is an overkill -- just use a struct for that. But
> instead of lots of dumpMyEnum(MyEnum e)/loadMyEnum(string s)
> pairs, you could write myMember.dump()/MyEnum.load(s)
>
>
> -tomer
Here how I implement it
struct EnumArray(E, V)
{
nothrow @safe:
public:
struct Entry
{
E e;
V v;
}
private:
enum isEntryType(T) = is(Entry == T);
enum size = EnumMembers!E.length;
V[size] _values;
public:
this(T...)(T aValues)
if (allSatisfy!(isEntryType, T))
{
foreach (ref Entry i; aValues)
_values[i.e] = i.v;
}
V opIndex(E aEnum) const
{
return _values[aEnum];
}
V opIndexAssign(V aValue, E aEnum)
{
return _values[aEnum] = aValue;
}
V opDispatch(string aEnumName)() const
{
import std.conv : to;
enum e = aEnumName.to!E;
return _values[e];
}
version (none)
V opDispatch(string aEnumName)(V aValue)
{
import std.conv : to;
enum e = aEnumName.to!E;
return _values[e] = aValue;
}
E getEnum(V aValue, E aDefault = E.min)
{
foreach (i; EnumMembers!E)
{
if (_values[i] == aValue)
return i;
}
return aDefault;
}
@property:
size_t length() const
{
return size;
}
}
unittest // EnumArray
{
enum EnumTest
{
one,
two,
max
}
alias EnumTestInt = EnumArray!(EnumTest, int);
EnumTestInt testInt = EnumTestInt(
EnumTestInt.Entry(EnumTest.one, 1),
EnumTestInt.Entry(EnumTest.two, 2),
EnumTestInt.Entry(EnumTest.max, int.max)
);
assert(testInt.one == 1);
assert(testInt.two == 2);
assert(testInt.max == int.max);
assert(testInt[EnumTest.one] == 1);
assert(testInt[EnumTest.two] == 2);
assert(testInt[EnumTest.max] == int.max);
assert(testInt.getEnum(1) == EnumTest.one);
assert(testInt.getEnum(2) == EnumTest.two);
assert(testInt.getEnum(int.max) == EnumTest.max);
assert(testInt.getEnum(3) == EnumTest.one); // Unknown ->
return default min
alias EnumTestString = EnumArray!(EnumTest, string);
EnumTestString testString = EnumTestString(
EnumTestString.Entry(EnumTest.one, "1"),
EnumTestString.Entry(EnumTest.two, "2"),
EnumTestString.Entry(EnumTest.max, "int.max")
);
assert(testString[EnumTest.one] == "1");
assert(testString[EnumTest.two] == "2");
assert(testString[EnumTest.max] == "int.max");
assert(testString.getEnum("1") == EnumTest.one);
assert(testString.getEnum("2") == EnumTest.two);
assert(testString.getEnum("int.max") == EnumTest.max);
assert(testString.getEnum("3") == EnumTest.one); // Unknown
-> return default min
}
Pham
More information about the Digitalmars-d
mailing list