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