From 41cca054a541c6727e08075409ab53aaee7749c9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 15 Jul 2012 00:48:06 +0200 Subject: [PATCH 1/3] std.typetuple docs: Use "template predicate". --- std/typetuple.d | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/std/typetuple.d b/std/typetuple.d index 4285c827499..2f89b0ede3c 100644 --- a/std/typetuple.d +++ b/std/typetuple.d @@ -8,6 +8,10 @@ * type tuple. TL[$(I lwr) .. $(I upr)] returns a new type * list that is a slice of the old one. * + * Several templates in this module use or operate on eponymous templates that + * take a single argument and evaluate to a boolean constant. Such templates + * are referred to as $(I template predicates). + * * References: * Based on ideas in Table 3.1 from * $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768, @@ -553,7 +557,8 @@ unittest } /** -Evaluates to $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])). +Tests whether all given items satisfy a template predicate, i.e. evaluates to +$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])). Example: ---- @@ -584,7 +589,8 @@ unittest } /** -Evaluates to $(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])). +Tests whether all given items satisfy a template predicate, i.e. evaluates to +$(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])). Example: ---- From 395e360d74552fabcd46a3ee0c692310db0341af Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 15 Jul 2012 00:49:28 +0200 Subject: [PATCH 2/3] Document non-short-circuiting behavior of allSatisfy/anySatisfy. --- std/typetuple.d | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/std/typetuple.d b/std/typetuple.d index 2f89b0ede3c..ce22cd49e20 100644 --- a/std/typetuple.d +++ b/std/typetuple.d @@ -560,6 +560,9 @@ unittest Tests whether all given items satisfy a template predicate, i.e. evaluates to $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])). +Evaluation is $(I not) short-circuited if a false result is encountered; the +template predicate must be instantiable with all the given items. + Example: ---- static assert(!allSatisfy!(isIntegral, int, double)); @@ -592,6 +595,9 @@ unittest Tests whether all given items satisfy a template predicate, i.e. evaluates to $(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])). +Evaluation is $(I not) short-circuited if a true result is encountered; the +template predicate must be instantiable with all the given items. + Example: ---- static assert(!anySatisfy!(isIntegral, string, double)); From 1c086dc002baf5afb2e8027876ad09d86ae19ca0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 15 Jul 2012 02:36:31 +0200 Subject: [PATCH 3/3] Added template{And, Or, Not}. Names in lowercase as per Andrei's request, see discussion in pull request #690. --- std/typetuple.d | 215 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 1 deletion(-) diff --git a/std/typetuple.d b/std/typetuple.d index ce22cd49e20..4fa607141f9 100644 --- a/std/typetuple.d +++ b/std/typetuple.d @@ -22,7 +22,9 @@ * * Copyright: Copyright Digital Mars 2005 - 2009. * License: Boost License 1.0. - * Authors: $(WEB digitalmars.com, Walter Bright) + * Authors: + * $(WEB digitalmars.com, Walter Bright), + * $(WEB klickverbot.at, David Nadlinger) * Source: $(PHOBOSSRC std/_typetuple.d) */ /* Copyright Digital Mars 2005 - 2009. @@ -817,3 +819,214 @@ unittest static assert(is(Filter!(isPointer, int, void*, char[], int*) == TypeTuple!(void*, int*))); static assert(is(Filter!isPointer == TypeTuple!())); } + + +/* + * Instantiates the given template with the given list of parameters. + * + * Used to work around syntactic limitations of D with regard to instantiating + * a template from a type tuple (e.g. T[0]!(...) is not valid) or a template + * returning another template (e.g. Foo!(Bar)!(Baz) is not allowed). + */ +// TODO: Consider publicly exposing this, maybe even if only for better +// understandability of error messages. +template Instantiate(alias Template, Params...) +{ + alias Template!Params Instantiate; +} + + +// Used in template predicate unit tests below. +version (unittest) +{ + template always(T...) + { + enum always = true; + } + + template never(T...) + { + enum never = false; + } + + template error(T...) + { + static assert(false, "Should never be instantiated."); + } +} + + +/** + * Negates the passed template predicate. + * + * Examples: + * --- + * alias templateNot!isPointer isNoPointer; + * static assert(!isNoPointer!(int*)); + * static assert(allSatisfy!(isNoPointer, string, char, float)); + * --- + */ +template templateNot(alias pred) +{ + template templateNot(T...) + { + enum templateNot = !pred!T; + } +} + +// Verify examples. +unittest +{ + import std.traits; + + alias templateNot!isPointer isNoPointer; + static assert(!isNoPointer!(int*)); + static assert(allSatisfy!(isNoPointer, string, char, float)); +} + +unittest +{ + foreach (T; TypeTuple!(int, staticMap, 42)) + { + static assert(!Instantiate!(templateNot!always, T)); + static assert(Instantiate!(templateNot!never, T)); + } +} + + +/** + * Combines several template predicates using logical AND, i.e. constructs a new + * predicate which evaluates to true for a given input T if and only if all of + * the passed predicates are true for T. + * + * The predicates are evaluated from left to right, aborting evaluation in a + * short-cut manner if a false result is encountered, in which case the latter + * instantiations do not need to compile. + * + * Examples: + * --- + * alias templateAnd!(isNumeric, templateNot!isUnsigned) storesNegativeNumbers; + * static assert(storesNegativeNumbers!int); + * static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint); + * + * // An empty list of predicates always yields true. + * alias templateAnd!() alwaysTrue; + * static assert(alwaysTrue!int); + * --- + */ +template templateAnd(Preds...) +{ + template templateAnd(T...) + { + static if (Preds.length == 0) + { + enum templateAnd = true; + } + else + { + static if (Instantiate!(Preds[0], T)) + alias Instantiate!(.templateAnd!(Preds[1 .. $]), T) templateAnd; + else + enum templateAnd = false; + } + } +} + +// Verify examples. +unittest +{ + alias templateAnd!(isNumeric, templateNot!isUnsigned) storesNegativeNumbers; + static assert(storesNegativeNumbers!int); + static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint); + + // An empty list of predicates always yields true. + alias templateAnd!() alwaysTrue; + static assert(alwaysTrue!int); +} + +unittest +{ + foreach (T; TypeTuple!(int, staticMap, 42)) + { + static assert(Instantiate!(templateAnd!(), T)); + static assert(Instantiate!(templateAnd!(always), T)); + static assert(Instantiate!(templateAnd!(always, always), T)); + static assert(!Instantiate!(templateAnd!(never), T)); + static assert(!Instantiate!(templateAnd!(always, never), T)); + static assert(!Instantiate!(templateAnd!(never, always), T)); + + static assert(!Instantiate!(templateAnd!(never, error), T)); + static assert(!is(typeof(Instantiate!(templateAnd!(always, error), T)))); + } +} + + +/** + * Combines several template predicates using logical OR, i.e. constructs a new + * predicate which evaluates to true for a given input T if and only at least + * one of the passed predicates is true for T. + * + * The predicates are evaluated from left to right, aborting evaluation in a + * short-cut manner if a true result is encountered, in which case the latter + * instantiations do not need to compile. + * + * Examples: + * --- + * alias templateOr!(isPointer, isUnsigned) isPtrOrUnsigned; + * static assert(isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*)); + * static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!string); + * + * // An empty list of predicates never yields true. + * alias templateOr!() alwaysFalse; + * static assert(!alwaysFalse!int); + * --- + */ +template templateOr(Preds...) +{ + template templateOr(T...) + { + static if (Preds.length == 0) + { + enum templateOr = false; + } + else + { + static if (Instantiate!(Preds[0], T)) + enum templateOr = true; + else + alias Instantiate!(.templateOr!(Preds[1 .. $]), T) templateOr; + } + } +} + +// Verify examples. +unittest +{ + alias templateOr!(isPointer, isUnsigned) isPtrOrUnsigned; + static assert(isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*)); + static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!string); + + // An empty list of predicates never yields true. + alias templateOr!() alwaysFalse; + static assert(!alwaysFalse!int); +} + +unittest +{ + foreach (T; TypeTuple!(int, staticMap, 42)) + { + static assert(Instantiate!(templateOr!(always), T)); + static assert(Instantiate!(templateOr!(always, always), T)); + static assert(Instantiate!(templateOr!(always, never), T)); + static assert(Instantiate!(templateOr!(never, always), T)); + static assert(!Instantiate!(templateOr!(), T)); + static assert(!Instantiate!(templateOr!(never), T)); + + static assert(Instantiate!(templateOr!(always, error), T)); + static assert(Instantiate!(templateOr!(never, always, error), T)); + // DMD @@BUG@@: Assertion fails for int, seems like a error gagging + // problem. The bug goes away when removing some of the other template + // instantiations in the module. + // static assert(!is(typeof(Instantiate!(templateOr!(never, error), T)))); + } +}