www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How can i increase max number recursive template expansions?

reply "QAston" <qaston gmail.com> writes:
I have a large enum in my code (opcodes for a protocol) - using 
std.traits.EnumMembers gives me a recursive template error.

How can i increase max number recursive template expansions?
Jul 07 2013
next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 7 July 2013 at 19:55:26 UTC, QAston wrote:
 I have a large enum in my code (opcodes for a protocol) - using 
 std.traits.EnumMembers gives me a recursive template error.

 How can i increase max number recursive template expansions?
I don't think you can. Please file a bug report: even though it might not get fixed any time soon (other than maybe just upping the threshold), there is talk of enabling more imperative-style programming in templates at the moment, and this would be a good case for it. Try this as a workaround for now: import std.typetuple; template EnumMembersLarge(E) if (is(E == enum)) { // Supply the specified identifier to an constant value. template WithIdentifier(string ident) { static if (ident == "Symbolize") { template Symbolize(alias value) { enum Symbolize = value; } } else { mixin("template Symbolize(alias "~ ident ~")" ~"{" ~"alias "~ ident ~" Symbolize;" ~"}"); } } template EnumSpecificMembers(names...) { static if (names.length > 0) { alias TypeTuple!( WithIdentifier!(names[0]) .Symbolize!(__traits(getMember, E, names[0])), EnumSpecificMembers!(names[1 .. $]) ) EnumSpecificMembers; } else { alias TypeTuple!() EnumSpecificMembers; } } alias TypeTuple!(EnumSpecificMembers!(__traits(allMembers, E)[0..$/2]), EnumSpecificMembers!(__traits(allMembers, E)[$/2..$]) EnumMembersLarge; } All except the last alias line and the changed name is just copied and pasted from EnumMembers. As you can see we're doing the recursive template stuff in 2 sections and then splicing them together, halving the recursion depth. The result is exactly equivalent to EnumMembers. If your enum is really huge you could split it up in to thirds or quarters, or even generate the split automatically with a template.
Jul 07 2013
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 07/07/2013 01:22 PM, John Colvin wrote:
 On Sunday, 7 July 2013 at 19:55:26 UTC, QAston wrote:
 I have a large enum in my code (opcodes for a protocol) - using
 std.traits.EnumMembers gives me a recursive template error.

 How can i increase max number recursive template expansions?
I don't think you can. Please file a bug report: even though it might not get fixed any time soon (other than maybe just upping the threshold), there is talk of enabling more imperative-style programming in templates at the moment, and this would be a good case for it.
or feel free to commandeer this one http://d.puremagic.com/issues/show_bug.cgi?id=6471
Jul 10 2013
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-07-07, 21:55, QAston wrote:

 I have a large enum in my code (opcodes for a protocol) - using  
 std.traits.EnumMembers gives me a recursive template error.

 How can i increase max number recursive template expansions?
You can't. However, you can amend std.traits.EnumMembers to work with larger enums by using this version: import std.typetuple; template EnumMembers(E) if (is(E == enum)) { // Supply the specified identifier to an constant value. template WithIdentifier(string ident) { static if (ident == "Symbolize") { template Symbolize(alias value) { enum Symbolize = value; } } else { mixin("template Symbolize(alias "~ ident ~")" ~"{" ~"alias "~ ident ~" Symbolize;" ~"}"); } } template EnumSpecificMembers(names...) { static if (names.length > 200) { alias TypeTuple!( EnumSpecificMembers!(names[0..$/2]), EnumSpecificMembers!(names[$/2..$]), ) EnumSpecificMembers; } else static if (names.length > 0) { alias TypeTuple!( WithIdentifier!(names[0]) .Symbolize!(__traits(getMember, E, names[0])), EnumSpecificMembers!(names[1 .. $]), ) EnumSpecificMembers; } else { alias TypeTuple!() EnumSpecificMembers; } } alias EnumSpecificMembers!(__traits(allMembers, E)) EnumMembers; } Here, this line: static if (names.length > 200) uses divide-and-conquer to reduce the number of template instantiations. -- Simen
Jul 07 2013
next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 7 July 2013 at 20:22:59 UTC, Simen Kjaeraas wrote:
 On 2013-07-07, 21:55, QAston wrote:

 I have a large enum in my code (opcodes for a protocol) - 
 using std.traits.EnumMembers gives me a recursive template 
 error.

 How can i increase max number recursive template expansions?
You can't. However, you can amend std.traits.EnumMembers to work with larger enums by using this version: import std.typetuple; template EnumMembers(E) if (is(E == enum)) { // Supply the specified identifier to an constant value. template WithIdentifier(string ident) { static if (ident == "Symbolize") { template Symbolize(alias value) { enum Symbolize = value; } } else { mixin("template Symbolize(alias "~ ident ~")" ~"{" ~"alias "~ ident ~" Symbolize;" ~"}"); } } template EnumSpecificMembers(names...) { static if (names.length > 200) { alias TypeTuple!( EnumSpecificMembers!(names[0..$/2]), EnumSpecificMembers!(names[$/2..$]), ) EnumSpecificMembers; } else static if (names.length > 0) { alias TypeTuple!( WithIdentifier!(names[0]) .Symbolize!(__traits(getMember, E, names[0])), EnumSpecificMembers!(names[1 .. $]), ) EnumSpecificMembers; } else { alias TypeTuple!() EnumSpecificMembers; } } alias EnumSpecificMembers!(__traits(allMembers, E)) EnumMembers; } Here, this line: static if (names.length > 200) uses divide-and-conquer to reduce the number of template instantiations.
We came up with almost identical solutions, posted within 19 seconds of each other!
Jul 07 2013
next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-07-07, 22:28, John Colvin wrote:

 We came up with almost identical solutions, posted within 19 seconds of  
 each other!
Sorta. Mine does repeated halving, and makes DMD run out of memory with 16384 enum members. Yours balks at an enum of > about 1000 elements. -- Simen
Jul 07 2013
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 7 July 2013 at 20:41:17 UTC, Simen Kjaeraas wrote:
 On 2013-07-07, 22:28, John Colvin wrote:

 We came up with almost identical solutions, posted within 19 
 seconds of each other!
Sorta. Mine does repeated halving, and makes DMD run out of memory with 16384 enum members. Yours balks at an enum of > about 1000 elements.
so it does. Yup, yours is betters.
Jul 07 2013
prev sibling parent "QAston" <qaston gmail.com> writes:
On Sunday, 7 July 2013 at 20:28:12 UTC, John Colvin wrote:
 On Sunday, 7 July 2013 at 20:22:59 UTC, Simen Kjaeraas wrote:
 On 2013-07-07, 21:55, QAston wrote:

 I have a large enum in my code (opcodes for a protocol) - 
 using std.traits.EnumMembers gives me a recursive template 
 error.

 How can i increase max number recursive template expansions?
You can't. However, you can amend std.traits.EnumMembers to work with larger enums by using this version: import std.typetuple; template EnumMembers(E) if (is(E == enum)) { // Supply the specified identifier to an constant value. template WithIdentifier(string ident) { static if (ident == "Symbolize") { template Symbolize(alias value) { enum Symbolize = value; } } else { mixin("template Symbolize(alias "~ ident ~")" ~"{" ~"alias "~ ident ~" Symbolize;" ~"}"); } } template EnumSpecificMembers(names...) { static if (names.length > 200) { alias TypeTuple!( EnumSpecificMembers!(names[0..$/2]), EnumSpecificMembers!(names[$/2..$]), ) EnumSpecificMembers; } else static if (names.length > 0) { alias TypeTuple!( WithIdentifier!(names[0]) .Symbolize!(__traits(getMember, E, names[0])), EnumSpecificMembers!(names[1 .. $]), ) EnumSpecificMembers; } else { alias TypeTuple!() EnumSpecificMembers; } } alias EnumSpecificMembers!(__traits(allMembers, E)) EnumMembers; } Here, this line: static if (names.length > 200) uses divide-and-conquer to reduce the number of template instantiations.
We came up with almost identical solutions, posted within 19 seconds of each other!
Thanks guys, you're awesome!
Jul 07 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Simen Kjaeraas:

 However, you can amend std.traits.EnumMembers to work
 with larger enums by using this version:
Worth putting in Phobos? Bye, bearophile
Jul 08 2013
next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 8 July 2013 at 09:03:24 UTC, bearophile wrote:
 Simen Kjaeraas:

 However, you can amend std.traits.EnumMembers to work
 with larger enums by using this version:
Worth putting in Phobos? Bye, bearophile
I reckon so. It's rare to have such huge structs or classes that this sort of this becomes a problem for them, but massive enums are reasonably common.
Jul 08 2013
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-07-08, 11:03, bearophile wrote:

 Simen Kjaeraas:

 However, you can amend std.traits.EnumMembers to work
 with larger enums by using this version:
Worth putting in Phobos?
Filed: http://d.puremagic.com/issues/show_bug.cgi?id=10569 And created a pull request: https://github.com/D-Programming-Language/phobos/pull/1400 -- Simen
Jul 08 2013