digitalmars.D.learn - constructing labels for static foreach inside switch inside foreach
- Steven Schveighoffer (27/27) Jul 07 2020 OK, so I have a situation where I'm foreaching over a compile-time list
- bauss (5/34) Jul 07 2020 Unfortunately mixin does not support labels so I don't think you
- cc (59/88) Jul 08 2020 I think I ran into similar problems due to the requirement to use
- Steven Schveighoffer (7/12) Jul 08 2020 Thanks for the suggestion. I've used that trick too, but in this case, I...
- Stanislav Blinov (3/9) Jul 08 2020 Can't you put a single label after your outer foreach and goto it?
- Steven Schveighoffer (17/29) Jul 08 2020 There is potentially code after the while loop that needs to run, but I
- ag0aep6g (11/14) Jul 08 2020 FWIW, you can write the extra function like this:
- Steven Schveighoffer (6/22) Jul 08 2020 Ooh, that's a good idea. That avoids having to declare a template
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
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? -SteveUnfortunately 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
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? -SteveI 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
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
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
On 7/8/20 6:13 AM, Stanislav Blinov wrote:On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer wrote: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). -SteveSeems 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
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
On 7/8/20 9:38 AM, ag0aep6g wrote:On 08.07.20 14:24, Steven Schveighoffer wrote: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! -SteveI 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