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