diff --git a/source/tanya/meta/metafunction.d b/source/tanya/meta/metafunction.d index 75c717c..ac25768 100644 --- a/source/tanya/meta/metafunction.d +++ b/source/tanya/meta/metafunction.d @@ -17,7 +17,7 @@ module tanya.meta.metafunction; version (unittest) { - import std.traits; + import tanya.meta.trait; } /** @@ -206,3 +206,248 @@ pure nothrow @safe @nogc unittest static assert(staticIndexOf!(int, float, double, int, real) == 2); 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) + * evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on. + * + * Empty $(D_PARAM Preds) evaluates to $(D_KEYWORD true). + * + * Params: + * Preds = Template predicates. + * + * Returns: The constructed template. + */ +template templateAnd(Preds...) +{ + template templateAnd(T...) + { + static if (Preds.length == 0) + { + enum bool templateAnd = true; + } + else static if (Instantiate!(Preds[0], T)) + { + alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T); + } + else + { + enum bool templateAnd = false; + } + } +} + +/// +pure nothrow @safe @nogc unittest +{ + alias isMutableInt = templateAnd!(isIntegral, isMutable); + static assert(isMutableInt!int); + static assert(!isMutableInt!(const int)); + static assert(!isMutableInt!float); + + alias alwaysTrue = templateAnd!(); + static assert(alwaysTrue!int); + + alias isIntegral = templateAnd!(.isIntegral); + static assert(isIntegral!int); + static assert(isIntegral!(const int)); + static assert(!isIntegral!float); +} + +/** + * Combines multiple templates with logical OR. So $(D_PSYMBOL templateOr) + * evaluates to $(D_INLINECODE Preds[0] || Preds[1] || Preds[2]) and so on. + * + * Empty $(D_PARAM Preds) evaluates to $(D_KEYWORD false). + * + * Params: + * Preds = Template predicates. + * + * Returns: The constructed template. + */ +template templateOr(Preds...) +{ + template templateOr(T...) + { + static if (Preds.length == 0) + { + enum bool templateOr = false; + } + else static if (Instantiate!(Preds[0], T)) + { + enum bool templateOr = true; + } + else + { + alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T); + } + } +} + +/// +pure nothrow @safe @nogc unittest +{ + alias isMutableOrInt = templateOr!(isIntegral, isMutable); + static assert(isMutableOrInt!int); + static assert(isMutableOrInt!(const int)); + static assert(isMutableOrInt!float); + static assert(!isMutableOrInt!(const float)); + + alias alwaysFalse = templateOr!(); + static assert(!alwaysFalse!int); + + alias isIntegral = templateOr!(.isIntegral); + static assert(isIntegral!int); + static assert(isIntegral!(const int)); + static assert(!isIntegral!float); +} + +/** + * Params: + * pred = Template predicate. + * + * Returns: Negated $(D_PARAM pred). + */ +template templateNot(alias pred) +{ + enum bool templateNot(T...) = !pred!T; +} + +/// +pure nothrow @safe @nogc unittest +{ + alias isNotIntegral = templateNot!isIntegral; + static assert(!isNotIntegral!int); + static assert(isNotIntegral!(char[])); +} + +/** + * Tests whether $(D_PARAM L) is sorted in ascending order according to + * $(D_PARAM cmp). + * + * $(D_PARAM cmp) can evaluate to: + * $(UL + * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means + * $(D_INLINECODE a[i] < a[i + 1]).) + * $(LI $(D_KEYWORD int): a negative number means that + * $(D_INLINECODE a[i] < a[i + 1]), a positive number that + * $(D_INLINECODE a[i] > a[i + 1]), `0` if they equal.) + * ) + * + * Params: + * cmp = Comparison template. + * L = Arguments. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM L) is sorted, $(D_KEYWORD false) + * if not. + */ +template staticIsSorted(alias cmp, L...) +{ + static if (L.length <= 1) + { + enum bool staticIsSorted = true; + } + else + { + // `L` is sorted if the both halves are sorted. + enum bool halves = staticIsSorted!(cmp, L[0 .. $ / 2]) + && staticIsSorted!(cmp, L[$ / 2 .. $]); + // Compare the boundary values of the havles. + enum result = cmp!(L[$ / 2], L[$ / 2 - 1]); + static if (is(typeof(result) == bool)) + { + enum bool staticIsSorted = !result && halves; + } + else + { + enum bool staticIsSorted = result >= 0 && halves; + } + } +} + +/// +pure nothrow @safe @nogc unittest +{ + enum cmp(T, U) = T.sizeof < U.sizeof; + static assert(staticIsSorted!(cmp)); + static assert(staticIsSorted!(cmp, byte)); + static assert(staticIsSorted!(cmp, byte, ubyte, short, uint)); + static assert(!staticIsSorted!(cmp, long, byte, ubyte, short, uint)); +} + +private pure nothrow @safe @nogc unittest +{ + enum cmp(int x, int y) = x - y; + static assert(staticIsSorted!(cmp)); + static assert(staticIsSorted!(cmp, 1)); + static assert(staticIsSorted!(cmp, 1, 2, 2)); + static assert(staticIsSorted!(cmp, 1, 2, 2, 4)); + static assert(staticIsSorted!(cmp, 1, 2, 2, 4, 8)); + static assert(!staticIsSorted!(cmp, 32, 2, 2, 4, 8)); + static assert(staticIsSorted!(cmp, 32, 32)); +} + +private pure nothrow @safe @nogc unittest +{ + enum cmp(int x, int y) = x < y; + static assert(staticIsSorted!(cmp)); + static assert(staticIsSorted!(cmp, 1)); + static assert(staticIsSorted!(cmp, 1, 2, 2)); + static assert(staticIsSorted!(cmp, 1, 2, 2, 4)); + static assert(staticIsSorted!(cmp, 1, 2, 2, 4, 8)); + static assert(!staticIsSorted!(cmp, 32, 2, 2, 4, 8)); + static assert(staticIsSorted!(cmp, 32, 32)); +} + +/** + * Params: + * T = A template. + * Args = The first arguments for $(D_PARAM T). + * + * Returns: $(D_PARAM T) with $(D_PARAM Args) applied to it as its first + * arguments. + */ +template ApplyLeft(alias T, Args...) +{ + alias ApplyLeft(U...) = T!(Args, U); +} + +/// +pure nothrow @safe @nogc unittest +{ + alias allAreIntegral = ApplyLeft!(allSatisfy, isIntegral); + static assert(allAreIntegral!(int, uint)); + static assert(!allAreIntegral!(int, float, uint)); +} + +/** + * Params: + * T = A template. + * Args = The last arguments for $(D_PARAM T). + * + * Returns: $(D_PARAM T) with $(D_PARAM Args) applied to it as itslast + * arguments. + */ +template ApplyRight(alias T, Args...) +{ + alias ApplyRight(U...) = T!(U, Args); +} + +/// +pure nothrow @safe @nogc unittest +{ + alias intIs = ApplyRight!(allSatisfy, int); + static assert(intIs!(isIntegral)); + static assert(!intIs!(isUnsigned)); +} diff --git a/source/tanya/meta/package.d b/source/tanya/meta/package.d index 4b74287..18edbc3 100644 --- a/source/tanya/meta/package.d +++ b/source/tanya/meta/package.d @@ -15,5 +15,5 @@ module tanya.meta; public import tanya.meta.metafunction; -public import tanya.meta.traits; +public import tanya.meta.trait; public import tanya.meta.transform; diff --git a/source/tanya/meta/traits.d b/source/tanya/meta/trait.d similarity index 99% rename from source/tanya/meta/traits.d rename to source/tanya/meta/trait.d index a15b5db..c4a79b8 100644 --- a/source/tanya/meta/traits.d +++ b/source/tanya/meta/trait.d @@ -12,10 +12,10 @@ * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/traits.d, - * tanya/meta/traits.d) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/meta/trait.d, + * tanya/meta/trait.d) */ -module tanya.meta.traits; +module tanya.meta.trait; import tanya.meta.metafunction; import tanya.meta.transform; @@ -631,7 +631,7 @@ pure nothrow @safe @nogc unittest static assert(!isType!T); static assert(isType!(T!())); static assert(!isType!5); - static assert(!isType!(tanya.meta.traits)); + static assert(!isType!(tanya.meta.trait)); } /** @@ -1598,7 +1598,7 @@ pure nothrow @safe unittest /** * Params: - * T = A function. + * F = A function. * * Returns $(D_KEYWORD true) if the $(D_PARAM T) is a nested function, * $(D_KEYWORD false) otherwise. diff --git a/source/tanya/meta/transform.d b/source/tanya/meta/transform.d index bdefd4e..ac6a773 100644 --- a/source/tanya/meta/transform.d +++ b/source/tanya/meta/transform.d @@ -17,7 +17,7 @@ */ module tanya.meta.transform; -import tanya.meta.traits; +import tanya.meta.trait; /** * Removes any type qualifiers from $(D_PARAM T).