1 /** Various metaprogramming helpers. 2 * 3 * Authors: $(LINK2 https://github.com/epi, Adrian Matoga) 4 * Copyright: © 2016 Adrian Matoga 5 * License: $(LINK2 http://www.boost.org/users/license.html, BSL-1.0). 6 */ 7 module flod.meta; 8 9 package: 10 11 /// Used to compare alias lists. 12 struct Id(X...) {} 13 14 /// Tests if template `S` can be instantiated with argument list `A` and the instantiation is a type. 15 /// Workaround for https://issues.dlang.org/show_bug.cgi?id=15623 16 template isType(alias T, A...) { 17 bool impl() { return is(T!A); } 18 enum isType = impl(); 19 } 20 21 unittest { 22 struct NoFoo {} 23 24 struct HasFoo { 25 void foo() {} 26 } 27 28 struct CallsFoo(T) { 29 T t; 30 void run() { t.foo(); } 31 } 32 33 static assert(!isType!(CallsFoo, NoFoo)); 34 static assert( isType!(CallsFoo, HasFoo)); 35 } 36 37 /// 38 template str(W...) { 39 static if (W.length == 0) { 40 enum str = "()"; 41 } else static if (W.length > 1) { 42 enum str = str!(W[0]) ~ "," ~ str!(W[1 .. $]); 43 } else { 44 import std.traits : isExpressions; 45 static if (isExpressions!(W[0])) { 46 import std.conv : to; 47 enum str = to!string(W[0]); 48 } else { 49 import std.traits : fullyQualifiedName; 50 alias V = W[0]; 51 static if (is(typeof(V.str) : string)) 52 enum str = V.str; 53 else static if (__traits(compiles, fullyQualifiedName!V)) 54 enum str = fullyQualifiedName!V; 55 else static if (__traits(compiles, __traits(identifier, V))) 56 enum str = __traits(identifier, V); 57 else 58 enum str = V.stringof; 59 } 60 } 61 } 62 63 /// 64 template ReplaceWithMask(ulong mask, ReplacementForZeros, Types...) { 65 alias What = ReplacementForZeros; 66 import std.meta : AliasSeq; 67 static if (Types.length == 0) 68 alias ReplaceWithMask = AliasSeq!(); 69 else { 70 static if (mask & 1) 71 alias ReplaceWithMask = AliasSeq!(ReplaceWithMask!(mask >> 1, What, Types[0 .. $ - 1]), Types[$ - 1]); 72 else 73 alias ReplaceWithMask = AliasSeq!(ReplaceWithMask!(mask >> 1, What, Types[0 .. $ - 1]), What); 74 } 75 } 76 77 unittest { 78 static struct Empty {} 79 struct Z(Params...) {} 80 alias List = ReplaceWithMask!(0b011011, Empty, int, bool, float, uint, ulong, double); 81 static assert(is(Z!List == Z!(Empty, bool, float, Empty, ulong, double))); 82 } 83 84 /// Mix it in inside a `struct` definition to make the `struct` non-copyable. 85 mixin template NonCopyable() { 86 @disable this(this); 87 @disable void opAssign(typeof(this)); 88 } 89 90 /// Evaluates to true iff instances of `T` can be copied. 91 template isCopyable(T) { 92 enum isCopyable = is(typeof({ T a; T b = a; T c = b; })); 93 } 94 95 unittest { 96 static struct A {} 97 static struct B { @disable this(this); } 98 static assert( isCopyable!A); 99 static assert(!isCopyable!B); 100 } 101 102 /// Forwards to `std.algorithm.move` iff `t` is non-copyable. 103 auto moveIfNonCopyable(T, string file = __FILE__, int line = __LINE__)(auto ref T t) 104 { 105 import std.conv : to; 106 static if (isCopyable!T) { 107 return t; 108 } else { 109 import std.algorithm : move; 110 return move(t); 111 } 112 } 113 114 template tupleFromArray(T, T[] arr) { 115 import std.meta : AliasSeq; 116 static if (arr.length) 117 alias tupleFromArray = AliasSeq!(arr[0], tupleFromArray!(T, arr[1 .. $])); 118 else 119 alias tupleFromArray = AliasSeq!(); 120 }