1 /// Comptime algorithm templates for working with `AliasSeq`. 2 module tern.meta; 3 4 // TODO: Function map try reinterpret 5 public import std.meta : Alias, AliasSeq, aliasSeqOf, Erase, EraseAll, NoDuplicates, Stride, 6 DerivedToFront, MostDerived, Repeat, Replace, ReplaceAll, Reverse, staticSort, 7 templateAnd, templateNot, templateOr, ApplyLeft, ApplyRight; 8 import tern.traits; 9 import std.string; 10 import std.conv; 11 12 public template seqLoad(A...) 13 { 14 auto seqLoad(size_t index) 15 { 16 switch (index) 17 { 18 static foreach (j, B; A) 19 { 20 mixin("case "~j.to!string~": 21 return A["~j.to!string~"];"); 22 } 23 default: assert(0); 24 } 25 } 26 } 27 28 /// Checks if an `AliasSeq` contains an alias. 29 enum seqContains(A...) = 30 { 31 static if (A.length != 0) 32 static foreach (C; A[1..$]) 33 { 34 static if (isSame!(C, A[0])) 35 return true; 36 } 37 return false; 38 }(); 39 40 public template seqIndexOf(A...) 41 { 42 enum seqIndexOf = 43 { 44 static if (A.length != 0) 45 static foreach (i, C; A[1..$]) 46 { 47 static if (isSame!(C, A[0])) 48 return i; 49 } 50 return -1; 51 }(); 52 } 53 54 /// Filters over an `AliasSeq` based on a predicate. 55 public template seqFilter(A...) 56 { 57 alias seqFilter = AliasSeq!(); 58 alias F = A[0]; 59 60 static if (A.length != 0) 61 static foreach (B; A[1..$]) 62 { 63 static if (F!B) 64 seqFilter = AliasSeq!(seqFilter, B); 65 } 66 } 67 68 /// Filters over an `AliasSeq` based on a string predicate. 69 public template seqFilter(string F, A...) 70 { 71 alias seqFilter = AliasSeq!(); 72 73 private template filter(size_t I, alias X) 74 { 75 static if (mixin(F)) 76 alias filter = X; 77 else 78 alias filter = AliasSeq!(); 79 } 80 81 static foreach (i, B; A) 82 seqFilter = AliasSeq!(seqFilter, filter!(i, B)); 83 } 84 85 /// Maps a template over an `AliasSeq`, returning an `AliasSeq` of all of the return values. 86 public template seqMap(A...) 87 { 88 alias seqMap = AliasSeq!(); 89 alias F = A[0]; 90 91 static if (A.length != 0) 92 static foreach (B; A[1..$]) 93 seqMap = AliasSeq!(seqMap, F!B); 94 } 95 96 /// Maps a string over an `AliasSeq`, returning an `AliasSeq` of all of the return values. 97 public template seqMap(string F, A...) 98 { 99 alias seqMap = AliasSeq!(); 100 101 private template map(size_t I, alias X) 102 { 103 static if (__traits(compiles, { alias map = mixin(F); })) 104 alias map = mixin(F); 105 else 106 enum map = mixin(F); 107 } 108 109 static foreach (i, B; A) 110 seqMap = AliasSeq!(seqMap, map!(i, B)); 111 } 112 113 /// True if all elements in `A` meet the first given predicate. 114 public enum seqAny(A...) = 115 { 116 return seqFilter!A.length == A.length - 1; 117 }(); 118 119 /// True if any elements in `A` meet the first given predicate. 120 public enum seqAny(A...) = 121 { 122 return seqFilter!A.length != 0; 123 }(); 124 125 /// Creates a string representing `A` using the given separator. 126 enum seqStringJoin(string SEPARATOR, A...) = 127 { 128 pragma(msg, A); 129 static if (A.length == 0) 130 return ""; 131 132 string ret; 133 foreach (i, B; A) 134 { 135 static if (__traits(compiles, { enum _ = B; })) 136 ret ~= B.to!string~(i == A.length - 1 ? null : SEPARATOR); 137 else 138 ret ~= B.stringof~(i == A.length - 1 ? null : SEPARATOR); 139 } 140 return ret[0..$]; 141 }(); 142 143 /// Checks if two aliases are identical. 144 // Ripped from `std.meta`. 145 public template isSame(alias A, alias B) 146 { 147 static if (!is(typeof(&A && &B)) // at least one is an rvalue 148 && __traits(compiles, { enum isSame = A == B; })) // c-t comparable 149 enum isSame = A == B; 150 else 151 enum isSame = __traits(isSame, A, B) || A.stringof == B.stringof; 152 } 153 154 /** 155 * Generates a random boolean with the odds `1/max`. 156 * 157 * Params: 158 * max = Maximum odds, this is what the chance is out of. 159 */ 160 public alias randomBool(uint max, uint seed = uint.max, uint R0 = __LINE__, string R1 = __TIMESTAMP__, string R2 = __FILE_FULL_PATH__, string R3 = __FUNCTION__) 161 = Alias!(random!(uint, 0, max, seed, R0, R1, R2, R3) == 0); 162 163 /** 164 * Generates a random floating point value. 165 * 166 * Params: 167 * min = Minimum value. 168 * max = Maximum value. 169 * seed = The seed to generate with, useful if you do multiple random generations in one line, as it causes entropy. 170 */ 171 public template random(T, T min, T max, uint seed = uint.max, uint R0 = __LINE__, string R1 = __TIMESTAMP__, string R2 = __FILE_FULL_PATH__, string R3 = __FUNCTION__) 172 if (is(T == float) || is(T == double)) 173 { 174 pure T random() 175 { 176 return random!(ulong, cast(ulong)(min * cast(T)1000), cast(ulong)(max * cast(T)1000), seed, R0, R1, R2, R3) / cast(T)1000; 177 } 178 } 179 180 /** 181 * Generates a random integral value. 182 * 183 * Params: 184 * min = Minimum value. 185 * max = Maximum value. 186 * seed = The seed to generate with, useful if you do multiple random generations in one line, as it causes entropy. 187 */ 188 public template random(T, T min, T max, uint seed = uint.max, uint R0 = __LINE__, string R1 = __TIMESTAMP__, string R2 = __FILE_FULL_PATH__, string R3 = __FUNCTION__) 189 if (isIntegral!T) 190 { 191 pure T random() 192 { 193 static if (min == max) 194 return min; 195 196 ulong s0 = (seed * R0) || 1; 197 ulong s1 = (seed * R0) || 1; 198 ulong s2 = (seed * R0) || 1; 199 200 static foreach (c; R1) 201 s0 *= (c * (R0 ^ seed)) || 1; 202 static foreach (c; R2) 203 s1 *= (c * (R0 - seed)) || 1; 204 static foreach (c; R3) 205 s2 *= (c * (R0 ^ seed)) || 1; 206 207 ulong o = s0 + s1 + s2; 208 return min + (cast(T)o % (max - min)); 209 } 210 }