1 /** Additions to $(STDMODULE _traits). 2 3 Copyright: Denis Shelomovskij 2011-2013 4 5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 7 Authors: Denis Shelomovskij 8 */ 9 module unstd.traits; 10 11 12 public import std.traits; 13 14 import unstd.generictuple; 15 import std.typecons: tuple; 16 17 18 // https://github.com/D-Programming-Language/phobos/pull/776 19 /** 20 Returns the element type of an array. 21 22 For ranges, see also 23 $(STDREF range, ElementEncodingType). 24 */ 25 alias ArrayElementType(T : T[]) = T; 26 27 /// 28 unittest 29 { 30 static assert( is(ArrayElementType!(int[]) == int)); 31 static assert(is(ArrayElementType!(int[7][8]) == int[7])); 32 static assert(is(ArrayElementType!string == immutable(char))); 33 } 34 35 unittest 36 { 37 static assert( is(ArrayElementType!(long[0]) == long)); 38 static assert(is(ArrayElementType!(int[0][]) == int[0])); 39 static assert(is(ArrayElementType!(int[][0]) == int[])); 40 41 static assert(!is(ArrayElementType!int)); 42 } 43 44 45 /** 46 Gets the rank (number of dimensions) of a static array type. 47 48 If $(D T) isn't a static array assumes it to be a $(I zero-dimensional) 49 static array with single element and returns zero. 50 */ 51 template staticArrayDims(T) 52 { 53 static if(isStaticArray!T) 54 enum staticArrayDims = 1 + staticArrayDims!(ArrayElementType!T); 55 else 56 enum staticArrayDims = 0; 57 } 58 59 /// 60 unittest 61 { 62 static assert(staticArrayDims!int == 0); 63 static assert(staticArrayDims!(int[]) == 0); 64 static assert(staticArrayDims!(int[0]) == 1); 65 static assert(staticArrayDims!(int[7][8]) == 2); 66 static assert(staticArrayDims!(int[0][]) == 0); 67 static assert(staticArrayDims!(int[][0]) == 1); 68 } 69 70 unittest 71 { 72 static assert(staticArrayDims!string == 0); 73 static assert(staticArrayDims!(int[0][0]) == 2); 74 } 75 76 77 /** 78 Gets the element type of the innermost array in a multidimensional static array type. 79 Considers $(D T) to be an $(D n)-dimensional static array type. 80 81 If $(D T) isn't a static array assumes it to be a $(I zero-dimensional) 82 static array with single element and returns $(D T). 83 */ 84 template MultidimStaticArrayElementType(T, size_t n = staticArrayDims!T) 85 { 86 static assert(staticArrayDims!T >= n, "Not enough static array dimensions"); 87 static if(n) 88 alias MultidimStaticArrayElementType = MultidimStaticArrayElementType!(ArrayElementType!T, n-1); 89 else 90 alias MultidimStaticArrayElementType = T; 91 } 92 93 /// 94 unittest 95 { 96 static assert(is(MultidimStaticArrayElementType!int == int)); 97 static assert(is(MultidimStaticArrayElementType!(int[]) == int[])); 98 static assert(is(MultidimStaticArrayElementType!(int[0]) == int)); 99 static assert(!__traits(compiles, MultidimStaticArrayElementType!(int[7][8], 3))); 100 static assert(is(MultidimStaticArrayElementType!(int[7][8]) == int)); 101 static assert(is(MultidimStaticArrayElementType!(int[7][8], 1) == int[7])); 102 static assert(is(MultidimStaticArrayElementType!(int[7][8], 0) == int[7][8])); 103 static assert(is(MultidimStaticArrayElementType!(int[0][]) == int[0][])); 104 static assert(is(MultidimStaticArrayElementType!(int[][0]) == int[])); 105 } 106 107 unittest 108 { 109 static assert(is(MultidimStaticArrayElementType!string == string)); 110 } 111 112 113 /** 114 Calculates the total element count of a multidimensional static array. 115 Considers $(D T) to be an $(D n)-dimensional static array type. 116 117 If $(D T) isn't a static array assumes it to be a $(I zero-dimensional) 118 static array with single element and returns 1. 119 */ 120 template multidimStaticArrayElementCount(T, size_t n = staticArrayDims!T) 121 { 122 static assert(staticArrayDims!T >= n, "Not enough static array dimensions"); 123 enum multidimStaticArrayElementCount = T.sizeof / MultidimStaticArrayElementType!(T, n).sizeof; 124 } 125 126 /// 127 unittest 128 { 129 static assert(multidimStaticArrayElementCount!int == 1); 130 static assert(multidimStaticArrayElementCount!(int[]) == 1); 131 static assert(multidimStaticArrayElementCount!(int[0]) == 0); 132 static assert(!__traits(compiles, multidimStaticArrayElementCount!(int[7][8], 3))); 133 static assert(multidimStaticArrayElementCount!(int[7][8]) == 7 * 8); 134 static assert(multidimStaticArrayElementCount!(int[7][8], 1) == 8); 135 static assert(multidimStaticArrayElementCount!(int[7][8], 0) == 1); 136 static assert(multidimStaticArrayElementCount!(int[0][]) == 1); 137 static assert(multidimStaticArrayElementCount!(int[][0]) == 0); 138 } 139 140 unittest 141 { 142 static assert(multidimStaticArrayElementCount!string == 1); 143 } 144 145 146 /** 147 Get, as an expression tuple, multidimensional static array lengths considering 148 $(D T) to be $(D n)-dimensioanl static array. 149 */ 150 template multidimStaticArrayLengths(T, size_t n = staticArrayDims!T) 151 { 152 static assert(staticArrayDims!T >= n, "Not enough static array dimensions"); 153 154 static if(n) 155 alias multidimStaticArrayLengths = expressionTuple!(T.length, multidimStaticArrayLengths!(ArrayElementType!T, n-1)); 156 else 157 alias multidimStaticArrayLengths = expressionTuple!(); 158 } 159 160 /// 161 unittest 162 { 163 alias e1 = multidimStaticArrayLengths!(int[7][8]); 164 static assert(e1.length == 2 && e1[0] == 8 && e1[1] == 7); 165 166 alias e2 = multidimStaticArrayLengths!(int[7][8], 1); 167 static assert(e2.length == 1 && e2[0] == 8); 168 static assert(multidimStaticArrayLengths!(int[7][8], 0).length == 0); 169 } 170 171 unittest 172 { 173 static assert(multidimStaticArrayLengths!int.length == 0); 174 static assert(multidimStaticArrayLengths!(int[]).length == 0); 175 static assert(multidimStaticArrayLengths!string.length == 0); 176 static assert(multidimStaticArrayLengths!(int[0]) == expressionTuple!(0)); 177 static assert(!__traits(compiles, multidimStaticArrayLengths!(int[7][8], 3))); 178 static assert(multidimStaticArrayLengths!(int[7][8]) == expressionTuple!(8, 7)); 179 static assert(multidimStaticArrayLengths!(int[7][8], 1) == expressionTuple!(8)); 180 static assert(multidimStaticArrayLengths!(int[7][8], 0).length == 0); 181 static assert(multidimStaticArrayLengths!(int[0][]).length == 0); 182 static assert(multidimStaticArrayLengths!(int[][0]) == expressionTuple!(0)); 183 } 184 185 186 /// Detect whether tuple $(D A) is $(D PackedGenericTuple). 187 enum isPackedTuple(alias A) = __traits(compiles, A.Tuple); 188 189 /// ditto 190 enum isPackedTuple(A) = false; 191 192 193 /** 194 Get all types $(D T) include except $(D Extracted) without duplicates 195 in such order that every compound type precedes types it includes. 196 */ 197 template ExtractTypes(T, Extracted...) if(isTypeTuple!Extracted) 198 { 199 static if(staticIndexOf!(T, Extracted) != -1) 200 { 201 alias ExtractTypes = TypeTuple!(); 202 } 203 else 204 { 205 template Extract(U) 206 { 207 alias Extract = .ExtractTypes!(U, Extracted, T); 208 } 209 210 static if(is(PointerTarget!T PT)) 211 { 212 alias ExtractTypes = TypeTuple!(T, Extract!PT); 213 } 214 else static if(__traits(isScalar, T)) 215 { 216 alias ExtractTypes = TypeTuple!T; 217 } 218 else static if(is(T == struct) || is(T == class) || is(T == union)) 219 { 220 alias ExtractTypes = TypeTuple!(T, NoDuplicates!(MapTuple!(Extract, FieldTypeTuple!T))); 221 } 222 else static if(isArray!T) 223 { 224 alias ExtractTypes = TypeTuple!(T, Extract!(ArrayElementType!T)); 225 } 226 else 227 static assert(0); 228 } 229 } 230 231 /// 232 unittest 233 { 234 static assert(is(ExtractTypes!int == TypeTuple!int)); 235 static assert(is(ExtractTypes!(int*) == TypeTuple!(int*, int))); 236 static assert(is(ExtractTypes!(int*, int) == TypeTuple!(int*))); 237 238 static struct S1 { int i; real r; } 239 static assert(is(ExtractTypes!S1 == TypeTuple!(S1, int, real))); 240 static assert(is(ExtractTypes!(S1, int) == TypeTuple!(S1, real))); 241 242 static struct S2 243 { 244 int* iptr; 245 S1* s1ptr1, s1ptr2; 246 S2[] s2darr; 247 S2[3]* s2sarr; 248 } 249 static assert(is(ExtractTypes!S2 == TypeTuple!( 250 S2, // for `S2` itself 251 int*, int, // for `int*` 252 S1*, S1, real, // for `S1*` 253 S2[], // for `S2[]` 254 S2[3]*, S2[3] // for `S2[3]*` 255 ))); 256 } 257 258 unittest 259 { 260 static assert(!__traits(compiles, ExtractTypes!(int*, 0))); 261 262 static struct S1 { int i; real r; } 263 264 static class C { real n; } 265 static assert(is(ExtractTypes!C == TypeTuple!(C, real))); 266 267 static struct S3 { C c; S1* s1ptr1, s1ptr2; C* cptr; } 268 static assert(is(ExtractTypes!S3 == TypeTuple!(S3, C, real, S1*, S1, int, C*))); 269 } 270 271 272 /** 273 true iff $(D T) is a type. Usable for analysing generic tuples. 274 */ 275 enum isType(T) = true; 276 277 /// ditto 278 enum isType(alias T) = false; 279 280 /// 281 unittest 282 { 283 static assert(isType!int && isType!string); 284 static assert(!isType!0 && !isType!"str"); 285 static assert(!isType!isType); 286 } 287 288 unittest 289 { 290 static assert(isType!(int[])); 291 static assert(isType!(TypeTuple!string)); 292 static assert(!__traits(compiles, isType!())); 293 static assert(!__traits(compiles, isType!(int, string))); 294 295 static assert(!isType!'a'); 296 297 static @property void __vp() { } 298 static @property int __ip() { return 0; } 299 static assert(!isType!(__vp)); 300 static assert(!isType!(__ip)); 301 302 static void __vf() { } 303 static int __if() { return 0; } 304 //static assert(!isType!(__vf())); //FIXME 305 static assert(!isType!(__if())); 306 }