Add template-time Set and set-theoretic metafunctions

This commit is contained in:
Eugen Wissner 2017-09-05 05:51:34 +02:00
parent d38e33593e
commit 520bd399a3
3 changed files with 337 additions and 172 deletions

View File

@ -112,7 +112,7 @@ pure nothrow @safe @nogc unittest
}
/**
* Zips one or more $(D_PSYMBOL AliasTuple)s with $(D_PARAM f).
* Zips one or more $(D_PSYMBOL Tuple)s with $(D_PARAM f).
*
* Given $(D_PARAM f) and tuples t1, t2, ..., tk, where tk[i] denotes the
* $(I i)-th element of the tuple $(I k)-th tuple, $(D_PSYMBOL ZipWith)
@ -137,7 +137,7 @@ pure nothrow @safe @nogc unittest
* Params:
* f = Some template that can be applied to the elements of
* $(D_PARAM Tuples).
* Tuples = $(D_PSYMBOL AliasTuple) instances.
* Tuples = $(D_PSYMBOL Tuple) instances.
*
* Returns: A sequence, whose $(I i)-th element contains the $(I i)-th element
* from each of the $(D_PARAM Tuples).
@ -145,7 +145,7 @@ pure nothrow @safe @nogc unittest
template ZipWith(alias f, Tuples...)
if (Tuples.length > 0
&& isTemplate!f
&& allSatisfy!(ApplyLeft!(isInstanceOf, AliasTuple), Tuples))
&& allSatisfy!(ApplyLeft!(isInstanceOf, Tuple), Tuples))
{
private template GetIth(size_t i, Args...)
{
@ -179,24 +179,24 @@ if (Tuples.length > 0
pure nothrow @safe @nogc unittest
{
alias Result1 = ZipWith!(AliasSeq,
AliasTuple!(1, 2),
AliasTuple!(5, 6),
AliasTuple!(9, 10));
Tuple!(1, 2),
Tuple!(5, 6),
Tuple!(9, 10));
static assert(Result1 == AliasSeq!(1, 5, 9, 2, 6, 10));
alias Result2 = ZipWith!(AliasSeq,
AliasTuple!(1, 2, 3),
AliasTuple!(4, 5));
Tuple!(1, 2, 3),
Tuple!(4, 5));
static assert(Result2 == AliasSeq!(1, 4, 2, 5));
alias Result3 = ZipWith!(AliasSeq, AliasTuple!(), AliasTuple!(4, 5));
alias Result3 = ZipWith!(AliasSeq, Tuple!(), Tuple!(4, 5));
static assert(Result3.length == 0);
}
/**
* Holds a typed sequence of template parameters.
*
* Different than $(D_PSYMBOL AliasSeq), $(D_PSYMBOL AliasTuple) doesn't unpack
* Different than $(D_PSYMBOL AliasSeq), $(D_PSYMBOL Tuple) doesn't unpack
* its template parameters automatically. Consider:
*
* ---
@ -211,7 +211,7 @@ pure nothrow @safe @nogc unittest
* Using $(D_PSYMBOL AliasSeq) template `A` gets 4 parameters instead of 2,
* because $(D_PSYMBOL AliasSeq) is just an alias for its template parameters.
*
* With $(D_PSYMBOL AliasTuple) it is possible to pass distinguishable
* With $(D_PSYMBOL Tuple) it is possible to pass distinguishable
* sequences of parameters to a template. So:
*
* ---
@ -220,15 +220,15 @@ pure nothrow @safe @nogc unittest
* static assert(Args.length == 2);
* }
*
* alias BInstance = B!(AliasTuple!(int, uint), AliasTuple!(float, double));
* alias BInstance = B!(Tuple!(int, uint), Tuple!(float, double));
* ---
*
* Params:
* Args = Elements of this $(D_PSYMBOL AliasTuple).
* Args = Elements of this $(D_PSYMBOL Tuple).
*
* See_Also: $(D_PSYMBOL AliasSeq).
*/
template AliasTuple(Args...)
template Tuple(Args...)
{
/// Elements in this tuple as $(D_PSYMBOL AliasSeq).
alias Seq = Args;
@ -240,9 +240,9 @@ template AliasTuple(Args...)
///
pure nothrow @safe @nogc unittest
{
alias A = AliasTuple!(short);
alias B = AliasTuple!(3, 8, 9);
alias C = AliasTuple!(A, B);
alias A = Tuple!(short);
alias B = Tuple!(3, 8, 9);
alias C = Tuple!(A, B);
static assert(C.length == 2);
@ -251,11 +251,175 @@ pure nothrow @safe @nogc unittest
static assert(B.length == 3);
static assert(B.Seq == AliasSeq!(3, 8, 9));
alias D = AliasTuple!();
alias D = Tuple!();
static assert(D.length == 0);
static assert(is(D.Seq == AliasSeq!()));
}
/**
* Unordered sequence of unique aliases.
*
* $(D_PARAM Args) can contain duplicates, but they will be filteredout, so
* $(D_PSYMBOL Set) contains only unique items. $(D_PSYMBOL isEqual) is used
* for determining if two items are equal.
*
* Params:
* Args = Elements of this $(D_PSYMBOL Tuple).
*/
template Set(Args...)
{
/// Elements in this set as $(D_PSYMBOL AliasSeq).
alias Seq = NoDuplicates!Args;
/// The length of the set.
enum size_t length = Seq.length;
}
///
pure nothrow @safe @nogc unittest
{
alias S1 = Set!(int, 5, 5, int, 4);
static assert(S1.length == 3);
}
/**
* Produces a $(D_PSYMBOL Set) containing all elements of the given
* $(D_PARAM Sets).
*
* Params:
* Sets = List of $(D_PSYMBOL Set) instances.
*
* Returns: Set-theoretic union of all $(D_PARAM Sets).
*
* See_Also: $(D_PSYMBOL Set).
*/
template Union(Sets...)
if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets))
{
private template Impl(Sets...)
{
static if (Sets.length == 0)
{
alias Impl = AliasSeq!();
}
else
{
alias Impl = AliasSeq!(Sets[0].Seq, Impl!(Sets[1 .. $]));
}
}
alias Union = Set!(Impl!Sets);
}
///
pure nothrow @safe @nogc unittest
{
alias S1 = Set!(2, 5, 8, 4);
alias S2 = Set!(3, 8, 4, 1);
static assert(Union!(S1, S2).Seq == AliasSeq!(2, 5, 8, 4, 3, 1));
}
/**
* Produces a $(D_PSYMBOL Set) that containing elements of
* $(D_INLINECODE Sets[0]) that are also elements of all other sets in
* $(D_PARAM Sets).
*
* Params:
* Sets = List of $(D_PSYMBOL Set) instances.
*
* Returns: Set-theoretic intersection of all $(D_PARAM Sets).
*
* See_Also: $(D_PSYMBOL Set).
*/
template Intersection(Sets...)
if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets))
{
private template Impl(Args...)
if (Args.length > 0)
{
alias Equal = ApplyLeft!(isEqual, Args[0]);
static if (Args.length == 1)
{
enum bool Impl = true;
}
else static if (!anySatisfy!(Equal, Args[1].Seq))
{
enum bool Impl = false;
}
else
{
enum bool Impl = Impl!(Args[0], Args[2 .. $]);
}
}
private enum bool FilterImpl(Args...) = Impl!(Args[0], Sets[1 .. $]);
static if (Sets.length == 0)
{
alias Intersection = Set!();
}
else
{
alias Intersection = Set!(Filter!(FilterImpl, Sets[0].Seq));
}
}
///
pure nothrow @safe @nogc unittest
{
alias S1 = Set!(2, 5, 8, 4);
alias S2 = Set!(3, 8, 4, 1);
static assert(Intersection!(S1, S2).Seq == AliasSeq!(8, 4));
static assert(Intersection!(S1).Seq == AliasSeq!(2, 5, 8, 4));
static assert(Intersection!().length == 0);
}
/**
* Produces a $(D_PSYMBOL Set) that contains all elements of
* $(D_PARAM S1) that are not members of $(D_PARAM S2).
*
* Params:
* S1 = A $(D_PSYMBOL Set).
* S2 = A $(D_PSYMBOL Set).
*
* Returns: Set-theoretic difference of two sets $(D_PARAM S1) and
* $(D_PARAM S2).
*
* See_Also: $(D_PSYMBOL Set).
*/
template Difference(alias S1, alias S2)
if (isInstanceOf!(Set, S1) && isInstanceOf!(Set, S2))
{
private template Impl(Args...)
{
alias Equal = ApplyLeft!(isEqual, Args[0]);
enum bool Impl = !anySatisfy!(Equal, S2.Seq);
}
static if (S1.length == 0)
{
alias Difference = Set!();
}
else static if (S2.length == 1)
{
alias Difference = S1;
}
else
{
alias Difference = Set!(Filter!(Impl, S1.Seq));
}
}
///
pure nothrow @safe @nogc unittest
{
alias S1 = Set!(2, 5, 8, 4);
alias S2 = Set!(3, 8, 4, 1);
static assert(Difference!(S1, S2).Seq == AliasSeq!(2, 5));
static assert(Difference!(S2, S1).Seq == AliasSeq!(3, 1));
static assert(Difference!(S1, Set!()).Seq == AliasSeq!(2, 5, 8, 4));
}
/**
* Tests whether $(D_INLINECODE Args[0]) is less than or equal to
* $(D_INLINECODE Args[1]) according to $(D_PARAM cmp).
@ -451,6 +615,9 @@ pure nothrow @safe @nogc unittest
* $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are
* considered to be not equal.
*
* If two items cannot be compared (for example comparing a type with a
* number), they are considered not equal.
*
* Params:
* Args = Two aliases to compare for equality.
*
@ -461,7 +628,8 @@ template isEqual(Args...)
if (Args.length == 2)
{
static if ((is(typeof(Args[0] == Args[1])) && (Args[0] == Args[1]))
|| is(Args[0] == Args[1]))
|| (isTypeTuple!Args && is(Args[0] == Args[1]))
|| isSame!Args)
{
enum bool isEqual = true;
}
@ -475,6 +643,8 @@ if (Args.length == 2)
pure nothrow @safe @nogc unittest
{
static assert(isEqual!(int, int));
static assert(isEqual!(8, 8));
static assert(!isEqual!(int, const(int)));
static assert(!isEqual!(5, int));
static assert(!isEqual!(5, 8));
}

View File

@ -416,6 +416,9 @@ version (TanyaPhobos)
EnumMembers,
classInstanceAlignment,
ifTestable,
FunctionTypeOf,
ReturnType,
TemplateOf,
isTypeTuple,
isExpressions;
}
@ -1873,11 +1876,149 @@ pure nothrow @safe @nogc unittest
}
}
deprecated("Use tanya.meta.transform.FunctionTypeOf instead")
alias FunctionTypeOf = tanya.meta.transform.FunctionTypeOf;
/**
* Params:
* F = A function.
*
* Returns: Type of the function $(D_PARAM F).
*/
template FunctionTypeOf(F...)
if (isCallable!F)
{
static if ((is(typeof(F[0]) T : T*) && is(T == function))
|| (is(F[0] T : T*) && is(T == function))
|| is(F[0] T == delegate)
|| is(typeof(F[0]) T == delegate)
|| is(F[0] T == function)
|| is(typeof(&F[0]) T == delegate)
|| (is(typeof(&F[0]) T : T*) && is(T == function)))
{
alias FunctionTypeOf = T;
}
else
{
alias FunctionTypeOf = FunctionTypeOf!(F[0].opCall);
}
}
deprecated("Use tanya.meta.transform.ReturnType instead")
alias ReturnType = tanya.meta.transform.ReturnType;
///
pure nothrow @safe @nogc unittest
{
static assert(is(FunctionTypeOf!(void function()) == function));
static assert(is(FunctionTypeOf!(() {}) == function));
}
private pure nothrow @safe @nogc unittest
{
static assert(is(FunctionTypeOf!(void delegate()) == function));
static void staticFunc()
{
}
auto functionPointer = &staticFunc;
static assert(is(FunctionTypeOf!staticFunc == function));
static assert(is(FunctionTypeOf!functionPointer == function));
void func()
{
}
auto dg = &func;
static assert(is(FunctionTypeOf!func == function));
static assert(is(FunctionTypeOf!dg == function));
interface I
{
@property int prop();
}
static assert(is(FunctionTypeOf!(I.prop) == function));
struct S
{
void opCall()
{
}
}
class C
{
static void opCall()
{
}
}
S s;
static assert(is(FunctionTypeOf!s == function));
static assert(is(FunctionTypeOf!C == function));
static assert(is(FunctionTypeOf!S == function));
}
private pure nothrow @safe @nogc unittest
{
struct S2
{
@property int opCall()
{
return 0;
}
}
S2 s2;
static assert(is(FunctionTypeOf!S2 == function));
static assert(is(FunctionTypeOf!s2 == function));
}
/**
* Params:
* F = A callable object.
*
* Returns: Return type of $(D_PARAM F).
*/
template ReturnType(F...)
if (isCallable!F)
{
static if (is(FunctionTypeOf!(F[0]) T == return))
{
alias ReturnType = T;
}
else
{
static assert(false, "Argument is not a callable");
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(is(ReturnType!(int delegate()) == int));
static assert(is(ReturnType!(bool function()) == bool));
}
/**
* Determines the template $(D_PARAM T) is an instance of.
*
* Params:
* T = Template instance.
*
* Returns: Template $(D_PARAM T) is an instance of.
*/
alias TemplateOf(alias T : Base!Args, alias Base, Args...) = Base;
///
pure nothrow @safe @nogc unittest
{
struct S(T)
{
}
static assert(isSame!(TemplateOf!(S!int), S));
static void func(T)()
{
}
static assert(isSame!(TemplateOf!(func!int), func));
template T(U)
{
}
static assert(isSame!(TemplateOf!(T!int), T));
}
/**
* Returns the mangled name of the symbol $(D_PARAM T).
@ -2392,7 +2533,7 @@ if (isCallable!F)
{
attrs |= FunctionAttribute.shared_;
}
else static if (a == "system")
else static if (a == "@system")
{
attrs |= FunctionAttribute.system;
}

View File

@ -6,7 +6,8 @@
* Type transformations.
*
* Templates in this module can be used to modify type qualifiers or transform
* types.
* types. They take some type as argument and return a different type after
* perfoming the specified transformation.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
@ -29,9 +30,6 @@ version (TanyaPhobos)
KeyType,
ValueType,
Promoted,
FunctionTypeOf,
ReturnType,
TemplateOf,
InoutOf,
ConstOf,
SharedOf,
@ -499,150 +497,6 @@ pure nothrow @safe @nogc unittest
static assert(is(Promoted!(shared bool) == shared int));
}
/**
* Params:
* F = A function.
*
* Returns: Type of the function $(D_PARAM F).
*/
template FunctionTypeOf(F...)
if (isCallable!F)
{
static if ((is(typeof(F[0]) T : T*) && is(T == function))
|| (is(F[0] T : T*) && is(T == function))
|| is(F[0] T == delegate)
|| is(typeof(F[0]) T == delegate)
|| is(F[0] T == function)
|| is(typeof(&F[0]) T == delegate)
|| (is(typeof(&F[0]) T : T*) && is(T == function)))
{
alias FunctionTypeOf = T;
}
else
{
alias FunctionTypeOf = FunctionTypeOf!(F[0].opCall);
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(is(FunctionTypeOf!(void function()) == function));
static assert(is(FunctionTypeOf!(() {}) == function));
}
private pure nothrow @safe @nogc unittest
{
static assert(is(FunctionTypeOf!(void delegate()) == function));
static void staticFunc()
{
}
auto functionPointer = &staticFunc;
static assert(is(FunctionTypeOf!staticFunc == function));
static assert(is(FunctionTypeOf!functionPointer == function));
void func()
{
}
auto dg = &func;
static assert(is(FunctionTypeOf!func == function));
static assert(is(FunctionTypeOf!dg == function));
interface I
{
@property int prop();
}
static assert(is(FunctionTypeOf!(I.prop) == function));
struct S
{
void opCall()
{
}
}
class C
{
static void opCall()
{
}
}
S s;
static assert(is(FunctionTypeOf!s == function));
static assert(is(FunctionTypeOf!C == function));
static assert(is(FunctionTypeOf!S == function));
}
private pure nothrow @safe @nogc unittest
{
struct S2
{
@property int opCall()
{
return 0;
}
}
S2 s2;
static assert(is(FunctionTypeOf!S2 == function));
static assert(is(FunctionTypeOf!s2 == function));
}
/**
* Params:
* F = A callable object.
*
* Returns: Return type of $(D_PARAM F).
*/
template ReturnType(F...)
if (isCallable!F)
{
static if (is(FunctionTypeOf!(F[0]) T == return))
{
alias ReturnType = T;
}
else
{
static assert(false, "Argument is not a callable");
}
}
///
pure nothrow @safe @nogc unittest
{
static assert(is(ReturnType!(int delegate()) == int));
static assert(is(ReturnType!(bool function()) == bool));
}
/**
* Determines the template $(D_PARAM T) is an instance of.
*
* Params:
* T = Template instance.
*
* Returns: Template $(D_PARAM T) is an instance of.
*/
alias TemplateOf(alias T : Base!Args, alias Base, Args...) = Base;
///
pure nothrow @safe @nogc unittest
{
struct S(T)
{
}
static assert(isSame!(TemplateOf!(S!int), S));
static void func(T)()
{
}
static assert(isSame!(TemplateOf!(func!int), func));
template T(U)
{
}
static assert(isSame!(TemplateOf!(T!int), T));
}
/**
* Adds $(D_KEYWORD inout) qualifier to the type $(D_PARAM T).
*