www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - foreach over enums?

reply %u <e ee.com> writes:
enum X { A=3, B=1, C }

void main() {
    foreach(e;X)
        writefln(e.stringof," = ",e);
}
//X.A = 3
//X.B = 1
//X.C = 2
or
//X.B = 1
//X.C = 2
//X.A = 3
Sep 21 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
%u <e ee.com> wrote:

 enum X { A=3, B=1, C }

 void main() {
     foreach(e;X)
         writefln(e.stringof," = ",e);
 }
 //X.A = 3
 //X.B = 1
 //X.C = 2
 or
 //X.B = 1
 //X.C = 2
 //X.A = 3
enum X { A=3, B=1, C } void main( ) { foreach( e; __traits(allMembers, X) ) { writeln( "X.", e, " = ", mixin( "X."~e ) ); } } -- Simen
Sep 21 2010
next sibling parent reply %u <e ee.com> writes:
== Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 enum X { A=3, B=1, C }

 void main() {
     foreach(e;X)
         writefln(e.stringof," = ",e);
 }
 //X.A = 3
 //X.B = 1
 //X.C = 2
 or
 //X.B = 1
 //X.C = 2
 //X.A = 3
enum X { A=3, B=1, C } void main( ) { foreach( e; __traits(allMembers, X) ) { writeln( "X.", e, " = ", mixin( "X."~e ) ); } }
D1 :'(
Sep 21 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
%u <e ee.com> wrote:

 == Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 enum X { A=3, B=1, C }

 void main() {
     foreach(e;X)
         writefln(e.stringof," = ",e);
 }
 //X.A = 3
 //X.B = 1
 //X.C = 2
 or
 //X.B = 1
 //X.C = 2
 //X.A = 3
enum X { A=3, B=1, C } void main( ) { foreach( e; __traits(allMembers, X) ) { writeln( "X.", e, " = ", mixin( "X."~e ) ); } }
D1 :'(
Oh. Without being an expert on D1 matters, I believe that is impossible. I thought there was a struct called defineEnum in phobos1, but it appears I am wrong. However, it should be fairly simple to create one. Untested code, as I do not have D1 installed: struct defineEnum( T... ) { foreach ( i, e; T ) { mixin( "static defineEnum " ~ e ~ " = defineEnum( i );" ); } static int opApply( int delegate( ref bar ) dg ) { int result = 0; foreach ( e; T ) { mixin( "result = dg( " ~ e ~ " ) );" ); if ( result ) { break; } } return result; } } -- Simen
Sep 21 2010
parent reply %u <e ee.com> writes:
== Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 == Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 enum X { A=3, B=1, C }

 void main() {
     foreach(e;X)
         writefln(e.stringof," = ",e);
 }
 //X.A = 3
 //X.B = 1
 //X.C = 2
 or
 //X.B = 1
 //X.C = 2
 //X.A = 3
enum X { A=3, B=1, C } void main( ) { foreach( e; __traits(allMembers, X) ) { writeln( "X.", e, " = ", mixin( "X."~e ) ); } }
D1 :'(
Oh. Without being an expert on D1 matters, I believe that is impossible. I thought there was a struct called defineEnum in phobos1, but it appears I am wrong. However, it should be fairly simple to create one. Untested code, as I do not have D1 installed: struct defineEnum( T... ) { foreach ( i, e; T ) { mixin( "static defineEnum " ~ e ~ " = defineEnum( i );" ); }
I think in D1, the foreach need to be encapsulated in a char[] function().
      static int opApply( int delegate( ref bar ) dg ) {
          int result = 0;
          foreach ( e; T ) {
              mixin( "result = dg( " ~ e ~ " ) );" );
Why is this a mixin?
              if ( result ) {
                  break;
              }
          }
          return result;
      }
 }
The code didn't compile, so I tried fixing it.. and failed as I don't really get what you want it to do (or even how to call it :) Please explain it to me.
Sep 22 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
%u <e ee.com> wrote:

 The code didn't compile, so I tried fixing it.. and failed as I don't  
 really get
 what you want it to do (or even how to call it :)
 Please explain it to me.
Sorry, it was late and I was tired. Updated code (tested, even! :p): module foo; import std.stdio; template defineStaticImpl( T, int value, string name, args... ) { mixin( "static T " ~ name ~ " = cast(T)value; " ); static if ( args.length != 0 ) { mixin defineStaticImpl!( T, value + 1, args ); } } template defineStatic( T, args... ) { mixin defineStaticImpl!( T, 0, args ); } struct defineEnum( T... ) { int value; static const int num = T.length; mixin defineStatic!( typeof( this ), T ); static int opApply( int delegate( ref defineEnum ) dg ) { int result = 0; foreach ( i, e; T ) { result = dg( defineEnum( i ) ); if ( result ) { break; } } return result; } static defineEnum opCall( int value ) { defineEnum tmp; tmp.value = value; return tmp; } string toString( ) { foreach ( i, e; T ) { if ( i == value ) { return e.dup; } } } } void main( ) { alias defineEnum!( "A", "B", "C" ) Bar; foreach ( e; Bar ) { writefln( e ); } } -- Simen
Sep 23 2010
next sibling parent %u <e ee.com> writes:
== Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 The code didn't compile, so I tried fixing it.. and failed as I don't
 really get
 what you want it to do (or even how to call it :)
 Please explain it to me.
Sorry, it was late and I was tired. Updated code (tested, even! :p): module foo; import std.stdio; template defineStaticImpl( T, int value, string name, args... ) { mixin( "static T " ~ name ~ " = cast(T)value; " ); static if ( args.length != 0 ) { mixin defineStaticImpl!( T, value + 1, args ); } } template defineStatic( T, args... ) { mixin defineStaticImpl!( T, 0, args ); } struct defineEnum( T... ) { int value; static const int num = T.length; mixin defineStatic!( typeof( this ), T ); static int opApply( int delegate( ref defineEnum ) dg ) { int result = 0; foreach ( i, e; T ) { result = dg( defineEnum( i ) ); if ( result ) { break; } } return result; } static defineEnum opCall( int value ) { defineEnum tmp; tmp.value = value; return tmp; } string toString( ) { foreach ( i, e; T ) { if ( i == value ) { return e.dup; } } } } void main( ) { alias defineEnum!( "A", "B", "C" ) Bar; foreach ( e; Bar ) { writefln( e ); } }
Thanks!! :) This I can understand.
Sep 23 2010
prev sibling parent reply %u <e ee.com> writes:
== Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 Sorry, it was late and I was tired. Updated code (tested, even! :p):
 module foo;
 import std.stdio;
 template defineStaticImpl( T, int value, string name, args... ) {
 	mixin( "static T " ~ name ~ " = cast(T)value; " );
 	static if ( args.length != 0 ) {
 		mixin defineStaticImpl!( T, value + 1, args );
 	}
 }
 template defineStatic( T, args... ) {
 	mixin defineStaticImpl!( T, 0, args );
 }
 struct defineEnum( T... ) {
 	int value;
 	static const int num = T.length;
 	mixin defineStatic!( typeof( this ), T );
      static int opApply( int delegate( ref defineEnum ) dg ) {
          int result = 0;
          foreach ( i, e; T ) {
              result = dg( defineEnum( i ) );
              if ( result ) {
                  break;
              }
          }
          return result;
      }
 	static defineEnum opCall( int value ) {
 		defineEnum tmp;
 		tmp.value = value;
 		return tmp;
 	}
 	string toString( ) {
 		foreach ( i, e; T ) {
 			if ( i == value ) {
 				return e.dup;
 			}
 		}
 	}
 }
 void main( ) {
 	alias defineEnum!( "A", "B", "C" ) Bar;
 	foreach ( e; Bar ) {
 		writefln( e );
 	}
 }
Okee, that took me a while to wholly get. :) First question, shouldn't the first foreach be replaced by a simple for loop: for(int i = 0; i<num; i++ ) { If I understand it correctly the foreach aggregates are actually string-tuple literals. Then couldn't the second one be CT translated to char[][]? That way the stringOf would be a simple array index. And lastly, I probably need to make the whole struct a string mixin if I want it's type to be like an enum.. don't I? :'(
Sep 23 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
%u <e ee.com> wrote:

 First question, shouldn't the first foreach be replaced by a simple for  
 loop:
 for(int i = 0; i<num; i++ ) {
It certainly could, and that would explain the presence of 'num', but it's not necessary, and should make no difference in the generated executable.
 If I understand it correctly the foreach aggregates are actually  
 string-tuple
 literals.
Yes.
 Then couldn't the second one be CT translated to char[][]?
 That way the stringOf would be a simple array index.
Indeed it could, though I will leave its implementation as an exercise for the reader :p. I also thought up a Duff's device-inspired contraption that works: string toString( ) { switch ( value ) { foreach ( i, e; T ) { case i: return T[i]; } } } This should be as fast as the char[][].
 And lastly, I probably need to make the whole struct a string mixin if I  
 want it's
 type to be like an enum.. don't I? :'(
I'm not sure what you're getting at here. In what way that you don't like it is it enum-unlike? -- Simen
Sep 23 2010
parent reply %u <e ee.com> writes:
== Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 First question, shouldn't the first foreach be replaced by a simple for
 loop:
 for(int i = 0; i<num; i++ ) {
It certainly could, and that would explain the presence of 'num', but it's not necessary, and should make no difference in the generated executable.
 If I understand it correctly the foreach aggregates are actually
 string-tuple
 literals.
Yes.
 Then couldn't the second one be CT translated to char[][]?
 That way the stringOf would be a simple array index.
Indeed it could, though I will leave its implementation as an exercise for the reader :p. I also thought up a Duff's device-inspired contraption that works: string toString( ) { switch ( value ) { foreach ( i, e; T ) { case i: return T[i]; } } } This should be as fast as the char[][].
I thought that would be more annoying to implement(string mixins etc).. didn't know it could be that nice :)
 And lastly, I probably need to make the whole struct a string mixin if I
 want it's
 type to be like an enum.. don't I? :'(
I'm not sure what you're getting at here. In what way that you don't like it is it enum-unlike?
These two have distinctly different outputs ;P alias defineEnum!( "A", "B", "C" ) Bar; writefln( typeof(Bar.A).stringof ); enum Foo { A, B, C } writefln( typeof(Foo.A).stringof ); Won't the compiler even choke on the type size when feeding defineEnum a hundred elements or so?
Sep 23 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
%u <e ee.com> wrote:

 I'm not sure what you're getting at here. In what way that you don't  
 like
 it is it enum-unlike?
These two have distinctly different outputs ;P alias defineEnum!( "A", "B", "C" ) Bar; writefln( typeof(Bar.A).stringof ); enum Foo { A, B, C } writefln( typeof(Foo.A).stringof );
They do. There are ways around that - mostly by using string mixins on this form: template defineEnum( string name, T... ) { string defineEnum = "struct " ~ name ~ " {" // Stuff from other implementation goes here. "}" } mixin( defineEnum!( "EnumName", "A","B","C" ) ); This pattern is one of the reasons I have been lobbying for automatic mixin templates in D2 - it should look only like this: defineEnum!( "EnumName", "A","B","C" )
 Won't the compiler even choke on the type size when feeding defineEnum a  
 hundred
 elements or so?
Types are limited to 64K of memory, I think. That should be enough for 16K elements in this case. If you're thinking of the horribly long names, I believe identifiers are hashed rather than being stored wholesale, once they move past 16K. -- Simen
Sep 23 2010
parent reply %u <e ee.com> writes:
== Quote from Simen kjaeraas (simen.kjaras gmail.com)'s article
 %u <e ee.com> wrote:
 I'm not sure what you're getting at here. In what way that you don't
 like
 it is it enum-unlike?
These two have distinctly different outputs ;P alias defineEnum!( "A", "B", "C" ) Bar; writefln( typeof(Bar.A).stringof ); enum Foo { A, B, C } writefln( typeof(Foo.A).stringof );
They do. There are ways around that - mostly by using string mixins on this form: template defineEnum( string name, T... ) { string defineEnum = "struct " ~ name ~ " {" // Stuff from other implementation goes here. "}" }
Of course! The encapsulation only needs to string mixin the struct signature.
      mixin( defineEnum!( "EnumName", "A","B","C" ) );
 This pattern is one of the reasons I have been lobbying for automatic
 mixin templates in D2 - it should look only like this:
      defineEnum!( "EnumName", "A","B","C" )
Looking more and more like typecons's defineEnum :) though, supporting a non-continues range of values (which I don't need) will be annoying in this setup, I think.. but, I think typecons uses the slow if version..
 Won't the compiler even choke on the type size when feeding defineEnum a
 hundred
 elements or so?
Types are limited to 64K of memory, I think. That should be enough for 16K elements in this case. If you're thinking of the horribly long names, I believe identifiers are hashed rather than being stored wholesale, once they move past 16K.
Good to know. All this makes for a nice freachable D1 defineEnum, thanks!
Sep 23 2010
parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
%u <e ee.com> wrote:

 though, supporting a non-continues range of values (which I don't need)  
 will be
 annoying in this setup, I think..
Impossible in the current version, unless you accept having a bunch of dummy fields. It is not hard to implement: template defineStaticImpl( T, int value, string name ) { // Do as below, no recursion. } template defineStaticImpl( T, int value, string name, string next, args... ) { // Mostly as before. } template defineStaticImpl( T, int value, string name, int actualValue, args... ) { mixin defineStaticImpl!( T, actualValue, name, args ); }
 Won't the compiler even choke on the type size when feeding  
defineEnum a
 hundred
 elements or so?
Types are limited to 64K of memory, I think. That should be enough for 16K elements in this case. If you're thinking of the horribly long names, I believe identifiers are hashed rather than being stored wholesale, once they move past 16K.
Good to know. All this makes for a nice freachable D1 defineEnum, thanks!
My pleasure. Was a fun challenge. -- Simen
Sep 23 2010
prev sibling parent Tomek =?UTF-8?B?U293acWEc2tp?= <just ask.me> writes:
Simen kjaeraas napisaƂ:

 enum X { A=3, B=1, C }
 
 void main( ) {
 foreach( e;  __traits(allMembers, X) ) {
 writeln( "X.", e, " = ", mixin( "X."~e ) );
 }
 }
mixin("X."~e) => __traits(getMember, X, e) For mixin-allergics. -- Tomek
Oct 05 2010