www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Merging two named Tuples

reply Edwin van Leeuwen <edder tkwsping.nl> writes:
I am trying to write a function to merge two named structs, but 
am completely stuck on how to do that and was wondering if anyone 
good provide any help. I know I can access the different names 
with tup.fieldNames, but basically can't work out how to use that 
to build the new return type. Below is an outline of what I am 
trying to do (with unittest). Any pointers would be greatly 
appreciated.


/++
Merge two Aes structs

If it has similar named types, then it uses the second one.

Returns a new struct, with combined types.
+/
import std.typecons : Tuple;
template merge(T, U)
{
     auto merge( T base, U other )
     {
         // Go over other.fieldNames and collect them for new tuple
         // Go over base.fieldNames, ignoring the ones that other 
has as well
         // Build newTuple
         return newTuple;
     }
}

///
unittest
{
     auto xs = ["a","b"];
     auto ys = ["c","d"];
     auto labels = ["e","f"];
     auto aes = Tuple!(string[], "x", string[], "y", string[], 
"label")(
             xs, ys, labels );

     auto nlAes = merge( aes, Tuple!(double[], "x",
                 double[], "y" )(
                 [0,1], [3,4] ) );

     assertEqual( nlAes.x[0], 0 );
     assertEqual( nlAes.label.front, "e" );
}
Oct 24 2015
parent reply Edwin van Leeuwen <edder tkwsping.nl> writes:
On Saturday, 24 October 2015 at 11:04:14 UTC, Edwin van Leeuwen 
wrote:
 I am trying to write a function to merge two named structs, but 
 am completely stuck on how to do that and was wondering if 
 anyone good provide any help. I know I can access the different 
 names with tup.fieldNames, but basically can't work out how to 
 use that to build the new return type. Below is an outline of 
 what I am trying to do (with unittest). Any pointers would be 
 greatly appreciated.
I tried the following, but get a compile error: source/ggplotd/aes.d(633): Error: variable tup cannot be read at compile time source/ggplotd/aes.d(633): Error: argument to mixin must be a string, not (__error) source/ggplotd/aes.d(646): Error: template instance ggplotd.aes.merge!(Tuple!(string[], "x", string[], "y", string[], "label"), Tuple!(double[], "x", double[], "y")) error instantiating import std.typecons : Tuple; template merge(T, U) { auto merge( T base, U other ) { string typing = "Tuple!("; string variables = "("; foreach( i, t; other.fieldNames ) { typing ~= other.Types[i].stringof ~ ",\"" ~ t ~ "\","; variables ~= "other." ~ t ~ ","; } foreach( i, t; base.fieldNames ) { bool contains = false; foreach( _, t2; other.fieldNames ) { if (t==t2) contains = true; } if (!contains) { typing ~= base.Types[i].stringof ~ ",\"" ~ t ~ "\","; variables ~= "base." ~ t ~ ","; } } string tup = typing[0..$-1] ~ ")" ~ variables[0..$-1] ~ ");"; // Do some clever CTFE return mixin(tup); } } /// unittest { auto xs = ["a","b"]; auto ys = ["c","d"]; auto labels = ["e","f"]; auto aes = Tuple!(string[], "x", string[], "y", string[], "label")( xs, ys, labels ); auto nlAes = merge( aes, Tuple!(double[], "x", double[], "y" )( [0,1], [3,4] ) ); assertEqual( nlAes.x[0], 0 ); assertEqual( nlAes.label.front, "e" ); } I guess fieldNames does not exist at compile time? Can I get the fieldNames etc at compile time? Cheers, Edwin
Oct 29 2015
parent reply anonymous <anonymous example.com> writes:
On 29.10.2015 19:59, Edwin van Leeuwen wrote:
 On Saturday, 24 October 2015 at 11:04:14 UTC, Edwin van Leeuwen wrote:
 I am trying to write a function to merge two named structs, but am
 completely stuck on how to do that and was wondering if anyone good
 provide any help. I know I can access the different names with
 tup.fieldNames, but basically can't work out how to use that to build
 the new return type. Below is an outline of what I am trying to do
 (with unittest). Any pointers would be greatly appreciated.
I tried the following, but get a compile error: source/ggplotd/aes.d(633): Error: variable tup cannot be read at compile time source/ggplotd/aes.d(633): Error: argument to mixin must be a string, not (__error) source/ggplotd/aes.d(646): Error: template instance ggplotd.aes.merge!(Tuple!(string[], "x", string[], "y", string[], "label"), Tuple!(double[], "x", double[], "y")) error instantiating import std.typecons : Tuple; template merge(T, U) { auto merge( T base, U other ) { string typing = "Tuple!("; string variables = "("; foreach( i, t; other.fieldNames ) { typing ~= other.Types[i].stringof ~ ",\"" ~ t ~ "\","; variables ~= "other." ~ t ~ ","; } foreach( i, t; base.fieldNames ) { bool contains = false; foreach( _, t2; other.fieldNames ) { if (t==t2) contains = true; } if (!contains) { typing ~= base.Types[i].stringof ~ ",\"" ~ t ~ "\","; variables ~= "base." ~ t ~ ","; } } string tup = typing[0..$-1] ~ ")" ~ variables[0..$-1] ~ ");"; // Do some clever CTFE return mixin(tup); } } /// unittest { auto xs = ["a","b"]; auto ys = ["c","d"]; auto labels = ["e","f"]; auto aes = Tuple!(string[], "x", string[], "y", string[], "label")( xs, ys, labels ); auto nlAes = merge( aes, Tuple!(double[], "x", double[], "y" )( [0,1], [3,4] ) ); assertEqual( nlAes.x[0], 0 ); assertEqual( nlAes.label.front, "e" ); } I guess fieldNames does not exist at compile time? Can I get the fieldNames etc at compile time? Cheers, Edwin
`tup` is an ordinary (run time, dynamic) string to the type system. You can't mixin those. You can only mixin static values (enum, static immutable, CTFE results). The code you're generating doesn't depend on `base` and `other`. All it needs are `T` and `U`. So, you can generate the code from the types and mix it into a function that takes `T base, U other`: ---- template merge(T, U) { auto generateCode() { string typing = "Tuple!("; string variables = "("; foreach( i, t; U.fieldNames ) { typing ~= U.Types[i].stringof ~ ",\"" ~ t ~ "\","; variables ~= "other." ~ t ~ ","; } foreach( i, t; T.fieldNames ) { bool contains = false; foreach( _, t2; U.fieldNames ) { if (t==t2) contains = true; } if (!contains) { typing ~= T.Types[i].stringof ~ ",\"" ~ t ~ "\","; variables ~= "base." ~ t ~ ","; } } return "return " ~ typing[0..$-1] ~ ")" ~ variables[0..$-1] ~ ");"; } auto merge(T base, U other) { mixin(generateCode()); } } ----
Oct 29 2015
parent Edwin van Leeuwen <edder tkwsping.nl> writes:
On Thursday, 29 October 2015 at 19:42:10 UTC, anonymous wrote:
 `tup` is an ordinary (run time, dynamic) string to the type 
 system. You can't mixin those. You can only mixin static values 
 (enum, static immutable, CTFE results).

 The code you're generating doesn't depend on `base` and 
 `other`. All it needs are `T` and `U`. So, you can generate the 
 code from the types and mix it into a function that takes `T 
 base, U other`:
Thanks :) That worked perfectly.
Oct 29 2015