digitalmars.D.learn - Bitfield-style enum to strings?
- Nick Sabalausky (17/17) May 07 2015 Assuming a plain old bitfield-style enum like:
- Baz (6/23) May 07 2015 Hi, i have a specialized struct for "bit sets" that handles the
- Nick Sabalausky (39/56) May 07 2015 Wow, D's seriously awesome, that was actually way easier than I expected...
- Nick Sabalausky (39/39) May 07 2015 Minor fix to work right for "none" fields. Already worked fine on
- Nick Sabalausky (5/44) May 07 2015 import std.algorithm : filter, map;
- Justin Whear (2/8) May 07 2015 T[] members = [ EnumMembers!T ];
- Nick Sabalausky (4/12) May 07 2015 Doh! Yup, that works.
- Meta (2/19) May 07 2015 You could also do `TypeTuple!(EnumMembers!T))` I believe.
- Nick Sabalausky (2/13) May 07 2015 filter doesn't seem to like that.
- Meta (2/17) May 08 2015 Yeah, sorry, forgot it was supposed to go through a range as well.
- anonymous (4/10) May 07 2015 only(EnumMembers!T) should work and did work before 2.067. I
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: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.// 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 Thursday, 7 May 2015 at 21:41:06 UTC, Nick Sabalausky wrote:On 05/07/2015 05:19 PM, Justin Whear wrote:You could also do `TypeTuple!(EnumMembers!T))` I believe.On Thu, 07 May 2015 16:55:42 -0400, Nick Sabalausky wrote: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.// 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 09:17 PM, Meta wrote:On Thursday, 7 May 2015 at 21:41:06 UTC, Nick Sabalausky wrote:filter doesn't seem to like that.On 05/07/2015 05:19 PM, Justin Whear wrote:You could also do `TypeTuple!(EnumMembers!T))` I believe.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 Friday, 8 May 2015 at 04:11:36 UTC, Nick Sabalausky wrote:On 05/07/2015 09:17 PM, Meta wrote:Yeah, sorry, forgot it was supposed to go through a range as well.On Thursday, 7 May 2015 at 21:41:06 UTC, Nick Sabalausky wrote:filter doesn't seem to like that.On 05/07/2015 05:19 PM, Justin Whear wrote:You could also do `TypeTuple!(EnumMembers!T))` I believe.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 08 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 07 2015