Jump to page: 1 2
Thread overview
Bitfield-style enum to strings?
May 07, 2015
Nick Sabalausky
May 07, 2015
Baz
May 07, 2015
Nick Sabalausky
May 07, 2015
Nick Sabalausky
May 07, 2015
Nick Sabalausky
May 07, 2015
Justin Whear
May 07, 2015
Nick Sabalausky
May 08, 2015
Meta
May 08, 2015
Nick Sabalausky
May 08, 2015
Meta
May 07, 2015
anonymous
May 07, 2015
Assuming a plain old bitfield-style enum like:

enum Foo {
    optionA = 1<<0;
    optionB = 1<<1;
    optionC = 1<<2;
    optionD = 1<<3;
    optionE = 1<<4;
}

Does a function already exist somewhere to take an instance of Foo and get a list of the switch names as strings?

Something kinda like:

Foo fooVar = Foo.optionB | Foo.optionD;
assert(
    DOES_THIS_FUNC_EXIST(fooVar)
        .equals(["optionB", "optionD"])
);

Seems entirely feasible, although my traits-fu is a bit rusty.

May 07, 2015
On Thursday, 7 May 2015 at 17:41:10 UTC, Nick Sabalausky wrote:
> Assuming a plain old bitfield-style enum like:
>
> enum Foo {
>     optionA = 1<<0;
>     optionB = 1<<1;
>     optionC = 1<<2;
>     optionD = 1<<3;
>     optionE = 1<<4;
> }
>
> Does a function already exist somewhere to take an instance of Foo and get a list of the switch names as strings?
>
> Something kinda like:
>
> Foo fooVar = Foo.optionB | Foo.optionD;
> assert(
>     DOES_THIS_FUNC_EXIST(fooVar)
>         .equals(["optionB", "optionD"])
> );
>
> Seems entirely feasible, although my traits-fu is a bit rusty.

Hi, i have a specialized struct for "bit sets" that handles the string representation:

https://github.com/BBasile/enumset/blob/master/import/enumset.d#L242

however it's not std. Building the string is easy (cf toString()) but if it can help...

May 07, 2015
On 05/07/2015 01:41 PM, Nick Sabalausky wrote:
> Assuming a plain old bitfield-style enum like:
>
> enum Foo {
>      optionA = 1<<0;
>      optionB = 1<<1;
>      optionC = 1<<2;
>      optionD = 1<<3;
>      optionE = 1<<4;
> }
>
> Does a function already exist somewhere to take an instance of Foo and
> get a list of the switch names as strings?
>
> Something kinda like:
>
> Foo fooVar = Foo.optionB | Foo.optionD;
> assert(
>      DOES_THIS_FUNC_EXIST(fooVar)
>          .equals(["optionB", "optionD"])
> );
>
> Seems entirely feasible, although my traits-fu is a bit rusty.
>

Wow, D's seriously awesome, that was actually way easier than I expected:

------------------------------------
import std.traits : isIntegral;
auto bitFieldValues(T)(T value) if(is(T==enum) && isIntegral!T)
{
    import std.algorithm : filter, map;
    import std.conv : to;
    import std.traits : EnumMembers;

    // There's gotta be a better way to convert EnumMembers!T
    // to a range, right? But std.range.only() didn't work,
    // due to a template instantiation error.
    T[] members;
    foreach(m; EnumMembers!(T))
        members ~= m;

    return members
        .filter!(member => (value & member) == member)
        .map!(member => to!string(member));
}
------------------------------------

Sample code to use it:

------------------------------------
enum Foo
{
    optionA = 1<<0,
    optionB = 1<<1,
    optionC = 1<<2,
    optionD = 1<<3,
    optionE = 1<<4,
}

void main()
{
    import std.range : join;
    import std.stdio : writeln;

    Foo fooVar = Foo.optionB | Foo.optionD;

    // Output: optionB | optionD
    writeln(bitFieldValues(fooVar).join(" | "));
}
------------------------------------

May 07, 2015
Minor fix to work right for "none" fields. Already worked fine on combination fields liek "all".

-------------------------------------
enum Foo
{
    none = 0,
    optionA = 1<<0,
    optionB = 1<<1,
    optionC = 1<<2,
    optionD = 1<<3,
    all = optionA | optionB | optionC | optionD,
}

import std.traits : isIntegral;
auto bitFieldValues(T)(T value) if(is(T==enum) && isIntegral!T)
{
    // There's gotta be a better way to convert EnumMembers!T
    // to a range, right? But std.range.only() didn't work,
    // due to a template instantiation error.
    T[] members;
    foreach(m; EnumMembers!(T))
        members ~= m;

    return members
        .filter!(member => member==0? value==0 : (value&member)==member)
        .map!(member => to!string(member));
}

void main()
{
    import std.range : join;
    import std.stdio : writeln;

    Foo fooVar = Foo.optionB | Foo.optionD;

    // Output:
    // optionB | optionD
    // none
    // optionA | optionB | optionC | optionD | all

    writeln(bitFieldValues(Foo.optionB | Foo.optionD).join(" | "));
    writeln(bitFieldValues(Foo.none).join(" | "));
    writeln(bitFieldValues(Foo.all).join(" | "));
}
-------------------------------------

May 07, 2015
Gah, missed some imports that time:

On 05/07/2015 05:04 PM, Nick Sabalausky wrote:
> Minor fix to work right for "none" fields. Already worked fine on
> combination fields liek "all".
>
> -------------------------------------
> enum Foo
> {
>      none = 0,
>      optionA = 1<<0,
>      optionB = 1<<1,
>      optionC = 1<<2,
>      optionD = 1<<3,
>      all = optionA | optionB | optionC | optionD,
> }
>
> import std.traits : isIntegral;
> auto bitFieldValues(T)(T value) if(is(T==enum) && isIntegral!T)
> {
import std.algorithm : filter, map;
import std.conv : to;
import std.traits : EnumMembers;

>      // There's gotta be a better way to convert EnumMembers!T
>      // to a range, right? But std.range.only() didn't work,
>      // due to a template instantiation error.
>      T[] members;
>      foreach(m; EnumMembers!(T))
>          members ~= m;
>
>      return members
>          .filter!(member => member==0? value==0 : (value&member)==member)
>          .map!(member => to!string(member));
> }
>
> void main()
> {
>      import std.range : join;
>      import std.stdio : writeln;
>
>      Foo fooVar = Foo.optionB | Foo.optionD;
>
>      // Output:
>      // optionB | optionD
>      // none
>      // optionA | optionB | optionC | optionD | all
>
>      writeln(bitFieldValues(Foo.optionB | Foo.optionD).join(" | "));
>      writeln(bitFieldValues(Foo.none).join(" | "));
>      writeln(bitFieldValues(Foo.all).join(" | "));
> }
> -------------------------------------
>

May 07, 2015
On Thu, 07 May 2015 16:55:42 -0400, Nick Sabalausky wrote:

>      // There's gotta be a better way to convert EnumMembers!T // to a
>      range, right? But std.range.only() didn't work, // due to a
>      template instantiation error.
>      T[] members;
>      foreach(m; EnumMembers!(T))
>          members ~= m;

T[] members = [ EnumMembers!T ];
May 07, 2015
On 05/07/2015 05:19 PM, Justin Whear wrote:
> On Thu, 07 May 2015 16:55:42 -0400, Nick Sabalausky wrote:
>
>>       // There's gotta be a better way to convert EnumMembers!T // to a
>>       range, right? But std.range.only() didn't work, // due to a
>>       template instantiation error.
>>       T[] members;
>>       foreach(m; EnumMembers!(T))
>>           members ~= m;
>
> T[] members = [ EnumMembers!T ];
>

Doh! Yup, that works.

Still, I would think there should be a way to do it without allocating an array. But it's not a huge deal right now though.

May 07, 2015
On Thursday, 7 May 2015 at 20:55:42 UTC, Nick Sabalausky wrote:
>     // There's gotta be a better way to convert EnumMembers!T
>     // to a range, right? But std.range.only() didn't work,
>     // due to a template instantiation error.
>     T[] members;
>     foreach(m; EnumMembers!(T))
>         members ~= m;

only(EnumMembers!T) should work and did work before 2.067. I filed a regression:
https://issues.dlang.org/show_bug.cgi?id=14556
May 08, 2015
On Thursday, 7 May 2015 at 21:41:06 UTC, Nick Sabalausky wrote:
> On 05/07/2015 05:19 PM, Justin Whear wrote:
>> On Thu, 07 May 2015 16:55:42 -0400, Nick Sabalausky wrote:
>>
>>>      // There's gotta be a better way to convert EnumMembers!T // to a
>>>      range, right? But std.range.only() didn't work, // due to a
>>>      template instantiation error.
>>>      T[] members;
>>>      foreach(m; EnumMembers!(T))
>>>          members ~= m;
>>
>> T[] members = [ EnumMembers!T ];
>>
>
> Doh! Yup, that works.
>
> Still, I would think there should be a way to do it without allocating an array. But it's not a huge deal right now though.

You could also do `TypeTuple!(EnumMembers!T))` I believe.
May 08, 2015
On 05/07/2015 09:17 PM, Meta wrote:
> On Thursday, 7 May 2015 at 21:41:06 UTC, Nick Sabalausky wrote:
>> On 05/07/2015 05:19 PM, Justin Whear wrote:
>>>
>>> T[] members = [ EnumMembers!T ];
>>>
>>
>> Doh! Yup, that works.
>>
>> Still, I would think there should be a way to do it without allocating
>> an array. But it's not a huge deal right now though.
>
> You could also do `TypeTuple!(EnumMembers!T))` I believe.

filter doesn't seem to like that.

« First   ‹ Prev
1 2