1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * Type transformations. 7 * 8 * Templates in this module can be used to modify type qualifiers or transform 9 * types. They take some type as argument and return a different type after 10 * perfoming the specified transformation. 11 * 12 * Copyright: Eugene Wissner 2017-2020. 13 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 14 * Mozilla Public License, v. 2.0). 15 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 16 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/transform.d, 17 * tanya/meta/transform.d) 18 */ 19 module tanya.meta.transform; 20 21 import tanya.meta.metafunction; 22 import tanya.meta.trait; 23 24 /** 25 * Removes any type qualifiers from $(D_PARAM T). 26 * 27 * Removed qualifiers are: 28 * $(UL 29 * $(LI const) 30 * $(LI immutable) 31 * $(LI inout) 32 * $(LI shared) 33 * ) 34 * and combinations of these. 35 * 36 * If the type $(D_PARAM T) doesn't have any qualifieres, 37 * $(D_INLINECODE Unqual!T) becomes an alias for $(D_PARAM T). 38 * 39 * Params: 40 * T = A type. 41 * 42 * Returns: $(D_PARAM T) without any type qualifiers. 43 */ 44 template Unqual(T) 45 { 46 static if (is(T U == shared const U) 47 || is(T U == shared inout U) 48 || is(T U == shared inout const U) 49 || is(T U == inout const U) 50 || is(T U == const U) 51 || is(T U == immutable U) 52 || is(T U == inout U) 53 || is(T U == shared U)) 54 { 55 alias Unqual = U; 56 } 57 else 58 { 59 alias Unqual = T; 60 } 61 } 62 63 /// 64 @nogc nothrow pure @safe unittest 65 { 66 static assert(is(Unqual!bool == bool)); 67 static assert(is(Unqual!(immutable bool) == bool)); 68 static assert(is(Unqual!(inout bool) == bool)); 69 static assert(is(Unqual!(inout const bool) == bool)); 70 static assert(is(Unqual!(shared bool) == bool)); 71 static assert(is(Unqual!(shared const bool) == bool)); 72 static assert(is(Unqual!(shared inout const bool) == bool)); 73 } 74 75 /** 76 * If $(D_PARAM T) is an $(D_KEYWORD enum), $(D_INLINECODE OriginalType!T) 77 * evaluates to the most base type of that $(D_KEYWORD enum) and to 78 * $(D_PARAM T) otherwise. 79 * 80 * Params: 81 * T = A type. 82 * 83 * Returns: Base type of the $(D_KEYWORD enum) $(D_PARAM T) or $(D_PARAM T) 84 * itself. 85 */ 86 template OriginalType(T) 87 { 88 static if (is(T U == enum)) 89 { 90 alias OriginalType = OriginalType!U; 91 } 92 else 93 { 94 alias OriginalType = T; 95 } 96 } 97 98 /// 99 @nogc nothrow pure @safe unittest 100 { 101 enum E1 : const(int) 102 { 103 n = 0, 104 } 105 enum E2 : bool 106 { 107 t = true, 108 } 109 enum E3 : E2 110 { 111 t = E2.t, 112 } 113 enum E4 : const(E2) 114 { 115 t = E2.t, 116 } 117 118 static assert(is(OriginalType!E1 == const int)); 119 static assert(is(OriginalType!E2 == bool)); 120 static assert(is(OriginalType!E3 == bool)); 121 static assert(is(OriginalType!E4 == bool)); 122 static assert(is(OriginalType!(const E4) == bool)); 123 } 124 125 /** 126 * Copies constness of $(D_PARAM From) to $(D_PARAM To). 127 * 128 * The following type qualifiers affect the constness and hence are copied: 129 * $(UL 130 * $(LI const) 131 * $(LI immutable) 132 * $(LI inout) 133 * $(LI inout const) 134 * ) 135 * 136 * Params: 137 * From = Source type. 138 * To = Target type. 139 * 140 * Returns: $(D_PARAM To) with the constness of $(D_PARAM From). 141 */ 142 template CopyConstness(From, To) 143 { 144 static if (is(From T == immutable T)) 145 { 146 alias CopyConstness = immutable To; 147 } 148 else static if (is(From T == const T) || is(From T == shared const T)) 149 { 150 alias CopyConstness = const To; 151 } 152 else static if (is(From T == inout T) || is(From T == shared inout T)) 153 { 154 alias CopyConstness = inout To; 155 } 156 else static if (is(From T == inout const T) 157 || is(From T == shared inout const T)) 158 { 159 alias CopyConstness = inout const To; 160 } 161 else 162 { 163 alias CopyConstness = To; 164 } 165 } 166 167 /// 168 @nogc nothrow pure @safe unittest 169 { 170 static assert(is(CopyConstness!(int, char) == char)); 171 static assert(is(CopyConstness!(const int, char) == const char)); 172 static assert(is(CopyConstness!(immutable int, char) == immutable char)); 173 static assert(is(CopyConstness!(inout int, char) == inout char)); 174 static assert(is(CopyConstness!(inout const int, char) == inout const char)); 175 176 static assert(is(CopyConstness!(shared int, char) == char)); 177 static assert(is(CopyConstness!(shared const int, char) == const char)); 178 static assert(is(CopyConstness!(shared inout int, char) == inout char)); 179 static assert(is(CopyConstness!(shared inout const int, char) == inout const char)); 180 181 static assert(is(CopyConstness!(const int, shared char) == shared const char)); 182 static assert(is(CopyConstness!(const int, immutable char) == immutable char)); 183 static assert(is(CopyConstness!(immutable int, const char) == immutable char)); 184 } 185 186 /** 187 * Retrieves the target type `U` of a pointer `U*`. 188 * 189 * Params: 190 * T = Pointer type. 191 * 192 * Returns: Pointer target type. 193 */ 194 template PointerTarget(T) 195 { 196 static if (is(T U : U*)) 197 { 198 alias PointerTarget = U; 199 } 200 else 201 { 202 static assert(T.stringof ~ " isn't a pointer type"); 203 } 204 } 205 206 /// 207 @nogc nothrow pure @safe unittest 208 { 209 static assert(is(PointerTarget!(bool*) == bool)); 210 static assert(is(PointerTarget!(const bool*) == const bool)); 211 static assert(is(PointerTarget!(const shared bool*) == const shared bool)); 212 static assert(!is(PointerTarget!bool)); 213 } 214 215 /** 216 * Params: 217 * T = The type of the associative array. 218 * 219 * Returns: The key type of the associative array $(D_PARAM T). 220 */ 221 template KeyType(T) 222 { 223 static if (is(T V : V[K], K)) 224 { 225 alias KeyType = K; 226 } 227 else 228 { 229 static assert(false, T.stringof ~ " isn't an associative array"); 230 } 231 } 232 233 /// 234 @nogc nothrow pure @safe unittest 235 { 236 static assert(is(KeyType!(int[string]) == string)); 237 static assert(!is(KeyType!(int[15]))); 238 } 239 240 /** 241 * Params: 242 * T = The type of the associative array. 243 * 244 * Returns: The value type of the associative array $(D_PARAM T). 245 */ 246 template ValueType(T) 247 { 248 static if (is(T V : V[K], K)) 249 { 250 alias ValueType = V; 251 } 252 else 253 { 254 static assert(false, T.stringof ~ " isn't an associative array"); 255 } 256 } 257 258 /// 259 @nogc nothrow pure @safe unittest 260 { 261 static assert(is(ValueType!(int[string]) == int)); 262 static assert(!is(ValueType!(int[15]))); 263 } 264 265 /** 266 * Adds $(D_KEYWORD inout) qualifier to the type $(D_PARAM T). 267 * 268 * Params: 269 * T = A type. 270 * 271 * Returns: $(D_INLINECODE inout(T)). 272 */ 273 alias InoutOf(T) = inout(T); 274 275 /// 276 @nogc nothrow pure @safe unittest 277 { 278 static assert(is(InoutOf!int == inout int)); 279 } 280 281 /** 282 * Adds $(D_KEYWORD inout) qualifier to the type $(D_PARAM T). 283 * 284 * Params: 285 * T = A type. 286 * 287 * Returns: $(D_INLINECODE inout(T)). 288 */ 289 alias ConstOf(T) = const(T); 290 291 /// 292 @nogc nothrow pure @safe unittest 293 { 294 static assert(is(ConstOf!int == const int)); 295 } 296 297 /** 298 * Adds $(D_KEYWORD inout) qualifier to the type $(D_PARAM T). 299 * 300 * Params: 301 * T = A type. 302 * 303 * Returns: $(D_INLINECODE inout(T)). 304 */ 305 alias SharedOf(T) = shared(T); 306 307 /// 308 @nogc nothrow pure @safe unittest 309 { 310 static assert(is(SharedOf!int == shared int)); 311 } 312 313 /** 314 * Adds $(D_KEYWORD inout) qualifier to the type $(D_PARAM T). 315 * 316 * Params: 317 * T = A type. 318 * 319 * Returns: $(D_INLINECODE inout(T)). 320 */ 321 alias SharedInoutOf(T) = shared(inout T); 322 323 /// 324 @nogc nothrow pure @safe unittest 325 { 326 static assert(is(SharedInoutOf!int == shared inout int)); 327 } 328 329 /** 330 * Adds $(D_KEYWORD shared const) qualifier to the type $(D_PARAM T). 331 * 332 * Params: 333 * T = A type. 334 * 335 * Returns: $(D_INLINECODE shared(const T)). 336 */ 337 alias SharedConstOf(T) = shared(const T); 338 339 /// 340 @nogc nothrow pure @safe unittest 341 { 342 static assert(is(SharedConstOf!int == shared const int)); 343 } 344 345 /** 346 * Adds $(D_KEYWORD immutable) qualifier to the type $(D_PARAM T). 347 * 348 * Params: 349 * T = A type. 350 * 351 * Returns: $(D_INLINECODE immutable(T)). 352 */ 353 alias ImmutableOf(T) = immutable(T); 354 355 /// 356 @nogc nothrow pure @safe unittest 357 { 358 static assert(is(ImmutableOf!int == immutable int)); 359 } 360 361 /** 362 * Adds $(D_KEYWORD inout const) qualifier to the type $(D_PARAM T). 363 * 364 * Params: 365 * T = A type. 366 * 367 * Returns: $(D_INLINECODE inout(const T)). 368 */ 369 alias InoutConstOf(T) = inout(const T); 370 371 /// 372 @nogc nothrow pure @safe unittest 373 { 374 static assert(is(InoutConstOf!int == inout const int)); 375 } 376 377 /** 378 * Adds $(D_KEYWORD shared inout const) qualifier to the type $(D_PARAM T). 379 * 380 * Params: 381 * T = A type. 382 * 383 * Returns: $(D_INLINECODE shared(inout const T)). 384 */ 385 alias SharedInoutConstOf(T) = shared(inout const T); 386 387 /// 388 @nogc nothrow pure @safe unittest 389 { 390 static assert(is(SharedInoutConstOf!int == shared inout const int)); 391 } 392 393 /** 394 * Determines the type of $(D_PARAM T). If $(D_PARAM T) is already a type, 395 * $(D_PSYMBOL TypeOf) aliases itself to $(D_PARAM T). 396 * 397 * $(D_PSYMBOL TypeOf) evaluates to $(D_KEYWORD void) for template arguments. 398 * 399 * The symbols that don't have a type and aren't types cannot be used as 400 * arguments to $(D_PSYMBOL TypeOf). 401 * 402 * Params: 403 * T = Expression, type or template. 404 * 405 * Returns: The type of $(D_PARAM T). 406 */ 407 alias TypeOf(T) = T; 408 409 /// ditto 410 template TypeOf(alias T) 411 if (isExpressions!T || __traits(isTemplate, T)) 412 { 413 alias TypeOf = typeof(T); 414 } 415 416 /// 417 @nogc nothrow pure @safe unittest 418 { 419 struct S(T) 420 { 421 } 422 static assert(is(TypeOf!S == void)); 423 static assert(is(TypeOf!int == int)); 424 static assert(is(TypeOf!true == bool)); 425 static assert(!is(TypeOf!(tanya.meta))); 426 } 427 428 /** 429 * Finds the type with the smallest size in the $(D_PARAM Args) list. If 430 * several types have the same type, the leftmost is returned. 431 * 432 * Params: 433 * Args = Type list. 434 * 435 * Returns: The smallest type. 436 * 437 * See_Also: $(D_PSYMBOL Largest). 438 */ 439 template Smallest(Args...) 440 if (Args.length >= 1) 441 { 442 static assert(is(Args[0]), T.stringof ~ " doesn't have .sizeof property"); 443 444 static if (Args.length == 1) 445 { 446 alias Smallest = Args[0]; 447 } 448 else static if (Smallest!(Args[1 .. $]).sizeof < Args[0].sizeof) 449 { 450 alias Smallest = Smallest!(Args[1 .. $]); 451 } 452 else 453 { 454 alias Smallest = Args[0]; 455 } 456 } 457 458 /// 459 @nogc nothrow pure @safe unittest 460 { 461 static assert(is(Smallest!(int, ushort, uint, short) == ushort)); 462 static assert(is(Smallest!(short) == short)); 463 static assert(is(Smallest!(ubyte[8], ubyte[5]) == ubyte[5])); 464 static assert(!is(Smallest!(short, 5))); 465 } 466 467 /** 468 * Finds the type with the largest size in the $(D_PARAM Args) list. If several 469 * types have the same type, the leftmost is returned. 470 * 471 * Params: 472 * Args = Type list. 473 * 474 * Returns: The largest type. 475 * 476 * See_Also: $(D_PSYMBOL Smallest). 477 */ 478 template Largest(Args...) 479 if (Args.length >= 1) 480 { 481 static assert(is(Args[0]), T.stringof ~ " doesn't have .sizeof property"); 482 483 static if (Args.length == 1) 484 { 485 alias Largest = Args[0]; 486 } 487 else static if (Largest!(Args[1 .. $]).sizeof > Args[0].sizeof) 488 { 489 alias Largest = Largest!(Args[1 .. $]); 490 } 491 else 492 { 493 alias Largest = Args[0]; 494 } 495 } 496 497 /// 498 @nogc nothrow pure @safe unittest 499 { 500 static assert(is(Largest!(int, short, uint) == int)); 501 static assert(is(Largest!(short) == short)); 502 static assert(is(Largest!(ubyte[8], ubyte[5]) == ubyte[8])); 503 static assert(!is(Largest!(short, 5))); 504 }