[Semi-OT] to!string(enumType)

Stefan Koch via Digitalmars-d digitalmars-d at puremagic.com
Thu May 18 17:14:05 PDT 2017


On Thursday, 18 May 2017 at 23:15:46 UTC, ag0aep6g wrote:
> On 05/19/2017 12:31 AM, Stefan Koch wrote:
>> string enumToString(E)(E v)
>> {
>>      static assert(is(E == enum), "emumToString is only meant 
>> for enums");
>>      mixin ({
>>      string result = "final switch(v) {\n";
>>      foreach(m;[__traits(allMembers, E)])
>>      {
>>          result ~= "\tcase E." ~ m ~ " :\n"
>>              ~ "\t\treturn \"" ~ m ~ "\";\n"
>>              ~ "\tbreak;\n";
>>      }
>>      return result ~ "}";
>>      } ());
>> }
>
> I'm sure that can be de-uglified a fair bit without hurting 
> performance.
>
> 1) "final switch(v) {" and the closing brace can be moved out 
> of the string. This should be completely free.
>
> 2) No need for `break` after `return`. Also free.
>
> 3) With a static foreach over `__traits(allMembers, E)` you can 
> get rid of the function literal. Doesn't seem to affect 
> performance much if at all.
>
> So far:
>
> ----
> string enumToString(E)(E v)
> {
>     static assert(is(E == enum),
>         "emumToString is only meant for enums");
>     final switch (v)
>     {
>         foreach(m; __traits(allMembers, E))
>         {
>             mixin("case E." ~ m ~ ": return \"" ~ m ~ "\";");
>         }
>     }
> }
> ----
>
> 4) If EnumMembers is an option, you can get rid of the string 
> mixin altogether:
>
> ----
> string enumToString(E)(E v)
> {
>     import std.meta: AliasSeq;
>     import std.traits: EnumMembers;
>     static assert(is(E == enum),
>         "emumToString is only meant for enums");
>     alias memberNames = AliasSeq!(__traits(allMembers, E));
>     final switch(v)
>     {
>         foreach(i, m; EnumMembers!E)
>         {
>             case m: return memberNames[i];
>         }
>     }
> }
> ----
>
> That takes a bit longer. May just be the time it takes to parse 
> the std.* modules. Object size stays the same.

Nice work beatifying the implementation.

Although AliasSeq and EnumMembers are unnecessary.
I incorporated your idea into the following version:

string enumToString(E)(E v)
{
     static assert(is(E == enum),
         "emumToString is only meant for enums");
     switch(v)
     {
         foreach(m; __traits(allMembers, E))
         {
             case mixin("E." ~ m) : return m;
         }

         default :
         {
             string result = "cast(" ~ E.stringof ~ ")";
             uint val = v;
             enum headLength = E.stringof.length + "cast()".length;
             uint log10Val = (val < 10) ? 0 : (val < 100) ? 1 : 
(val < 1000) ? 2 :
                 (val < 10000) ? 3 : (val < 100000) ? 4 : (val < 
1000000) ? 5 :
                 (val < 10000000) ? 6 : (val < 100000000) ? 7 : 
(val < 1000000000) ? 8 : 9;
             result.length += log10Val + 1;
             for(uint i;i != log10Val + 1;i++)
             {
                 cast(char)result[headLength + log10Val - i] = 
cast(char) ('0' + (val % 10));
                 val /= 10;
             }

             return cast(string) result;
         }
     }
}



More information about the Digitalmars-d mailing list