Re: Variadic template parameters, refactor a long chain of static if's to 'functions'.

2019-06-28 Thread realhet via Digitalmars-d-learn

On Tuesday, 11 June 2019 at 13:22:26 UTC, Adam D. Ruppe wrote:

On Tuesday, 11 June 2019 at 09:26:56 UTC, realhet wrote:

  static bool processId(bool captureIntId, alias r, alias a)(){
mixin("alias ta = typeof("~a.stringof~");");


As I have been saying a lot, mixin and stringof should almost 
never be used together. You could write this a lot easier:

...


Thank you for the long example, it helped me a lot!

The thing is now capable of:

- getting a specific type of parameter -> 
args.paramByType!(string[int]).writeln;


- including wrapper structs. In that case, optionally can fall 
back to the type inside the struct.


- handle and call events (structs or fallback as well)

- It is super easy now to make a function that can process a 
specific set of events:

struct onClick  { void delegate() val; }
...
struct onHold   { void delegate() val; }

void processBtnEvents(T...)(bool click, bool state, bool chg, 
T args){
  if(click) args.paramCall!(onClick, true/*fallback to pure 
delegate*/);

  if(state) args.paramCall!onHold;
  if(chg){
args.paramCall!onChange;
if(state) args.paramCall!onPress;
 else args.paramCall!onRelease;
  }
}

- Also I've found a way to exchange state values (for example a 
bool for a CheckBox control):

  - I can give it a pointer to a bool
  - Or I can give a getter and 0 or more setter(s): bool 
delegate(), void delegate(bool)

  - Can be functionPointers too, not just delegates.
  - example:
void fIncrementer(T...)(T args){
  paramGetterType!T x;
  args.paramGetter(x);
  x = (x + 1).to!(paramGetterType!T);
  args.paramSetter(x);
}
  - it is letting me use enumerated types too -> I will not have 
to write anything, and there will be an automatic 
RadioButtonGroup on the screen, just bu mentioning that variable. 
It will be awesome!


- Sorry for the lot of string processing and some mixin()s :D At 
the end of the code below, I've learned a lot while being able to 
write nicer code.


Thank you for your example code, I've learned a lot from it.

--
private{
  bool is2(A, B)() { return is(immutable(A)==immutable(B)); }

  bool isBool  (A)(){ return is2!(A, bool  ); }
  bool isInt   (A)(){ return is2!(A, int   ) || is2!(A, uint  ); }
  bool isFloat (A)(){ return is2!(A, float ) || is2!(A, double); }
  bool isString(A)(){ return is2!(A, string); }

  bool isSimple(A)(){ return isBool!A || isInt!A || isFloat!A || 
isString!A; }


  bool isGetter(A, T)(){
enum a = A.stringof, t = T.stringof;
return a.startsWith(t~" delegate()")
|| a.startsWith(t~" function()");
  }
  bool isSetter(A, T)(){
enum a = A.stringof, t = T.stringof;
return a.startsWith("void delegate("~t~" ")
|| a.startsWith("void function("~t~" ");
  }
  bool isEvent(A)(){ return isGetter!(A, void); } //event = void 
getter


  bool isCompatible(TDst, TSrc, bool compiles, bool 
compilesDelegate)(){

return (isBool  !TDst && isBool  !TSrc)
|| (isInt   !TDst && isInt   !TSrc)
|| (isFloat !TDst && isFloat !TSrc)
|| (isString!TDst && isString!TSrc)
|| !isSimple!TDst && (compiles || compilesDelegate); 
//assignment is working. This is the last priority

  }
}

auto paramByType(Tp, bool fallback=false, T...)(T args){
  Tp res;

  enum isWrapperStruct = __traits(hasMember, Tp, "val") && 
Fields!Tp.length==1; //is it encapsulated in a wrapper struct?  
-> struct{ type val; }


  enum checkDuplicatedParams = q{
static assert(!__traits(compiles, duplicated_parameter), 
"Duplicated parameter type: %s%s".format(Tp.stringof, fallback ? 
"("~typeof(Tp.val).stringof~")" : ""));

enum duplicated_parameter = 1;
  };

  static foreach_reverse(idx, t; T){
//check simple types/structs
static if(isCompatible!(typeof(res), t, __traits(compiles, 
res = args[idx]), __traits(compiles, res = 
args[idx].toDelegate))){
  static if(__traits(compiles, res = args[idx]))   
res = args[idx];else res = args[idx].toDelegate;

  mixin(checkDuplicatedParams);
}else
//check fallback struct.val
static if(fallback && isWrapperStruct && 
isCompatible!(typeof(res.val), t, __traits(compiles, res.val = 
args[idx]), __traits(compiles, res.val = args[idx].toDelegate))){
  static if(__traits(compiles, res.val = args[idx]))  
res.val = args[idx];  
  else res.val = args[idx].toDelegate;

  mixin(checkDuplicatedParams);
}
  }

  static if(isWrapperStruct) return res.val;
else return res;
}

void paramCall(Tp, bool fallback=false, T...)(T args){
  auto e = paramByType!(Tp, fallback)(args);
  static assert(isEvent!(typeof(e)), "paramCallEvent() error: %s 
is not an event.".format(Tp.stringof));

  if(e !is null) e();
}

template paramGetterType(T...){
  static foreach(t; T){
static 

Re: Variadic template parameters, refactor a long chain of static if's to 'functions'.

2019-06-11 Thread Adam D. Ruppe via Digitalmars-d-learn

On Tuesday, 11 June 2019 at 09:26:56 UTC, realhet wrote:

  static bool processId(bool captureIntId, alias r, alias a)(){
mixin("alias ta = typeof("~a.stringof~");");


As I have been saying a lot, mixin and stringof should almost 
never be used together. You could write this a lot easier:


alias ta = typeof(a);

no need for mixin at all.


Error: template instance processId!(true, id, _param_1) 
processId!(true, id, _param_1) is nested in both Args and btn


So Args is a runtime thing, but you are trying to use it in 
compile time. The compiler can handle one layer of this - it 
basically inlines a runtime function when you do that - but with 
more layers it gets lost.


What you'll need to do is to kinda embrace this and have a helper 
struct that returns the stuff by value. To avoid holding all the 
possible types, pass what you want to it as type arguments inside 
the function.


Check this out:


---

struct ID { int val; }
struct enabled { bool val; }
struct disabled { bool val; }

struct PossibleArguments(T...) {

this(Args...)(Args args) {
static foreach(arg; args) {{
enum idx = TindexOf!(typeof(arg));
static if(idx >= 0)
contents[idx] = arg;
else
static assert(0, "Unusable arg " 
~ typeof(arg).stringof);

}}
}

private T contents;
private static int TindexOf(What)() {
static foreach(idx, t; T) {
// you could use your isSame here
static if(is(t == What))
return cast(int) idx;
}
return -1;
}

auto opDispatch(string n)() {
static foreach(idx, item; T)
if(item.stringof == n)
return contents[idx].val;
assert(0);
}
}

void btn(T...)(string params, T args) {
 // here's the usage: list args I want to support as CT,
 // then pass the other args as runtime
auto r = PossibleArguments!(
ID,
enabled
)(args);

import std.stdio;
writeln(r.opDispatch!"ID"); // or r.ID, but while 
debugging it helps to explicitly all r.opDispatch so you get the 
full error instead of "no such property"

writeln(r.enabled);
}


void main() {
// I enabled the first two, but not disabled, so this is 
an error

//btn("ignored", ID(5), enabled(true), disabled(false));

// but this works
btn("ignored", ID(5), enabled(true));

// and it can be reordered/ignored/etc
btn("ignored", enabled(false));
}

---



So now you avoid the list of ifs thanks to that TindexOf helper 
thing while still getting the helpful user error message, and the 
opDispatch can make feel like you are accessing by name inside.


Extending it to other types is an exercise for you :) 
Particularly, the event ones will need a different approach of 
some sort.


I would suggest actually putting them in a wrapper struct so you 
can  still use this cool name trick.


But alternatively, you could special-case them in the two loops, 
like always knowing void delegate() is going to be named onClick. 
I can help you solve this later too if you wanna go that way, I 
just g2g right now lol.


Variadic template parameters, refactor a long chain of static if's to 'functions'.

2019-06-11 Thread realhet via Digitalmars-d-learn

Hi again,

I'm trying to do variadic parameter processing, and I have the 
following function that works fine:


  static bool same(T1, T2)(){
pragma(msg, "same? "~T1.stringof~" "~T2.stringof);
return is(immutable(T1)==immutable(T2));
  }

  Btn btn(T...)(string params, T args){
enum captureIntID = true,
 captureBoolEnabled = true,
 captureFunct = true;

Args r; //Arg is a struct to store all the possible 
parameters in runtime

static foreach(a; args){
  //process id parameter
   static if(same!(typeof(a), id)) r.id = a.val;
  else static if(captureIntID && (same!(typeof(a), int) || 
same!(typeof(a), uint))) r.id = a;


  //process enabled/disabled
  else static if(same!(typeof(a), enabled )) r.enabled = 
a.val;
  else static if(same!(typeof(a), disabled)) r.enabled = 
!a.val;
  else static if(captureBoolEnabled && same!(typeof(a), bool) 
) r.enabled = a;


  //process data events
  else static if(same!(typeof(a), onClick  )) 
r.events.onClick   = a.f;
  else static if(same!(typeof(a), onPress  )) 
r.events.onPress   = a.f;
  else static if(same!(typeof(a), onRelease)) 
r.events.onRelease = a.f;
  else static if(same!(typeof(a), onChange )) 
r.events.onChange  = a.f;
  else static if(same!(typeof(a), onTrue   )) r.events.onTrue 
   = a.f;
  else static if(same!(typeof(a), onFalse  )) 
r.events.onFalse   = a.f;
  else static if(same!(typeof(a), onBool   )) r.events.onBool 
   = a.f;
  else static if(typeof(a).stringof.startsWith("void 
delegate()")) r.events.onClick = a;
  else static if(typeof(a).stringof.startsWith("void 
delegate(bool)")) r.events.onBool = a;


  else static assert(false, "Unsupported type 
"~typeof(a).stringof);

}

return new Btn(params, r.id, r.enabled, r.events);
  }


The long chain of is's are required to be able to show the error 
message at the end when an unhandled parameter type is found.


I will have more of these and want to reuse these ifs in other 
functions as well, so I decided to take out the first 2 if's and 
put it into a template function:


  static bool processId(bool captureIntId, alias r, alias a)(){
mixin("alias ta = typeof("~a.stringof~");");
pragma(msg, "ta "~ta.stringof);
 static if(same!(ta, id)) { r = a.val; return true; }
else static if(captureIntId && (same!(ta, int) || same!(ta, 
uint))) { r = a; return true; }

else return false;
  }

later I call it with:

  static if(processId!(true, r.id, a)){}
  else static if(...

'a' is the variadic foreach variable (_param_1 and so on),
'r.id' is the result field from an Arg structure.
Both 'a' and 'r.id' are existing and compiling, also the pragma 
messages are good, I see it can find the right types, but I have 
the following error for every variadic parameter:


Error: template instance processId!(true, id, _param_1) 
processId!(true, id, _param_1) is nested in both Args and btn


id is a struct. And also a field in the Args struct. I changed it 
to id1 in the Args struct ant the error remains the same.
Everything resides in the scope of a class called 
ContainerBuilder.


Is there a way to do this elegantly?
Maybe if I put everything in a very large chain of if's and 
enable the required parameters with a set of flags, but that's 
not structured well, and also needs the biggest possible set of 
runtime parameter storage to store the processed parametest.


Here's an example using the above function:
btn(`Yes flex=1`, id(54231), enabled(true), { lastClickedBtn = 
"Yes"; hehe = true; })

checkbox("Checkbox_1", 12345432, (bool b){ hehe = b; })

I will have a lot of controls and a lot of parameter types. I 
wanna do something like in the old VisualBasic, where you can 
skip a lot of default parameters, and also access the only few 
you need by name. Something like this: btn("caption", 
hint:"blabla", icon:"icon.ico"), but as I currently know this is 
not implemented in D.


Thank You in advance!