Skip to content

Instantly share code, notes, and snippets.

@sinfu
Created September 27, 2010 05:32
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 sinfu/598659 to your computer and use it in GitHub Desktop.
Save sinfu/598659 to your computer and use it in GitHub Desktop.
More tuple algorithms
module meta;
@safe:
/**
*/
template StaticTuple(seq...)
{
alias seq StaticTuple;
}
//----------------------------------------------------------------------------//
// Algorithms
//----------------------------------------------------------------------------//
/**
*/
template staticMap(alias map, seq...)
{
static if (seq.length < 2)
{
static if (seq.length == 0)
{
alias StaticTuple!() staticMap;
}
else
{
alias StaticTuple!(Instantiate!map.With!(seq[0])) staticMap;
}
}
else
{
alias StaticTuple!(staticMap!(map, seq[ 0 .. $/2]),
staticMap!(map, seq[$/2 .. $ ]))
staticMap;
}
}
unittest
{
}
/**
*/
template staticFilter(alias pred, seq...)
{
static if (seq.length < 2)
{
static if (seq.length == 1 && Instantiate!pred.With!(seq[0]))
{
alias seq staticFilter;
}
else
{
alias StaticTuple!() staticFilter;
}
}
else
{
alias StaticTuple!(staticFilter!(pred, seq[ 0 .. $/2]),
staticFilter!(pred, seq[$/2 .. $ ]))
staticFilter;
}
}
unittest
{
}
/**
*/
template staticReduce(alias compose, Seed, seq...)
{
static if (seq.length == 0)
{
alias Seed staticReduce;
}
else
{
alias staticReduce!(compose,
Instantiate!compose.With!(Seed, seq[0]),
seq[1 .. $])
staticReduce;
}
}
/// ditto
template staticReduce(alias compose, alias Seed, seq...)
{
static if (seq.length == 0)
{
alias Seed staticReduce;
}
else
{
alias staticReduce!(compose,
Instantiate!compose.With!(Seed, seq[0]),
seq[1 .. $])
staticReduce;
}
}
unittest
{
}
/**
*/
template staticRemove(E, seq...)
{
alias staticRemoveIf!(Instantiate!isSame.bindFront!E, seq) staticRemove;
}
/// ditto
template staticRemove(alias E, seq...)
{
alias staticRemoveIf!(Instantiate!isSame.bindFront!E, seq) staticRemove;
}
unittest
{
}
/// ditto
template staticRemoveIf(alias pred, seq...)
{
alias staticFilter!(templateNot!pred, seq) staticRemoveIf;
}
unittest
{
}
// Groundwork for find-family algorithms
private template _staticFindChunk(alias pred, size_t m)
{
template index(seq...)
if (seq.length < m)
{
enum index = seq.length;
}
template index(seq...)
if (m <= seq.length && seq.length < 2*m)
{
static if (Instantiate!pred.With!(seq[0 .. m]))
{
enum index = cast(size_t) 0;
}
else
{
enum index = index!(seq[1 .. $]) + 1;
}
}
template index(seq...)
if (2*m <= seq.length)
{
static if (index!(seq[0 .. $/2 + m - 1]) < seq.length/2)
{
enum index = index!(seq[0 .. $/2 + m - 1]);
}
else
{
enum index = index!(seq[$/2 .. $]) + seq.length/2;
}
}
}
/**
*/
template staticFind(E, seq...)
{
alias staticFindIf!(Instantiate!isSame.bindFront!E, seq) staticFind;
}
/// ditto
template staticFind(alias E, seq...)
{
alias staticFindIf!(Instantiate!isSame.bindFront!E, seq) staticFind;
}
unittest
{
}
/// ditto
template staticFindIf(alias pred, seq...)
{
alias seq[_staticFindChunk!(pred, 1).index!seq .. $] staticFindIf;
}
unittest
{
}
/**
*/
template staticFindAdjacentIf(alias pred, seq...)
{
alias seq[_staticFindChunk!(pred, 2).index!seq .. $] staticFindAdjacentIf;
}
unittest
{
}
/**
*/
template staticIndexOf(E, seq...)
{
static if (staticFind!(E, seq).length == 0)
{
enum sizediff_t staticIndexOf = -1;
}
else
{
enum sizediff_t staticIndexOf = (seq.length -
staticFind!(E, seq).length);
}
}
/// ditto
template staticIndexOf(alias E, seq...)
{
static if (staticFind!(E, seq).length == 0)
{
enum sizediff_t staticIndexOf = -1;
}
else
{
enum sizediff_t staticIndexOf = (seq.length -
staticFind!(E, seq).length);
}
}
unittest
{
}
/**
*/
template staticUntil(E, seq...)
{
alias staticUntilIf!(Instantiate!isSame.bindFront!E, seq) staticUntil;
}
/// ditto
template staticUntil(alias E, seq...)
{
alias staticUntilIf!(Instantiate!isSame.bindFront!E, seq) staticUntil;
}
unittest
{
}
/// ditto
template staticUntilIf(alias pred, seq...)
{
alias seq[0 .. _staticFindChunk!(pred, 1).index!seq] staticUntilIf;
}
unittest
{
}
/**
*/
template staticCount(E, seq...)
{
alias staticCountIf!(Instantiate!isSame.bindFront!E, seq) staticCount;
}
/// ditto
template staticCount(alias E, seq...)
{
alias staticCountIf!(Instantiate!isSame.bindFront!E, seq) staticCount;
}
unittest
{
}
/// ditto
template staticCountIf(alias pred, seq...)
{
static if (seq.length <= 1)
{
static if (seq.length == 0 || !Instantiate!pred.With!(seq[0]))
{
enum size_t staticCountIf = 0;
}
else
{
enum size_t staticCountIf = 1;
}
}
else
{
enum staticCountIf = staticCountIf!(pred, seq[ 0 .. $/2]) +
staticCountIf!(pred, seq[$/2 .. $ ]);
}
}
unittest
{
}
/**
*/
template staticReplace(From, To, seq...)
{
alias staticMap!(_staticReplace!(From, To).map, seq) staticReplace;
}
/// ditto
template staticReplace(alias From, To, seq...)
{
alias staticMap!(_staticReplace!(From, To).map, seq) staticReplace;
}
/// ditto
template staticReplace(From, alias To, seq...)
{
alias staticMap!(_staticReplace!(From, To).map, seq) staticReplace;
}
/// ditto
template staticReplace(alias From, alias To, seq...)
{
alias staticMap!(_staticReplace!(From, To).map, seq) staticReplace;
}
private template _staticReplace(tr...)
{
alias Identity!(tr[0]) from;
alias Identity!(tr[1]) to;
template map(e...)
{
static if (isSame!(e, from))
{
alias to map;
}
else
{
alias e map;
}
}
}
unittest
{
}
/**
*/
template staticMost(alias comp, seq...)
if (seq.length >= 1)
{
static if (seq.length <= 2)
{
static if (seq.length == 1 || !Instantiate!comp.With!(seq[1], seq[0]))
{
alias Identity!(seq[0]) staticMost;
}
else
{
alias Identity!(seq[1]) staticMost;
}
}
else
{
alias staticMost!(comp, staticMost!(comp, seq[ 0 .. $/2]),
staticMost!(comp, seq[$/2 .. $ ]))
staticMost;
}
}
unittest
{
}
/**
*/
template staticSort(alias comp, seq...)
{
static if (seq.length < 2)
{
alias seq staticSort;
}
else
{
alias _staticMerger!comp.Merge!(staticSort!(comp, seq[ 0 .. $/2]))
.With!(staticSort!(comp, seq[$/2 .. $ ]))
staticSort;
}
}
private template _staticMerger(alias comp)
{
template Merge()
{
template With(B...)
{
alias B With;
}
}
template Merge(A...)
{
template With()
{
alias A With;
}
template With(B...)
{
static if (Instantiate!comp.With!(B[0], A[0]))
{
alias StaticTuple!(B[0], Merge!(A )
.With!(B[1 .. $])) With;
}
else
{
alias StaticTuple!(A[0], Merge!(A[1 .. $])
.With!(B )) With;
}
}
}
}
/// ditto
template isStaticSorted(alias comp, seq...)
{
static if (seq.length < 2)
{
enum isStaticSorted = true;
}
else
{
static if (Instantiate!comp.With!(seq[$/2], seq[$/2 - 1]))
{
enum isStaticSorted = false;
}
else
{
enum isStaticSorted = isStaticSorted!(comp, seq[ 0 .. $/2]) &&
isStaticSorted!(comp, seq[$/2 .. $ ]);
}
}
}
unittest
{
}
/**
*/
template staticUniqSort(alias comp, seq...)
{
static if (seq.length < 2)
{
alias seq staticUniqSort;
}
else
{
alias _staticUniqMerger!comp
.Merge!(staticUniqSort!(comp, seq[ 0 .. $/2]))
.With!(staticUniqSort!(comp, seq[$/2 .. $ ]))
staticUniqSort;
}
}
private template _staticUniqMerger(alias comp)
{
template Merge()
{
template With(B...)
{
alias B With;
}
}
template Merge(A...)
{
template With()
{
alias A With;
}
template With(B...)
{
static if (Instantiate!comp.With!(A[0], B[0]))
{
alias StaticTuple!(A[0], Merge!(A[1 .. $])
.With!(B[0 .. $])) With;
}
else static if (Instantiate!comp.With!(B[0], A[0]))
{
alias StaticTuple!(B[0], Merge!(A[0 .. $])
.With!(B[1 .. $])) With;
}
else
{
alias Merge!(A[0 .. $])
.With!(B[1 .. $]) With;
}
}
}
}
/// ditto
template isStaticUniqSorted(alias comp, seq...)
{
static if (seq.length < 2)
{
enum isStaticUniqSorted = true;
}
else
{
static if (Instantiate!comp.With!(seq[$/2 - 1], seq[$/2]))
{
enum isStaticUniqSorted =
isStaticUniqSorted!(comp, seq[ 0 .. $/2]) &&
isStaticUniqSorted!(comp, seq[$/2 .. $ ]);
}
else
{
enum isStaticUniqSorted = false;
}
}
}
unittest
{
}
/**
*/
template staticUniq(seq...)
{
static if (seq.length <= 1)
{
alias seq staticUniq;
}
else
{
static if (isSame!(seq[$/2 - 1], seq[$/2]))
{
alias StaticTuple!(staticUniq!(seq[0 .. $/2]),
staticUniq!(seq[$/2 .. $])[1 .. $])
staticUniq;
}
else
{
alias StaticTuple!(staticUniq!(seq[0 .. $/2]),
staticUniq!(seq[$/2 .. $]))
staticUniq;
}
}
}
unittest
{
}
/**
*/
template staticRemoveDuplicates(seq...)
{
static if (seq.length <= 1)
{
alias seq staticRemoveDuplicates;
}
else
{
alias StaticTuple!(seq[0],
staticRemoveDuplicates!(staticRemove!(seq[0],
seq[1 .. $])))
staticRemoveDuplicates;
}
}
unittest
{
}
/**
*/
template staticReverse(seq...)
{
static if (seq.length < 2)
{
alias seq staticReverse;
}
else
{
alias StaticTuple!(staticReverse!(seq[$/2 .. $ ]),
staticReverse!(seq[ 0 .. $/2]))
staticReverse;
}
}
unittest
{
}
/**
*/
template staticRepeat(size_t n, seq...)
{
static if (n == 0)
{
alias StaticTuple!() staticRepeat;
}
else
{
static if (n == 1 || seq.length == 0)
{
alias seq staticRepeat;
}
else
{
alias StaticTuple!(staticRepeat!( n / 2, seq),
staticRepeat!((n + 1) / 2, seq))
staticRepeat;
}
}
}
unittest
{
}
/**
*/
template staticStride(size_t n, seq...)
if (n >= 1)
{
static if (n == 1 || seq.length <= 1)
{
alias seq staticStride;
}
else
{
static if (seq.length <= n)
{
alias seq[0 .. 1] staticStride;
}
else
{
alias StaticTuple!(staticStride!(n, seq[0 .. _strideMid!($, n)]),
staticStride!(n, seq[_strideMid!($, n) .. $]))
staticStride;
}
}
}
private template _strideMid(size_t n, size_t k)
{
enum _strideMid = ((n + k - 1) / k / 2) * k;
}
unittest
{
}
/**
*/
template staticTransverse(size_t i, tuples...)
{
static if (tuples.length < 2)
{
static if (tuples.length == 0)
{
alias StaticTuple!() staticTransverse;
}
else
{
alias StaticTuple!(tuples[0].Expand[i]) staticTransverse;
}
}
else
{
alias StaticTuple!(staticTransverse!(i, tuples[ 0 .. $/2]),
staticTransverse!(i, tuples[$/2 .. $ ]))
staticTransverse;
}
}
/// ditto
template staticFrontTransverse(tuples...)
{
alias staticTransverse!(0, tuples) staticFrontTransverse;
}
unittest
{
}
/**
*/
template staticZip(tuples...)
{
alias staticMap!(_ZipTransverser!tuples,
staticIota!(0, _minLength!tuples))
staticZip;
}
private
{
template _ZipTransverser(tuples...)
{
template _ZipTransverser(size_t i)
{
alias Wrap!(staticTransverse!(i, tuples)) _ZipTransverser;
}
}
template _minLength(tuples...)
{
alias staticMost!(q{ a < b }, staticMap!(q{ a.length }, tuples))
_minLength;
}
}
unittest
{
}
/**
*/
template staticPermutations(seq...)
{
static if (seq.length > 5)
{
static assert(0, "too many elements for compile-time permutation");
}
else
{
alias _staticPermutations!(seq.length, seq).Result
staticPermutations;
}
}
private
{
template _staticPermutations(size_t k, seq...)
if (k == 0)
{
alias StaticTuple!(metaArray!()) Result;
}
template _staticPermutations(size_t k, seq...)
if (k == 1)
{
alias staticMap!(metaArray, seq) Result;
}
template _staticPermutations(size_t k, seq...)
if (k >= 2)
{
template consLater(car...)
{
template consLater(alias wrap)
{
alias Wrap.insertFront!car consLater;
}
}
template consMapAt(size_t i)
{
alias staticMap!(consLater!(seq[i]),
_staticPermutations!(k - 1,
seq[ 0 .. i],
seq[i + 1 .. $]).Result)
consMapAt;
}
alias staticMap!(consMapAt, staticIota!(seq.length)) Result;
}
}
unittest
{
}
/**
*/
template staticCombinations(size_t k, seq...)
if (k <= seq.length)
{
alias _staticCombinations!(k, seq).Result staticCombinations;
}
private
{
template _staticCombinations(size_t k, seq...)
if (k == 0)
{
alias StaticTuple!(Wrap!()) Result;
}
template _staticCombinations(size_t k, seq...)
if (k == 1)
{
alias staticMap!(Wrap, seq) Result;
}
template _staticCombinations(size_t k, seq...)
if (k >= 2)
{
template consLater(car...)
{
template consLater(alias wrap)
{
alias wrap.insertFront!car consLater;
}
}
template consMapFrom(size_t i)
{
alias staticMap!(consLater!(seq[i]),
_staticCombinations!(k - 1,
seq[i + 1 .. $]).Result)
consMapFrom;
}
alias staticMap!(consMapFrom, staticIota!(seq.length)) Result;
}
}
unittest
{
}
/**
*/
template staticCartesian(tuples...)
if (tuples.length >= 1)
{
alias _staticCartesian!tuples.Result staticCartesian;
}
private
{
template _staticCartesian(alias wrap)
{
alias staticMap!(Wrap, wrap.Expand) Result;
}
template _staticCartesian(alias wrap, rest...)
{
alias _staticCartesian!rest.Result subCartesian;
template consLater(car...)
{
template consLater(alias wrap)
{
alias wrap.insertFront!car consLater;
}
}
template consMap(car...)
{
alias staticMap!(consLater!car, subCartesian) consMap;
}
alias staticMap!(consMap, wrap.Expand) Result;
}
}
unittest
{
}
/**
*/
template staticIota(int beg, int end, int step = 1)
if (step != 0)
{
static if (beg + 1 >= end)
{
static if (beg >= end)
{
alias StaticTuple!() staticIota;
}
else
{
alias StaticTuple!(+beg) staticIota;
}
}
else
{
alias StaticTuple!(staticIota!(beg, _iotaMid!(beg, end) ),
staticIota!( _iotaMid!(beg, end), end))
staticIota;
}
}
private template _iotaMid(int beg, int end)
{
enum _iotaMid = beg + (end - beg) / 2;
}
/// ditto
template staticIota(int end)
{
alias staticIota!(0, end) staticIota;
}
unittest
{
}
/**
*/
template allSatisfy(alias pred, seq...)
{
enum allSatisfy = (staticCountIf!(pred, seq) == seq.length);
}
/// ditto
template anySatisfy(alias pred, seq...)
{
enum anySatisfy = (staticCountIf!(pred, seq) > 0);
}
/// ditto
template noneSatisfy(alias pred, seq...)
{
enum noneSatisfy = (staticCountIf!(pred, seq) == 0);
}
unittest
{
}
//----------------------------------------------------------------------------//
// Convenience Templates
//----------------------------------------------------------------------------//
/**
*/
template Identity(alias E)
{
alias E Identity;
}
/// ditto
template Identity(E)
{
alias E Identity;
}
unittest
{
}
/**
*/
template Wrap(seq...)
{
/**
*/
alias seq Expand;
/**
*/
enum bool empty = !seq.length;
/**
*/
enum size_t length = seq.length;
/**
*/
template at(size_t i)
{
alias Identity!(seq[i]) at;
}
/**
*/
template slice(size_t i, size_t j)
{
alias Wrap!(seq[i .. j]) slice;
}
/**
*/
template take(size_t n)
{
alias Wrap!(seq[0 .. (n < $ ? n : $)]) take;
}
/**
*/
template drop(size_t n)
{
alias Wrap!(seq[(n < $ ? n : $) .. $]) drop;
}
/**
*/
template insertFront(aseq...)
{
alias Wrap!(aseq, seq) insertFront;
}
/**
*/
template insertBack(aseq...)
{
alias Wrap!(seq, aseq) insertBack;
}
/**
*/
template insertAt(size_t i, aseq...)
{
alias Wrap!(seq[0 .. i], aseq, seq[i .. $]) insertAt;
}
/**
*/
template contains(subseq...)
{
static if (subseq.length == 0 || subseq.length > seq.length)
{
enum contains = (subseq.length == 0);
}
else
{
enum contains = _staticFindChunk!(MatchSequence!aseq.With,
subseq.length)
.index!seq < seq.length;
}
}
private:
template ToType()
{
struct ToType {}
}
version (unittest) alias ToType!() _T;
}
unittest
{
}
/**
*/
template MatchSequence(seq...)
{
/**
*/
template With(aseq...)
{
enum With = is(Wrap!seq.ToType!() == Wrap!aseq.ToType!());
}
}
unittest
{
}
/**
*/
template isSame(A, B)
{
enum isSame = is(A == B);
}
/// ditto
template isSame(alias A, alias B)
{
enum isSame = is(Wrap!A.ToType!() == Wrap!B.ToType!());
}
/// ditto
template isSame(alias A, B)
{
enum isSame = false;
}
/// ditto
template isSame(A, alias B)
{
enum isSame = false;
}
unittest
{
}
/**
*/
template templateFun(string expr)
{
alias _templateFun!expr._ templateFun;
}
// XXX
private template _templateFun(string expr)
{
enum size_t maxArgs = ('z' - 'a' + 1);
template _(args...)
if (args.length <= maxArgs)
{
alias invoke!args.result _;
}
template invoke(args...)
if (args.length <= maxArgs)
{
mixin bind!(0, args);
mixin("alias Identity!(" ~ expr ~ ") result;");
}
template bind(size_t i, args...)
{
static if (i < args.length)
{
mixin("alias Identity!(args[i]) " ~ paramAt!i ~ ";");
mixin bind!(i + 1, args);
}
}
template paramAt(size_t i)
if (i < maxArgs)
{
enum dchar paramAt = ('a' + i);
}
}
unittest
{
}
//----------------------------------------------------------------------------//
// Templationals
//----------------------------------------------------------------------------//
/**
*/
template Instantiate(alias templat)
{
/**
*/
template With(args...)
{
alias templat!args With;
}
/**
*/
template bindFront(bind...)
{
template bindFront(args...)
{
alias templat!(bind, args) bindFront;
}
}
/**
*/
template bindBack(bind...)
{
template bindBack(args...)
{
alias templat!(args, bind) bindBack;
}
}
}
/// ditto
template Instantiate(string templat)
{
alias Instantiate!(templateFun!templat) Instantiate;
}
unittest
{
}
private template Instantiator(args...)
{
template Instantiator(alias templat)
{
alias Instantiate!templat.With!args Instantiator;
}
}
/**
*/
template templateNot(alias pred)
{
template templateNot(args...)
{
enum templateNot = !Instantiate!pred.With!args;
}
}
unittest
{
}
/**
*/
template templateAnd(preds...)
{
template templateAnd(args...)
{
alias allSatisfy!(Instantiator!args, preds) templateAnd;
}
}
/// ditto
template templateOr(preds...)
{
template templateOr(args...)
{
alias anySatisfy!(Instantiator!args, preds) templateOr;
}
}
unittest
{
}
/**
*/
template templateCompose(templates...)
if (templates.length >= 1)
{
template templateCompose(args...)
{
static if (templates.length == 1)
{
alias Instantiate!(templates[0]).With!args templateCompose;
}
else
{
alias Instantiate!(templates[0])
.With!(Instantiate!(.templateCompose!(templates[1 .. $]))
.With!args)
templateCompose;
}
}
}
unittest
{
}
//----------------------------------------------------------------------------//
/**
*/
template Select(bool condition, Then, Else)
{
static if (cnodition)
{
alias Then Select;
}
else
{
alias Else Select;
}
}
/// ditto
template Select(bool condition, Then, alias Else)
{
static if (condition)
{
alias Then Select;
}
else
{
alias Else Select;
}
}
/// ditto
template Select(bool condition, alias Then, Else)
{
static if (condition)
{
alias Then Select;
}
else
{
alias Else Select;
}
}
/// ditto
template Select(bool condition, alias Then, alias Else)
{
static if (condition)
{
alias Then Select;
}
else
{
alias Else Select;
}
}
unittest
{
}
/**
*/
A select(bool cond, A, B)(A a, lazy B b)
if (cond)
{
return a;
}
/// Ditto
B select(bool cond, A, B)(lazy A a, B b)
if (!cond)
{
return b;
}
unittest
{
}
module types;
import meta;
@safe:
/**
*/
template TypeTuple(T...)
if (allSatisfy!(isType, T))
{
alias T TypeTuple;
}
/**
*/
template MostDerived(T, Rest...)
{
alias staticMost!(q{ is(a : b) }, T, Rest) MostDerived;
}
/**
*/
template DerivedToFront(T...)
{
alias staticSort!(q{ is(a : b) }, T) DerivedToFront;
}
/**
*/
template SmallestAmong(T...)
{
alias staticMost!(q{ a.sizeof < b.sizeof }, T) SmallestAmong;
}
/**
*/
template LargestAmong(T...)
{
alias staticMost!(q{ a.sizeof > b.sizeof }, T) LargestAmong;
}
// traits
/**
*/
template isType(T)
{
enum isType = true;
}
template isType(alias T)
{
enum isType = is(T);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment