1 module nxt.meta_ex; 2 3 @safe: 4 5 import std.meta : AliasSeq, aliasSeqOf; 6 7 pure nothrow @safe @nogc unittest { 8 import std.range : iota; 9 foreach (_; aliasSeqOf!(iota(10))) 10 { 11 // pragma(msg, i); 12 } 13 } 14 15 /** 16 See_Also: http://forum.dlang.org/post/sulxqtfprmkeekjatqup@forum.dlang.org 17 */ 18 template Merge1(A...) 19 if (!(A.length & 1)) 20 { 21 static if (A.length == 0) 22 { 23 alias Merge1 = AliasSeq!(); 24 } 25 else 26 { 27 alias Left = A[0 .. $ / 2]; 28 alias Right = A[$ / 2 .. $]; 29 alias Merge1 = AliasSeq!(Left[0], Right[0], Merge1!(Left[1 .. $], Right[1 .. $])); 30 } 31 } 32 33 pure nothrow @safe @nogc unittest { 34 struct S(A...) {} // needed to reliably compare AliasSeq's for equality 35 36 alias first = AliasSeq!(int, string, bool); 37 alias second = AliasSeq!("abc", "def", "ghi"); 38 alias third = Merge1!(first, second); 39 40 static assert(is(S!third == S!(int, "abc", 41 string, "def", 42 bool, "ghi"))); 43 } 44 45 /** 46 See_Also: http://forum.dlang.org/post/sulxqtfprmkeekjatqup@forum.dlang.org 47 */ 48 template Merge(A...) 49 { 50 template With(B...) 51 { 52 static if (A.length == 0 || 53 B.length == 0) 54 alias With = AliasSeq!(A, B); // or static assert(0) if you require equal lengths 55 else 56 alias With = AliasSeq!(A[0], B[0], Merge!(A[1 .. $]).With!(B[1 .. $])); 57 } 58 } 59 60 pure nothrow @safe @nogc unittest { 61 struct S(A...) {} // needed to reliably compare AliasSeq's for equality 62 63 alias first = AliasSeq!(int, string, bool); 64 alias second = AliasSeq!("abc", "def", "ghi"); 65 alias third = Merge!first.With!second; 66 67 static assert(is(S!third == S!(int, "abc", 68 string, "def", 69 bool, "ghi"))); 70 71 alias fourth = Merge!(first[0 .. 2]).With!second; 72 73 static assert(is(S!fourth == S!(int, "abc", 74 string, "def", 75 "ghi"))); 76 } 77 78 /** Mixin for generating `struct` member `byRef`. 79 See_Also: http://forum.dlang.org/post/o0vk14$2j89$1@digitalmars.com 80 */ 81 mixin template RvalueRef() 82 { 83 alias T = typeof(this); 84 static assert (is(T == struct)); 85 86 @nogc @safe 87 ref const(T) byRef() const return => this; 88 } 89 90 pure nothrow @safe @nogc unittest { 91 struct Vector 92 { 93 float x, y; 94 mixin RvalueRef; 95 } 96 97 void useVector(ref const Vector pos) {} 98 99 Vector v = Vector(42, 23); 100 101 useVector(v); // works 102 useVector(Vector(42, 23).byRef); // works as well, and use the same function 103 } 104 105 // Use same as staticIndexOf 106 template staticAssignableTypeIndexOf(U) 107 { 108 static auto f(U)() 109 { 110 import std.traits : isAssignable; 111 static foreach (i, T; Types) 112 static if (isAssignable!(T, U)) 113 return i; 114 return 0; 115 } 116 enum canStore = f!U; 117 } 118 119 import std.functional : unaryFun; 120 121 /** Returns: `xs` forwarded through calls to `fun` and packed into a `std.typecons.Tuple`. 122 * 123 * See_Also: https://forum.dlang.org/post/zjxmreegqkxgdzvihvyk@forum.dlang.org 124 */ 125 auto forwardMap(alias fun, Ts...)(Ts xs) 126 if (is(typeof(unaryFun!(fun)))) 127 { 128 import std.meta : staticMap; 129 alias MappedTypeOf(T) = typeof(fun(T.init)); 130 alias NewTypes = staticMap!(MappedTypeOf, Ts); 131 132 import std.typecons : Tuple; 133 Tuple!NewTypes ys = void; 134 135 alias fun_ = unaryFun!(fun); 136 137 import core.lifetime : emplace; 138 static foreach (immutable i, x; xs) 139 emplace(&ys[i], fun_(x)); 140 141 return ys; 142 } 143 144 pure @safe unittest { 145 import std.typecons : Tuple; 146 alias X = Tuple!(int, float, double); 147 auto x = X(42, 42f, 42); 148 auto y = forwardMap!(_ => _ + 1)(x.tupleof); 149 static assert(is(typeof(x) == typeof(y))); 150 assert(y == X(43, 43f, 43)); 151 } 152 153 /** Flattens a list `Values` of ranges and non ranges. 154 * 155 * If a type is a range then its `ElementType` is used. 156 */ 157 template FlattenedRanges(Values...) 158 { 159 import std.meta : AliasSeq; 160 static if (Values.length) 161 { 162 import std.range.primitives : isInputRange; 163 alias Head = Values[0]; 164 alias Tail = Values[1 .. $]; 165 static if (isInputRange!Head) 166 { 167 import std.range.primitives : ElementType; 168 alias FlattenedRanges = FlattenedRanges!(ElementType!Head, FlattenedRanges!Tail); 169 } 170 else 171 alias FlattenedRanges = AliasSeq!(Head, FlattenedRanges!Tail); 172 } 173 else 174 alias FlattenedRanges = AliasSeq!(); 175 } 176 177 /// 178 @safe unittest { 179 import std.algorithm : filter; 180 import std.meta : AliasSeq; 181 182 alias R1 = typeof([1, 2, 3].filter!"true"); 183 alias R2 = typeof([1.0, 2.0, 3.0]); 184 185 static assert(is(FlattenedRanges!(int, double) == AliasSeq!(int, double))); 186 static assert(is(FlattenedRanges!(int, R1, R2) == AliasSeq!(int, int, double))); 187 188 import std.traits : CommonType; 189 190 static assert(is(CommonType!(FlattenedRanges!(int, R1, R2, float)) == double)); 191 } 192 193 /** Returns the types of all values given. 194 * 195 * If a `T` is an expression it is resolved with `typeof` else it is just 196 * appended. 197 * 198 * Returns: `AliasSeq` of the resulting types 199 */ 200 template TypesOf(Values...) 201 { 202 import std.meta : AliasSeq; 203 import std.traits : isExpressions; 204 static if (Values.length) 205 { 206 static if (isExpressions!(Values[0])) 207 alias T = typeof(Values[0]); 208 else 209 alias T = Values[0]; 210 alias TypesOf = AliasSeq!(T, TypesOf!(Values[1 .. $])); 211 } 212 else 213 alias TypesOf = AliasSeq!(); 214 } 215 216 /// 217 pure nothrow @safe @nogc unittest { 218 import std.meta : AliasSeq; 219 static assert(is(TypesOf!("hello", 1, 2, 3.0, real) == 220 AliasSeq!(string, int, int, double, real))); 221 } 222 223 /** Can be used to construct a meta function that checks if a symbol is of a type. 224 */ 225 template typeOf(T) 226 { 227 auto typeOf(U)(U) => is(U == T); 228 enum typeOf(alias a) = typeOf!T(a); 229 } 230 231 /// 232 pure nothrow @safe @nogc unittest { 233 import std.meta : allSatisfy; 234 static assert(typeOf!int(3)); 235 static assert(allSatisfy!(typeOf!int, 3)); 236 } 237 238 template from(string moduleName) 239 { 240 mixin("import nxt.from = " ~ moduleName ~ ";"); 241 }