Unstandard

Various stuff for working with generic tuples.

A replacement for std.typetuple.

The following symbols from std.typetuple are publicly imported:

The following symbols from std.typetuple are superseded: The following symbols from std.typetuple are considered useless:
Generic tuple manipulation functions
Category Functions
Searching anyTuple   allTuple  
Creation RetroTuple   StrideTuple   ChainTuple   RoundRobinTuple   RadialTuple   RepeatTuple   ZipTuple   iotaTuple   IndexedTuple   ChunksTuple  
Comparison cmpTuple   equalTuple  
Iteration FilterTuple   groupTuple   JoinTuple   MapTuple   ReduceTuple   UniqTuple  

License
Boost License 1.0.
Authors
Denis Shelomovskij

template  GenericTuple(Args...)

Creates a generic tuple out of a sequence of zero or more types, expressions, or aliases.

Examples
alias MyTemplate(T) = T[];

alias MyTuple = GenericTuple!(int, 5, "a string", MyTemplate);

MyTuple[0] myVar = MyTuple[1]; // same as `int myVar = 5;`
auto str = MyTuple[2]; // same as `auto str = "a string";`

alias Template = MyTuple[3];
static assert(is(Template!int == int[]));

template  PackedGenericTuple(Args...)

Creates a packed generic tuple out of a sequence of zero or more types, expressions, or aliases.

Packed version doesn't alias itself to its content, i.e. it doesn't auto-unpack.

Examples
alias MyPackedTuple = PackedGenericTuple!(long, 3);

MyPackedTuple.Tuple[0] myVar = MyPackedTuple.Tuple[1]; // same as `long myVar = 3;`

alias MyTemplate(alias packed) = packed.Tuple[0][];

// It is passed as a single template alias parameter:
static assert(is(MyTemplate!MyPackedTuple == long[]));

alias  Tuple = Args;

Use this member of to access its content as a generic tuple.


alias  Types = Args;

Use this member of to access its content as a typetuple. Defined if Args is a typetuple.


alias  expressions = Args;

Use this member of to access its content as an expression tuple. Defined if Args is an expression tuple.


template  equals(A...)

Convenient equality check template. Same as equalTuple.


template  cmp(A...)

Convenient comparison template. Same as cmpTuple.


template  TypeTuple(Types...) if (isTypeTuple!Types)

Creates a typetuple out of a sequence of zero or more types. Same as GenericTuple, except it contains only types.

Examples
alias IntDouble = TypeTuple!(int, double);

int foo(IntDouble args)  // same as `int foo(int, double)`
{
	return args[0] + cast(int) args[1];
}

alias IntDoubleChar = TypeTuple!(int, double, char);
static assert(is(TypeTuple!(IntDouble, char) == IntDoubleChar));
static assert(is(IntDoubleChar[0 .. 2] == IntDouble));


version(none)
alias BadTypeTuple = TypeTuple!(int, 5); // error: not a type tuple

template  PackedTypeTuple(T...) if (isTypeTuple!T)

Creates a packed typetuple out of a sequence of zero or more types. Same as PackedGenericTuple, except it contains only types.


template  expressionTuple(expressions...) if (isExpressionTuple!expressions)

Creates an expression tuple out of a sequence of zero or more expressions. Same as GenericTuple, except it contains only expressions.

Examples
alias expressions = expressionTuple!(5, 'c', "str");

typeof(expressions[0]) myVar = expressions[1]; // same as `int myVar = 5;`
auto str = expressions[2]; // same as `auto str = "a string";`

void foo(out typeof(expressions[0 .. 2]) args)  // same as `int foo(out int, out char)`
{
	args[0] = expressions[0] * 2; // same as `5 * 2`
	args[1] = expressions[1] + 1; // same as `'c' + 1`
}

void main()
{
	int i;
	char c;
	foo(i, c);
	assert(i == 10 && c == 'd');
}

version(none)
alias badExpressionTuple = expressionTuple!(int, 5); // error: not an expression tuple

template  packedExpressionTuple(expr...) if (isExpressionTuple!expr)

Creates a packed expression tuple out of a sequence of zero or more expressions. Same as PackedGenericTuple, except it contains only expressions.


template  RetroTuple(A...)

Creates a generic tuple comprised of elemetns of A in reverse order.

Applying  RetroTuple twice to the same generic tuple equals to the original generic tuple.

Example:
static assert(is(RetroTuple!(int, bool, long) == TypeTuple!(long, bool, int)));
static assert(PackedGenericTuple!(RetroTuple!(1, bool, "x")).equals!("x", bool, 1));


Analog of std.range.retro for generic tuples.

template  StrideTuple(size_t n, A...) if (n > 0)

Creates a generic tuple comprised of elemetns of A taken with stride n.

Applying  StrideTuple twice to the same generic tuple equals to applying  StrideTuple with a step that is the product of the two applications.

Example:
static assert(is(StrideTuple!(2, ubyte, byte, uint, int, ulong, long) == TypeTuple!(ubyte, uint, ulong)));
static assert(StrideTuple!(3, iota) == expressionTuple!(1, 4, 7, 10));


Analog of std.range.stride for generic tuples except n is the first argument.

template  ChainTuple(packedTuples...) if (packedTuples.length && allTuple!(isPackedTuple, packedTuples))

Creates a generic tuple comprised of all elemetns of packed generic tuples packedTuples in sequence.

Example:
alias chain = ChainTuple!(packedExpressionTuple!(1, 2, 3), packedExpressionTuple!(4, 5));
static assert(chain == expressionTuple!(1, 2, 3, 4, 5));


Analog of std.range.chain for generic tuples.

template  RoundRobinTuple(packedTuples...) if (packedTuples.length && allTuple!(isPackedTuple, packedTuples))

Creates a generic tuple comprised of all elemetns of packed generic tuples packedTuples in an order by analogy with Round-robin scheduling.

Example:
alias roundRobin = RoundRobinTuple!(packedExpressionTuple!(1, 2, 3), packedExpressionTuple!(10, 20, 30, 40));
static assert(roundRobin == expressionTuple!(1, 10, 2, 20, 3, 30, 40));


Analog of std.range.roundRobin for generic tuples.

template  RadialTuple(size_t startingIndex, A...)
template  RadialTupleMiddle(A...)

Creates a generic tuple comprised of all elemetns of A which are teken starting from a given point and progressively extending left and right from that point. If RadialTupleMiddle is used or startingIndex is -1 it is assumed that no initial point is given and iteration starts from the middle of A.

Example:
static assert(RadialTuple!(-1, 1, 2, 3, 4, 5) == expressionTuple!(3, 4, 2, 5, 1));
static assert(RadialTuple!( 1, 1, 2, 3, 4, 5) == expressionTuple!(2, 3, 1, 4, 5));


Analog of std.range.radial for generic tuples except startingIndex is the first argument and there is no overload without it.

template  RepeatTuple(size_t n, A...)

Repeats A n times.

Example:
static assert(is(RepeatTuple!(2, int) == TypeTuple!(int, int)));
static assert(RepeatTuple!(4, 5) == expressionTuple!(5, 5, 5, 5));


Analog of std.array.replicate and std.range.repeat for generic tuples except n is the first argument and there is no overload without it as tuples can't be infinite. Also it repeats a generic tuple, not only one value.

template  ZipTuple(StoppingPolicy stoppingPolicy : StoppingPolicy.longest, alias empty, packedTuples...)
template  ZipTuple(StoppingPolicy stoppingPolicy : StoppingPolicy.longest, empty, packedTuples...)
template  ZipTuple(StoppingPolicy stoppingPolicy, packedTuples...) if (stoppingPolicy != StoppingPolicy.longest)
template  ZipTuple(packedTuples...) if (packedTuples.length && allTuple!(isPackedTuple, packedTuples))

Creates a generic tuple comprised of packed generic tuples comprised of elemetns of packed generic tuples packedTuples taken in lockstep.

If stoppingPolicy is StoppingPolicy.longest and a tuple is finished in a lockstep iteration then empty will be taken.

Example:
alias packed1 = packedExpressionTuple!(1, 2, 3);
alias packed2 = PackedTypeTuple!(short, int, long);
alias zip = ZipTuple!(packed1, packed2);

static assert(zip[0].equals!(1, short));
static assert(zip[1].equals!(2, int));
static assert(zip[2].equals!(3, long))


Analog of std.range.zip for generic tuples except empty value must be explicitly specified for StoppingPolicy.longest.

template  iotaTuple(alias begin, alias end, alias step)
template  iotaTuple(alias begin, alias end)
template  iotaTuple(alias end)

Returns expression tuple with elements going through the numbers begin, begin + step, begin + 2 * step, ..., up to and excluding end. The two-arguments version has step = 1. The one-argument version also has begin = 0. If begin < end && step < 0 or begin > end && step > 0 or begin == end, then an empty tuple is returned.

Example:
int res;
foreach(i; iotaTuple!5) // same as res += foo!1(); res += foo!3();
	static if(i & 1)
		res += foo!i();
Tip:
This is a convenient way to create a CT analog of Foreach Range Statement.

Analog of std.range.iota for generic tuples.

template  IndexedTuple(alias packedSourceTuple, alias packedIndicesTuple) if (isPackedTuple!packedSourceTuple && isPackedTuple!packedIndicesTuple)

Creates a generic tuple comprised of elemetns of packed generic tuple packedSourceTuple reordered according to packed expression tuple packedIndicesTuple. packedIndicesTuple may include only a subset of the elements of packedSourceTuple and may also repeat elements.

Example:
alias indexed = IndexedTuple!(PackedTypeTuple!(short, int, long, double),
                              packedExpressionTuple!(1, 0, 2, 2));
static assert(is(indexed == TypeTuple!(int, short, long, long)));


Analog of std.range.indexed for generic tuples.

template  ChunksTuple(size_t chunkSize, A...)

Creates a generic tuple comprised of packed generic tuples comprised of fixed-sized chunks of size chunkSize of A.

If A.length is not evenly divisible by chunkSize, the last packed generic tuple will contain fewer than chunkSize elements.

Example:
alias chunks = ChunksTuple!(4,  1, 2, 3, 4, 5, 6, byte, short, int, long);
static assert(chunks[0].equals!(1, 2, 3, 4));
static assert(chunks[1].equals!(5, 6, byte, short));
static assert(chunks[2].equals!(int, long));


Analog of std.range.chunks for generic tuples except chunkSize is the first argument.

template  cmpTuple(alias pred, alias packedTuple1, alias packedTuple2) if (isPackedTuple!packedTuple1 && isPackedTuple!packedTuple2)
template  cmpTuple(alias packedTuple1, alias packedTuple2)

Performs three-way lexicographical comparison on two packed generic tuples according to predicate pred.

Iterating packedTuple1 and packedTuple2 in lockstep,  cmpTuple compares each element A1 of packedTuple1 with the corresponding element A2 in packedTuple2. If Inst!(binaryPred!pred, A1, A2), cmp returns a negative value. If Inst!(binaryPred!pred, A2, A1), cmp returns a positive value. If one of the tuples has been finished, cmp returns a negative value if packedTuple1 has fewer elements than packedTuple2, a positive value if packedTuple1 has more elements than packedTuple2, and 0 if the tuples have the same number of elements.

Example:
static assert(cmpTuple!(packedExpressionTuple!0, packedExpressionTuple!0) == 0);
static assert(cmpTuple!(packedExpressionTuple!"a", packedExpressionTuple!"ab") < 0);
static assert(cmpTuple!(`T.sizeof < U.sizeof`, PackedTypeTuple!int, PackedTypeTuple!long) < 0);


Analog of std.algorithm.cmp for generic tuples.

template  equalTuple(alias pred, alias packedTuple1, alias packedTuple2) if (isPackedTuple!packedTuple1 && isPackedTuple!packedTuple2)
template  equalTuple(alias packedTuple1, alias packedTuple2)

Detect whether two packed generic tuples packedTuple1 and packedTuple2 elements are equal according to binary predicate pred.

isSame is used if no predicacte specified.

Example:
static assert( equalTuple!(packedExpressionTuple!(0, 1), packedExpressionTuple!(iotaTuple!2)));
static assert( equalTuple!(PackedGenericTuple!(int, "a"), PackedGenericTuple!(int, "a")));

static assert( equalTuple!(`true`, packedExpressionTuple!1, PackedTypeTuple!int));
static assert(!equalTuple!(`true`, packedExpressionTuple!1, packedExpressionTuple!()));


Analog of std.algorithm.equal for generic tuples.

template  FilterTuple(alias pred, A...)

Creates a generic tuple comprised of elemetns of A for which a unary predicate pred is true.

Example:
import std.traits;

static assert(is(FilterTuple!(isNumeric, int, void, immutable short, char) ==
              TypeTuple!(int, immutable short)));

static assert(is(FilterTuple!(`__traits(isUnsigned, T)`, int, size_t, void, ushort, char) ==
              TypeTuple!(size_t, ushort, char)));


Analog of std.algorithm.filter for generic tuples.

template  groupTuple(alias pred, A...)

Similarly to UniqTuple, creates a generic tuple comprised of packed generic tuples comprised of unique consecutive elemetns of A and counts of equivalent elements seen.

Equivalence of elements is assessed by using a binary predicate pred.

Example:
alias tuple = GenericTuple!(1, 2, 2, 2, "x", "x", int, 1, 1);

alias group = groupTuple!(isSame, tuple);
static assert(group.length == 5);
static assert(group[0].equals!(1, 1));
static assert(group[1].equals!(2, 3));
static assert(group[2].equals!("x", 2));
static assert(group[3].equals!(int, 1));
static assert(group[4].equals!(1, 2));

alias group2 = groupTuple!(notTemplate!isSame, tuple);
static assert(group2.length == 3);
static assert(group2[0].equals!(1, 7));
static assert(group2[1].equals!(1, 1));
static assert(group2[2].equals!(1, 1));


Analog of std.algorithm.group for generic tuples except pred must be explicitly specified.

template  JoinTuple(alias packedSeparatorTuple, packedTuples...) if (allTuple!(isPackedTuple, packedSeparatorTuple, packedTuples))

Creates a generic tuple comprised of packed generic tuples packedTuples generic tuples joined together using packed generic tuple packedSeparatorTuple as a separator.

Example:
alias sep = packedExpressionTuple!"+";
alias part1 = PackedTypeTuple!(void, int);
alias part2 = packedExpressionTuple!0;
static assert(PackedGenericTuple!(JoinTuple!(sep, part1, part2)).equals!(void, int, "+", 0));


Analog of std.array.join and std.algorithm.joiner for generic tuples.

template  MapTuple(alias Func, A...)

Creates a generic tuple comprised of results of applying unary template Func to elemetns of A consecutively.

Example:
alias squares = MapTuple!(`a * a`, iotaTuple!4);
static assert(squares == expressionTuple!(0, 1, 4, 9));

static assert(is(MapTuple!(`T[]`, int, long) == TypeTuple!(int[], long[])));


Analog of std.algorithm.map for generic tuples except Func can return any count of elements.

template  ReduceTuple(alias Func, alias init, A...)

The instantiation of  ReduceTuple!(Func, init, A) first lets result be init. Then, for each element x in A sequentially, it lets result be Inst!(BinaryTemplate!Func, result, x). Finally, result is returned.

Example:
static assert(ReduceTuple!(`a + U.sizeof`, 0, bool, short, int) == 1 + 2 + 4);
static assert(is(ReduceTuple!(`Select!(T.sizeof > U.sizeof, T, U)`, void, bool, long, int) == long));


Analog of std.algorithm.reduce for generic tuples except there is no overload with multiple functions.

template  UniqTuple(alias pred, A...)

Creates a generic tuple comprised of unique consecutive elemetns of A.

Equivalence of elements is assessed by using a binary predicate pred.

Example:
alias expr = expressionTuple!(1, 2, 2, 2, 3, 3, 4, 1, 1);
static assert(UniqTuple!(`a == b`, expr) == expressionTuple!(1, 2, 3, 4, 1));
static assert(UniqTuple!(`a != b`, expr) == expressionTuple!(1, 1, 1));


Analog of std.algorithm.uniq for generic tuples except pred must be explicitly specified.

template  anyTuple(alias pred, A...)

Detect whether a generic tuple A contains an element satisfying the predicate pred.

Example:
static assert(!anyTuple!(`true`));
static assert( anyTuple!(`isIntegral!T`, float, int));
static assert(!anyTuple!(`a < 2`, 2, 3));


Analog of std.algorithm.any for generic tuples except pred must be explicitly specified.

template  allTuple(alias pred, A...)

Detect whether all elements of a generic tuple A satisfy the predicate pred.

Returns true for an empty tuple.

Example:
static assert( allTuple!(`false`));
static assert( allTuple!(`isIntegral!T`, byte, int));
static assert(!allTuple!("a & 1", 1, 2, 3));


Analog of std.algorithm.all for generic tuples except pred must be explicitly specified.