www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - constructing labels for static foreach inside switch inside foreach

reply Steven Schveighoffer <schveiguy gmail.com> writes:
OK, so I have a situation where I'm foreaching over a compile-time list 
of types. Inside the loop, I'm using a second loop over a set of input.

Inside that loop, I'm using a switch on the input, and inside the 
switch, I'm foreaching over the type's members, to construct a switch 
that can handle member names (this is for serialization).

If I encounter a certain name, then I want to break out of the inner 
loop (it's a while loop)

So naturally, I have to use break statements with labels like:

innerloop:
while(haveMoreData)
    switchstmt:
    switch(nextDataElement) {
       static foreach(name; __traits(allMembers, T)) {
       case name:
          ... // handle it
          break switchstmt;
       }
       case "STOP":
          break innerloop;
    }

Seems simple enough, except that this inner portion is unrolled, and if 
I have more than one type to run this on, I already have an "innerloop" 
label defined.

Is there a way to define a label using a mixin or something? or do I 
have to wrap this in a function?

Is there another way to approach this?

-Steve
Jul 07 2020
next sibling parent bauss <jj_1337 live.dk> writes:
On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer 
wrote:
 OK, so I have a situation where I'm foreaching over a 
 compile-time list of types. Inside the loop, I'm using a second 
 loop over a set of input.

 Inside that loop, I'm using a switch on the input, and inside 
 the switch, I'm foreaching over the type's members, to 
 construct a switch that can handle member names (this is for 
 serialization).

 If I encounter a certain name, then I want to break out of the 
 inner loop (it's a while loop)

 So naturally, I have to use break statements with labels like:

 innerloop:
 while(haveMoreData)
    switchstmt:
    switch(nextDataElement) {
       static foreach(name; __traits(allMembers, T)) {
       case name:
          ... // handle it
          break switchstmt;
       }
       case "STOP":
          break innerloop;
    }

 Seems simple enough, except that this inner portion is 
 unrolled, and if I have more than one type to run this on, I 
 already have an "innerloop" label defined.

 Is there a way to define a label using a mixin or something? or 
 do I have to wrap this in a function?

 Is there another way to approach this?

 -Steve
Unfortunately mixin does not support labels so I don't think you can do what you want to do. Kind of surprised me tbh
Jul 07 2020
prev sibling next sibling parent reply cc <cc nevernet.com> writes:
On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer 
wrote:
 OK, so I have a situation where I'm foreaching over a 
 compile-time list of types. Inside the loop, I'm using a second 
 loop over a set of input.

 Inside that loop, I'm using a switch on the input, and inside 
 the switch, I'm foreaching over the type's members, to 
 construct a switch that can handle member names (this is for 
 serialization).

 If I encounter a certain name, then I want to break out of the 
 inner loop (it's a while loop)

 So naturally, I have to use break statements with labels like:

 innerloop:
 while(haveMoreData)
    switchstmt:
    switch(nextDataElement) {
       static foreach(name; __traits(allMembers, T)) {
       case name:
          ... // handle it
          break switchstmt;
       }
       case "STOP":
          break innerloop;
    }

 Seems simple enough, except that this inner portion is 
 unrolled, and if I have more than one type to run this on, I 
 already have an "innerloop" label defined.

 Is there a way to define a label using a mixin or something? or 
 do I have to wrap this in a function?

 Is there another way to approach this?

 -Steve
I think I ran into similar problems due to the requirement to use a labeled break inside static foreach. I got around it by defining enums when my target was found and checking if it existed via __traits(compiles) to "ignore" the rest of the loop. Sorry if I got what you're trying to accomplish wrong or this is too ugly: class Foo { (RPC) bar(int x, float f, string s) { // ... } } class Remoter(T) { void opDispatch(string s, SA...)(SA sargs) { alias A = getSymbolsByUDA!(T, RPC); static foreach (idx, FUNC; A) { static if (!__traits(compiles, FOUND) && hasUDA!(FUNC, RPC) && FUNCNAME!FUNC == s && SA.length == (Parameters!FUNC).length) { version(CheckImplicitlyConvertibleArgs) { static foreach (argi; 0 .. SA.length) { static if (!__traits(compiles, mixin(format("MISMATCH_%d", idx)))) { static if (isImplicitlyConvertible!(SA[argi], (Parameters!FUNC)[argi])) { //pragma(msg, format("implc ok: %s => %s", SA[argi].stringof, (Parameters!FUNC)[argi].stringof)); // Parameter Ok } else { pragma(msg, format("RPC argument[%s] of %s is not implicitly convertible: %s => %s", argi, FUNCNAME!FUNC, SA[argi].stringof, (Parameters!FUNC)[argi].stringof)); mixin(`enum bool `~format("MISMATCH_%d", idx)~` = true;`); } } } static if (!__traits(compiles, mixin(format("MISMATCH_%d", idx)))) { enum FOUND = idx; //pragma(msg, format("and we found: %s", FOUND)); } } else { enum FOUND = idx; } } } static if (__traits(compiles, FOUND)) { alias FUNC = A[FOUND]; // generate a packet to transmit that corresponds to RPC function call } else { static assert(0, format("No matching function found for %s%s", s, SA.stringof)); } } } Remoter!foo remote; remote.bar(4, 3.14f, "hello"); // succeeds remote.bar("hi", 12); // static assert fail
Jul 08 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/8/20 5:10 AM, cc wrote:
 
 I think I ran into similar problems due to the requirement to use a 
 labeled break inside static foreach.  I got around it by defining enums 
 when my target was found and checking if it existed via 
 __traits(compiles) to "ignore" the rest of the loop.
Thanks for the suggestion. I've used that trick too, but in this case, I still have a problem with the switch label as well (I need to use labeled breaks inside the static foreach that generates case clauses). And in this case, the loop I'm breaking is NOT a static loop, it's a regular while loop. And I don't want to ignore the rest of the static loop. -Steve
Jul 08 2020
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer 
wrote:

 Seems simple enough, except that this inner portion is 
 unrolled, and if I have more than one type to run this on, I 
 already have an "innerloop" label defined.

 Is there a way to define a label using a mixin or something? or 
 do I have to wrap this in a function?

 Is there another way to approach this?
Can't you put a single label after your outer foreach and goto it?
Jul 08 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/8/20 6:13 AM, Stanislav Blinov wrote:
 On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer wrote:
 
 Seems simple enough, except that this inner portion is unrolled, and 
 if I have more than one type to run this on, I already have an 
 "innerloop" label defined.

 Is there a way to define a label using a mixin or something? or do I 
 have to wrap this in a function?

 Is there another way to approach this?
Can't you put a single label after your outer foreach and goto it?
There is potentially code after the while loop that needs to run, but I could move that code somewhere else. However it still won't work, because static foreach requires a label for break. So if I fix the loop problem, I will still have a label problem, because I need to label the switch and use labeled breaks on that. This is really an issue with: a) static foreach-ing case clauses requires a labeled break. b) static foreach (or foreach on a tuple) unrolls all the code inside, including labels c) labels have to be unique within the function. I solved it for now by extrapolating the inner code into a local template function. But this is definitely an awkward situation for static foreach. I was hoping I could use mixins or something to make new label names, but it appears I cannot (without mixing in the entire loop contents). -Steve
Jul 08 2020
parent reply ag0aep6g <anonymous example.com> writes:
On 08.07.20 14:24, Steven Schveighoffer wrote:
 I solved it for now by extrapolating the inner code into a local 
 template function. But this is definitely an awkward situation for 
 static foreach.
FWIW, you can write the extra function like this: static foreach (T; Types) () { innerloop: while (haveMoreData) { ... break innerloop; ... } } ();
Jul 08 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/8/20 9:38 AM, ag0aep6g wrote:
 On 08.07.20 14:24, Steven Schveighoffer wrote:
 I solved it for now by extrapolating the inner code into a local 
 template function. But this is definitely an awkward situation for 
 static foreach.
FWIW, you can write the extra function like this:     static foreach (T; Types)     () {         innerloop: while (haveMoreData)         {             ...             break innerloop;             ...         }     } ();
Ooh, that's a good idea. That avoids having to declare a template function before the loop (I can't declare it inside because, then multiple functions of the same name would exist lol). Works like a charm, thanks! -Steve
Jul 08 2020