Skip to content

Instantly share code, notes, and snippets.

@wilzbach
Last active February 12, 2018 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wilzbach/0a55a571f1c46e9d59420cf158354b85 to your computer and use it in GitHub Desktop.
Save wilzbach/0a55a571f1c46e9d59420cf158354b85 to your computer and use it in GitHub Desktop.
A stripped down version of std.typecons.Tuple
alias Identity(alias A) = A;
template AliasSeq(TList...)
{
alias AliasSeq = TList;
}
template staticMap(alias F, T...)
{
static if (T.length == 0)
{
alias staticMap = AliasSeq!();
}
else static if (T.length == 1)
{
alias staticMap = AliasSeq!(F!(T[0]));
}
else
{
alias staticMap =
AliasSeq!(
staticMap!(F, T[ 0 .. $/2]),
staticMap!(F, T[$/2 .. $ ]));
}
}
template Tuple(Specs...)
{
// Parse (type,name) pairs (FieldSpecs) out of the specified
// arguments. Some fields would have name, others not.
template parseSpecs(Specs...)
{
static if (Specs.length == 0)
{
alias parseSpecs = AliasSeq!();
}
else static if (is(Specs[0]))
{
static if (is(typeof(Specs[1]) : string))
{
alias parseSpecs =
AliasSeq!(FieldSpec!(Specs[0 .. 2]),
parseSpecs!(Specs[2 .. $]));
}
else
{
alias parseSpecs =
AliasSeq!(FieldSpec!(Specs[0]),
parseSpecs!(Specs[1 .. $]));
}
}
else
{
static assert(0, "Attempted to instantiate Tuple with an "
~"invalid argument: "~ Specs[0].stringof);
}
}
template FieldSpec(T, string s = "")
{
alias Type = T;
alias name = s;
}
alias fieldSpecs = parseSpecs!Specs;
static string injectNamedFields()
{
string decl = "";
static foreach (i, val; fieldSpecs)
{{
immutable si = i.stringof;
decl ~= "alias _" ~ si ~ " = Identity!(expand[" ~ si ~ "]); ";
if (val.name.length != 0)
{
decl ~= "alias " ~ val.name ~ " = _" ~ si ~ "; ";
}
}}
return decl;
}
struct Tuple
{
alias extractType(alias spec) = spec.Type;
alias Types = staticMap!(extractType, fieldSpecs);
Types expand;
pragma(msg, "Injected Fields: ", injectNamedFields);
pragma(msg, "Types: ", Types);
mixin(injectNamedFields());
static if (is(Specs))
{
// This is mostly to make t[n] work.
alias expand this;
}
else
{
@property
ref inout(Tuple!Types) _Tuple_super() inout @trusted
{
foreach (i, _; Types) // Rely on the field layout
{
static assert(typeof(return).init.tupleof[i].offsetof ==
expand[i].offsetof);
}
return *cast(typeof(return)*) &(expand[0]);
}
// This is mostly to make t[n] work.
alias _Tuple_super this;
//alias expand this;
}
static if (Types.length > 0)
{
this(Types values)
{
expand[] = values[];
}
}
}
}
@safe unittest
{
alias point = Tuple!(int, "x", int, "y");
static assert(point(2, 2)[0] == 2);
}
@safe unittest
{
auto t1 = Tuple!(int, "x", string, "y")(1, "a");
void foo(Tuple!(int, string) t2) {}
foo(t1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment