Created
September 27, 2010 05:32
-
-
Save sinfu/598659 to your computer and use it in GitHub Desktop.
More tuple algorithms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
{ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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