Add new metafunctions: Min, Max, ZipWith

Documentation follow
This commit is contained in:
Eugen Wissner 2017-08-27 15:32:05 +02:00
parent 25d59ffdda
commit 4dbfbe9874

View File

@ -15,6 +15,109 @@
*/ */
module tanya.meta.metafunction; module tanya.meta.metafunction;
import tanya.meta.trait;
template Min(alias pred, Args...)
if (Args.length > 0 && isTemplate!pred)
{
static if (Args.length == 1)
{
alias Min = Alias!(Args[0]);
}
else static if (isLess!(pred, Args[1], Args[0]))
{
alias Min = Min!(pred, Args[1], Args[2 .. $]);
}
else
{
alias Min = Min!(pred, Args[0], Args[2 .. $]);
}
}
///
pure nothrow @safe @nogc unittest
{
enum bool cmp(alias T, alias U) = T < U;
static assert(Min!(cmp, 8, 4, 5, 3, 13) == 3);
static assert(Min!(cmp, 8) == 8);
}
template Max(alias pred, Args...)
if (Args.length > 0 && isTemplate!pred)
{
static if (Args.length == 1)
{
alias Max = Alias!(Args[0]);
}
else static if (isGreater!(pred, Args[1], Args[0]))
{
alias Max = Max!(pred, Args[1], Args[2 .. $]);
}
else
{
alias Max = Max!(pred, Args[0], Args[2 .. $]);
}
}
///
pure nothrow @safe @nogc unittest
{
enum bool cmp(alias T, alias U) = T < U;
static assert(Max!(cmp, 8, 4, 5, 3, 13) == 13);
static assert(Max!(cmp, 8) == 8);
}
template ZipWith(alias pred, Tuples...)
if (Tuples.length > 0
&& isTemplate!pred
&& allSatisfy!(ApplyLeft!(isInstanceOf, AliasTuple), Tuples))
{
private template GetIth(size_t i, Args...)
{
static if ((Args.length == 0) || (Args[0].Seq.length <= i))
{
alias GetIth = AliasSeq!();
}
else
{
alias GetIth = AliasSeq!(Args[0].Seq[i], GetIth!(i, Args[1 .. $]));
}
}
private template Iterate(size_t i, Args...)
{
alias Tuple = GetIth!(i, Args);
static if (Tuple.length < Tuples.length)
{
alias Iterate = AliasSeq!();
}
else
{
alias Iterate = AliasSeq!(pred!Tuple,
Iterate!(i + 1, Args));
}
}
alias ZipWith = Iterate!(0, Tuples);
}
///
pure nothrow @safe @nogc unittest
{
alias Result1 = ZipWith!(AliasSeq,
AliasTuple!(1, 2),
AliasTuple!(5, 6),
AliasTuple!(9, 10));
static assert(Result1 == AliasSeq!(1, 5, 9, 2, 6, 10));
alias Result2 = ZipWith!(AliasSeq,
AliasTuple!(1, 2, 3),
AliasTuple!(4, 5));
static assert(Result2 == AliasSeq!(1, 4, 2, 5));
alias Result3 = ZipWith!(AliasSeq, AliasTuple!(), AliasTuple!(4, 5));
static assert(Result3.length == 0);
}
/** /**
* Holds a typed sequence of template parameters. * Holds a typed sequence of template parameters.
* *
@ -98,7 +201,7 @@ pure nothrow @safe @nogc unittest
* to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. * to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise.
*/ */
template isLessEqual(alias cmp, Args...) template isLessEqual(alias cmp, Args...)
if (Args.length == 2) if (Args.length == 2 && isTemplate!cmp)
{ {
private enum result = cmp!(Args[1], Args[0]); private enum result = cmp!(Args[1], Args[0]);
static if (is(typeof(result) == bool)) static if (is(typeof(result) == bool))
@ -145,7 +248,7 @@ pure nothrow @safe @nogc unittest
* equal to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. * equal to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise.
*/ */
template isGreaterEqual(alias cmp, Args...) template isGreaterEqual(alias cmp, Args...)
if (Args.length == 2) if (Args.length == 2 && isTemplate!cmp)
{ {
private enum result = cmp!Args; private enum result = cmp!Args;
static if (is(typeof(result) == bool)) static if (is(typeof(result) == bool))
@ -192,7 +295,7 @@ pure nothrow @safe @nogc unittest
* $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise.
*/ */
template isLess(alias cmp, Args...) template isLess(alias cmp, Args...)
if (Args.length == 2) if (Args.length == 2 && isTemplate!cmp)
{ {
private enum result = cmp!Args; private enum result = cmp!Args;
static if (is(typeof(result) == bool)) static if (is(typeof(result) == bool))
@ -239,7 +342,7 @@ pure nothrow @safe @nogc unittest
* $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise.
*/ */
template isGreater(alias cmp, Args...) template isGreater(alias cmp, Args...)
if (Args.length == 2) if (Args.length == 2 && isTemplate!cmp)
{ {
private enum result = cmp!Args; private enum result = cmp!Args;
static if (is(typeof(result) == bool)) static if (is(typeof(result) == bool))
@ -329,6 +432,17 @@ pure nothrow @safe @nogc unittest
static assert(isNotEqual!(5, 8)); static assert(isNotEqual!(5, 8));
} }
/**
* Instantiates the template $(D_PARAM T) with $(D_PARAM ARGS).
*
* Params:
* T = Template.
* Args = Template parameters.
*
* Returns: Instantiated template.
*/
alias Instantiate(alias T, Args...) = T!Args;
version (TanyaPhobos) version (TanyaPhobos)
{ {
public import std.meta : Alias, public import std.meta : Alias,
@ -402,7 +516,6 @@ pure nothrow @safe @nogc unittest
static assert(is(typeof(Alias!i))); static assert(is(typeof(Alias!i)));
} }
/** /**
* Holds a sequence of aliases. * Holds a sequence of aliases.
* *
@ -454,6 +567,7 @@ pure nothrow @safe @nogc unittest
* $(D_PARAM F), $(D_KEYWORD false) otherwise. * $(D_PARAM F), $(D_KEYWORD false) otherwise.
*/ */
template allSatisfy(alias F, L...) template allSatisfy(alias F, L...)
if (isTemplate!F)
{ {
static if (L.length == 0) static if (L.length == 0)
{ {
@ -491,6 +605,7 @@ pure nothrow @safe @nogc unittest
* $(D_PARAM F), $(D_KEYWORD false) otherwise. * $(D_PARAM F), $(D_KEYWORD false) otherwise.
*/ */
template anySatisfy(alias F, L...) template anySatisfy(alias F, L...)
if (isTemplate!F)
{ {
static if (L.length == 0) static if (L.length == 0)
{ {
@ -562,17 +677,6 @@ pure nothrow @safe @nogc unittest
static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3); static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3);
} }
/**
* Instantiates the template $(D_PARAM T) with $(D_PARAM ARGS).
*
* Params:
* T = Template.
* Args = Template parameters.
*
* Returns: Instantiated template.
*/
alias Instantiate(alias T, Args...) = T!Args;
/** /**
* Combines multiple templates with logical AND. So $(D_PSYMBOL templateAnd) * Combines multiple templates with logical AND. So $(D_PSYMBOL templateAnd)
* evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on. * evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on.
@ -585,6 +689,7 @@ alias Instantiate(alias T, Args...) = T!Args;
* Returns: The constructed template. * Returns: The constructed template.
*/ */
template templateAnd(Preds...) template templateAnd(Preds...)
if (allSatisfy!(isTemplate, Preds))
{ {
template templateAnd(T...) template templateAnd(T...)
{ {
@ -632,6 +737,7 @@ pure nothrow @safe @nogc unittest
* Returns: The constructed template. * Returns: The constructed template.
*/ */
template templateOr(Preds...) template templateOr(Preds...)
if (allSatisfy!(isTemplate, Preds))
{ {
template templateOr(T...) template templateOr(T...)
{ {
@ -675,6 +781,7 @@ pure nothrow @safe @nogc unittest
* Returns: Negated $(D_PARAM pred). * Returns: Negated $(D_PARAM pred).
*/ */
template templateNot(alias pred) template templateNot(alias pred)
if (isTemplate!pred)
{ {
enum bool templateNot(T...) = !pred!T; enum bool templateNot(T...) = !pred!T;
} }
@ -708,6 +815,7 @@ pure nothrow @safe @nogc unittest
* if not. * if not.
*/ */
template isSorted(alias cmp, L...) template isSorted(alias cmp, L...)
if (isTemplate!cmp)
{ {
static if (L.length <= 1) static if (L.length <= 1)
{ {
@ -986,6 +1094,7 @@ pure nothrow @safe @nogc unittest
* Returns: Elements $(D_PARAM T) after applying $(D_PARAM F) to them. * Returns: Elements $(D_PARAM T) after applying $(D_PARAM F) to them.
*/ */
template Map(alias F, T...) template Map(alias F, T...)
if (isTemplate!F)
{ {
static if (T.length == 0) static if (T.length == 0)
{ {
@ -1027,6 +1136,7 @@ pure nothrow @safe @nogc unittest
* See_Also: $(LINK2 https://en.wikipedia.org/wiki/Merge_sort, Merge sort). * See_Also: $(LINK2 https://en.wikipedia.org/wiki/Merge_sort, Merge sort).
*/ */
template Sort(alias cmp, L...) template Sort(alias cmp, L...)
if (isTemplate!cmp)
{ {
private template merge(size_t A, size_t B) private template merge(size_t A, size_t B)
{ {