1 /*******************************************************************************
2
3 Basic traits allowing to distinguish various types between each other. Any
4 more convoluted traits dedicated to specific type kinds should go in
5 dedicated modules.
6
7 NB: because this module is often used as purely compile-time dependency it
8 used built-in asserts instead of `ocean.core.Test` to reduce amount of
9 cyclic imports. `ocean.meta` modules in general are not supposed to
10 import anything outside of `ocean.meta`.
11
12 Copyright:
13 Copyright (C) 2017 dunnhumby Germany GmbH. All rights reserved.
14
15 License:
16 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
17 Alternatively, this file may be distributed under the terms of the Tango
18 3-Clause BSD License (see LICENSE_BSD.txt for details).
19
20 *******************************************************************************/
21
22 module ocean.meta.traits.Basic;
23
24 import ocean.meta.types.Qualifiers;
25 import ocean.meta.types.Typedef;
26
27 /*******************************************************************************
28
29 Primitive types are the types from which one or multiple other types cannot
30 be derived from using the ``is()`` expression or corresponding template type
31 parameter specialisation. The following types are not primitive:
32 - arrays (static, dynamic and associative) and pointers,
33 - classes structs and unions,
34 - delegates, function pointers and functions (function pointer base types),
35 - enums and typedefs.
36
37 All other, including arithmetic and character types are primitive. Each
38 primitive type is represented by a D keyword.
39 ``void`` is a primitive type. Imaginary and complex numbers are considered
40 primitive types, too, which may be subject to discussion.
41
42 Params:
43 T = type to check
44
45 Returns:
46 `true` if `T` is a primitive type
47
48 *******************************************************************************/
49
50 public template isPrimitiveType ( T )
51 {
52 static immutable isPrimitiveType =
53 is(Unqual!(T) == void)
54 || is(Unqual!(T) == bool)
55 || isIntegerType!(T)
56 || isCharType!(T)
57 || isFloatingPointType!(T);
58 }
59
60 ///
61 unittest
62 {
63 static assert ( isPrimitiveType!(int));
64 static assert (!isPrimitiveType!(int*));
65 struct S { }
66 static assert (!isPrimitiveType!(S));
67 }
68
69 /*******************************************************************************
70
71 Params:
72 T = type to check
73
74 Returns:
75 `true` if `T` is one of supported string element types
76
77 *******************************************************************************/
78
79 public template isCharType ( T )
80 {
81 static immutable bool isCharType =
82 is(Unqual!(T) == char)
83 || is(Unqual!(T) == wchar)
84 || is(Unqual!(T) == dchar);
85 }
86
87 ///
88 unittest
89 {
90 static assert ( isCharType!(wchar));
91 static assert ( isCharType!(const(char)));
92 static assert (!isCharType!(byte));
93 }
94
95 /*******************************************************************************
96
97 Params:
98 T = type to check
99
100 Returns:
101 `true` if `T` is a built-in signed integer type
102
103 *******************************************************************************/
104
105 public template isSignedIntegerType ( T )
106 {
107 static immutable bool isSignedIntegerType =
108 is(Unqual!(T) == byte)
109 || is(Unqual!(T) == short)
110 || is(Unqual!(T) == int)
111 || is(Unqual!(T) == long);
112 }
113
114 ///
115 unittest
116 {
117 static assert ( isSignedIntegerType!(int));
118 static assert ( isSignedIntegerType!(const(long)));
119 static assert (!isSignedIntegerType!(ubyte));
120 }
121
122 /*******************************************************************************
123
124 Params:
125 T = type to check
126
127 Returns:
128 `true` if `T` is a built-in unsigned integer type
129
130 *******************************************************************************/
131
132 public template isUnsignedIntegerType ( T )
133 {
134 static immutable bool isUnsignedIntegerType =
135 is(Unqual!(T) == ubyte)
136 || is(Unqual!(T) == ushort)
137 || is(Unqual!(T) == uint)
138 || is(Unqual!(T) == ulong);
139 }
140
141 ///
142 unittest
143 {
144 static assert (!isUnsignedIntegerType!(int));
145 static assert ( isUnsignedIntegerType!(ubyte));
146 static assert ( isUnsignedIntegerType!(const(ulong)));
147 }
148
149 /*******************************************************************************
150
151 Params:
152 T = type to check
153
154 Returns:
155 `true` if `T` is a built-in integer type
156
157 *******************************************************************************/
158
159 public template isIntegerType ( T )
160 {
161 static immutable bool isIntegerType =
162 isSignedIntegerType!(T)
163 || isUnsignedIntegerType!(T);
164 }
165
166 ///
167 unittest
168 {
169 static assert ( isIntegerType!(long));
170 static assert ( isIntegerType!(ubyte));
171 static assert (!isIntegerType!(char));
172 }
173
174 /*******************************************************************************
175
176 Params:
177 T = type to check
178
179 Returns:
180 `true` if `T` is a built-in floating point type, excluding
181 complex/imaginary ones
182
183 *******************************************************************************/
184
185 public template isRealType ( T )
186 {
187 static immutable bool isRealType =
188 is( Unqual!(T) == float )
189 || is( Unqual!(T) == double )
190 || is( Unqual!(T) == real );
191 }
192
193 ///
194 unittest
195 {
196 static assert ( isRealType!(double));
197 static assert (!isRealType!(long));
198 static assert (!isRealType!(cdouble));
199 }
200
201
202 /*******************************************************************************
203
204 Params:
205 T = type to check
206
207 Returns:
208 `true` if `T` is a built-in complex floating point type
209
210 *******************************************************************************/
211
212 public template isComplexType( T )
213 {
214 static immutable bool isComplexType =
215 is( Unqual!(T) == cfloat )
216 || is( Unqual!(T) == cdouble )
217 || is( Unqual!(T) == creal );
218 }
219
220 ///
221 unittest
222 {
223 static assert ( isComplexType!(cdouble));
224 static assert ( isComplexType!(const(cdouble)));
225 static assert (!isComplexType!(double));
226 }
227
228 /*******************************************************************************
229
230 Params:
231 T = type to check
232
233 Returns:
234 `true` if `T` is a built-in imaginary floating point type
235
236 *******************************************************************************/
237
238 public template isImaginaryType( T )
239 {
240 static immutable bool isImaginaryType =
241 is( Unqual!(T) == ifloat )
242 || is( Unqual!(T) == idouble )
243 || is( Unqual!(T) == ireal );
244 }
245
246 ///
247 unittest
248 {
249 static assert ( isImaginaryType!(idouble));
250 static assert ( isImaginaryType!(const(idouble)));
251 static assert (!isImaginaryType!(double));
252 }
253
254 /*******************************************************************************
255
256 Params:
257 T = type to check
258
259 Returns:
260 `true` if `T` is any built-in floating-point type: real, complex, or
261 imaginary.
262
263 *******************************************************************************/
264
265 public template isFloatingPointType( T )
266 {
267 static immutable bool isFloatingPointType =
268 isRealType!(T)
269 || isComplexType!(T)
270 || isImaginaryType!(T);
271 }
272
273 ///
274 unittest
275 {
276 static assert (isFloatingPointType!(double));
277 static assert (isFloatingPointType!(ifloat));
278 }
279
280 /*******************************************************************************
281
282 Used by other traits to distinguish between dynamic and static arrays
283 instead of plain `bool` values.
284
285 `ArrayKind.NotArray` is explicitly defined to have value `0` so that it can
286 be in regular condition, i.e. `static if (isArrayType!(T))`.
287
288 *******************************************************************************/
289
290 public enum ArrayKind
291 {
292 NotArray = 0,
293 Static = 1,
294 Dynamic = 2,
295 Associative = 3,
296 }
297
298 /*******************************************************************************
299
300 Check if type is an array type and which kind of array it is
301
302 Params:
303 T = type to check
304
305 Returns:
306 `ArrayKind` value indicating if `T` is an array and if it is, static or
307 dynamic
308
309 *******************************************************************************/
310
311 public template isArrayType ( T )
312 {
313 static if (is(Unqual!(T) U == U[]))
314 static immutable isArrayType = ArrayKind.Dynamic;
315 else static if (is(Unqual!(T) U : U[]))
316 static immutable isArrayType = ArrayKind.Static;
317 else static if (is(typeof(T.init.values[0])[typeof(T.init.keys[0])] ==
318 Unqual!(T)))
319 static immutable isArrayType = ArrayKind.Associative;
320 else
321 static immutable isArrayType = ArrayKind.NotArray;
322 }
323
324 ///
325 unittest
326 {
327 static assert ( isArrayType!(char[15]) == ArrayKind.Static);
328 static assert ( isArrayType!(char[]) == ArrayKind.Dynamic);
329 static assert ( isArrayType!(char[][5]) == ArrayKind.Static);
330 static assert ( isArrayType!(char) == ArrayKind.NotArray);
331 static assert ( isArrayType!(int[int]) == ArrayKind.Associative);
332 static assert ( isArrayType!(const(int[int])) == ArrayKind.Associative);
333 static assert (!isArrayType!(char));
334 }
335
336 unittest
337 {
338 static struct S { }
339 static assert (!isArrayType!(S));
340 static assert ( isArrayType!(S[5]));
341 }
342
343 /*******************************************************************************
344
345 Params:
346 T = any type
347
348 Returns:
349 `true` if T is static or dynamic array, `false` otherwise
350
351 *******************************************************************************/
352
353 public template isBasicArrayType ( T )
354 {
355 static immutable isBasicArrayType =
356 (isArrayType!(T) == ArrayKind.Static)
357 || (isArrayType!(T) == ArrayKind.Dynamic);
358 }
359
360 ///
361 unittest
362 {
363 static assert ( isBasicArrayType!(int[]));
364 static assert ( isBasicArrayType!(int[5]));
365 static assert (!isBasicArrayType!(int[int]));
366 }
367
368 /*******************************************************************************
369
370 Params:
371 T = static array type
372
373 Returns:
374 for static array T[N] returns N
375
376 *******************************************************************************/
377
378 public template staticArrayLength ( T : U[Dim], U, size_t Dim )
379 {
380 static immutable staticArrayLength = Dim;
381 }
382
383 unittest
384 {
385 static assert (staticArrayLength!(int[][5]) == 5);
386 static assert (staticArrayLength!(char[42]) == 42);
387 static assert (staticArrayLength!(immutable(mstring[2])) == 2);
388 }
389
390 /*******************************************************************************
391
392 Params:
393 T = type to check
394
395 Returns:
396 `true` if `T` is a pointer type.
397
398 *******************************************************************************/
399
400 template isPointerType ( T )
401 {
402 static if (is(Unqual!(T) U == U*))
403 static immutable isPointerType = true;
404 else
405 static immutable isPointerType = false;
406 }
407
408 ///
409 unittest
410 {
411 static assert ( isPointerType!(void*));
412 static assert (!isPointerType!(char[]));
413 }
414
415 unittest
416 {
417 static assert ( isPointerType!(char[]*));
418 static assert (!isPointerType!(char*[]));
419 static assert ( isPointerType!(const(real)*));
420 static assert (!isPointerType!(uint));
421
422 class Ham { void* a; }
423
424 static assert (!isPointerType!(Ham));
425
426 union Eggs
427 {
428 void* a;
429 uint b;
430 }
431
432 static assert (!isPointerType!(Eggs));
433 static assert ( isPointerType!(immutable(Eggs*)));
434
435 struct Bacon { }
436
437 static assert (!isPointerType!(Bacon));
438
439 // function pointer is a pointer, but delegate is not:
440 void foo () {}
441 static void bar () {}
442 static assert (!isPointerType!(typeof(&foo)));
443 static assert ( isPointerType!(typeof(&bar)));
444 }
445
446 /*******************************************************************************
447
448 Params:
449 T = type to check
450
451 Returns:
452 `true` if `T` is a struct, class, interface or union
453
454 *******************************************************************************/
455
456 template isReferenceType ( T )
457 {
458 static immutable isReferenceType =
459 isPointerType!(T)
460 || is(T == delegate)
461 || isArrayType!(T) == ArrayKind.Dynamic
462 || isArrayType!(T) == ArrayKind.Associative
463 || is(T == class)
464 || is(T == interface);
465 }
466
467 ///
468 unittest
469 {
470 struct S { }
471 class C { }
472 interface I { }
473
474 static assert (!isReferenceType!(S));
475 static assert ( isReferenceType!(S*));
476 static assert ( isReferenceType!(S[]));
477 static assert ( isReferenceType!(C));
478 static assert ( isReferenceType!(I));
479 static assert ( isReferenceType!(S[C]));
480 static assert ( isReferenceType!(void function(int)));
481
482 static void foo ( ) { }
483 static assert (!isReferenceType!(typeof(foo)));
484 }
485
486 /*******************************************************************************
487
488 Params:
489 T = type to check
490
491 Returns:
492 `true` if `T` is a struct, class, interface or union
493
494 *******************************************************************************/
495
496 template isAggregateType ( T )
497 {
498 static immutable isAggregateType =
499 is(T == class)
500 || is(T == interface)
501 || is(T == struct)
502 || is(T == union);
503 }
504
505 ///
506 unittest
507 {
508 struct S { int x; }
509 union U { int x; double y; }
510
511 static assert ( isAggregateType!(S));
512 static assert ( isAggregateType!(U));
513 static assert (!isAggregateType!(S[2]));
514 }
515
516 /*******************************************************************************
517
518 Params:
519 T = type to check
520
521 Returns:
522 `true` if T is a function, function pointer or delegate
523
524 *******************************************************************************/
525
526 template isFunctionType ( T )
527 {
528 static immutable bool isFunctionType =
529 is(T == function)
530 || is(typeof(*T.init) == function)
531 || is(T == delegate);
532 }
533
534 ///
535 unittest
536 {
537 void foo1() { }
538 auto foo2 = () { };
539 static void foo3() { }
540
541 static assert (isFunctionType!(typeof(&foo1)));
542 static assert (isFunctionType!(typeof(foo2)));
543 static assert (isFunctionType!(typeof(&foo3)));
544 static assert (isFunctionType!(typeof(foo3)));
545 }
546
547 unittest
548 {
549 static real func(ref int) { return 0; }
550 void nestedFunc() { }
551 class C
552 {
553 real method(ref int) { return 0; }
554 }
555 auto c = new C;
556 auto fp = &func;
557 auto dg = &c.method;
558 real val;
559
560 static assert ( isFunctionType!(typeof(func)));
561 static assert ( isFunctionType!(typeof(nestedFunc)));
562 static assert ( isFunctionType!(typeof(C.method)));
563 static assert ( isFunctionType!(typeof(fp)));
564 static assert ( isFunctionType!(typeof(dg)));
565 static assert ( isFunctionType!(real function(ref int)));
566 static assert ( isFunctionType!(real delegate(ref int)));
567 static assert ( isFunctionType!(typeof((int a) { return a; })));
568
569 static assert (!isFunctionType!(int));
570 static assert (!isFunctionType!(typeof(val)));
571 }
572
573 /*******************************************************************************
574
575 Params:
576 T = type to check
577
578 Returns:
579 `true` if T is a function, function pointer or delegate or callable
580 aggregate
581
582 *******************************************************************************/
583
584 template isCallableType ( T )
585 {
586 static if (is(typeof(T.opCall)))
587 static immutable isCallableType = isFunctionType!(typeof(&T.init.opCall));
588 else
589 static immutable isCallableType = isFunctionType!(T);
590 }
591
592 ///
593 unittest
594 {
595 struct S
596 {
597 void opCall (int) { }
598 }
599
600 static assert (isCallableType!(S));
601 static assert (isCallableType!(typeof(S.opCall)));
602 }
603
604 unittest
605 {
606 struct S2
607 {
608 static bool opCall( in int p1, in int p2 ) { return true; }
609 }
610
611 static assert (isCallableType!(S2));
612 }
613
614 /*******************************************************************************
615
616 Used as result type for `isTypedef` trait.
617
618 `None` value is explicitly set to `0` so that it can be used in condition
619 like `if(isTypedef!(T))`.
620
621 *******************************************************************************/
622
623 public enum TypedefKind
624 {
625 /// Not a typedef
626 None = 0,
627 /// D1 `typedef` keyword
628 Keyword,
629 /// Emulated by struct
630 Struct
631 }
632
633 /*******************************************************************************
634
635 Determines if T is a typedef of some kind
636
637 Params:
638 T = type to check
639
640 Evaluates to:
641 `TypedefKind` value which is non-zero is T is some typedef
642
643 *******************************************************************************/
644
645 public template isTypedef (T)
646 {
647 static if (is(T.IsTypedef))
648 static immutable isTypedef = TypedefKind.Struct;
649 else
650 static immutable isTypedef = TypedefKind.None;
651 }
652
653 unittest
654 {
655 mixin(Typedef!(double, "RealNum"));
656
657 static assert(!isTypedef!(int));
658 static assert(!isTypedef!(double));
659 static assert( isTypedef!(RealNum));
660
661 static assert(isTypedef!(RealNum) == TypedefKind.Struct);
662 }
663
664 /******************************************************************************
665
666 Check if the type of a member inside a struct or class is a D manifest
667 constant
668
669 Params:
670 T = The struct that will be checked
671 name = The struct member that will be checked
672
673 ******************************************************************************/
674
675 bool isManifestConstant ( T, string name ) ( )
676 {
677 T instance;
678 mixin(`return is(typeof(instance.`~name~`)) && !is(typeof(&instance.`~name~`));`);
679 }
680
681 unittest
682 {
683 struct Test
684 {
685 enum manifest = 2;
686 int notManifest1;
687 enum CustomType : int {
688 a = 1, b = 2
689 }
690
691 CustomType notManifest2;
692 }
693
694 static assert(isManifestConstant!(Test, "manifest"));
695 static assert(!isManifestConstant!(Test, "CustomType"));
696 static assert(!isManifestConstant!(Test, "notManifest1"));
697 static assert(!isManifestConstant!(Test, "notManifest2"));
698 }
699
700
701
702 /******************************************************************************
703
704 Check if a constant is manifest constant
705
706 Params:
707 T = The constant
708
709 ******************************************************************************/
710
711 bool isManifestConstant ( alias T ) ( )
712 {
713 return is(typeof(T)) && !is(typeof(&T));
714 }
715
716 unittest
717 {
718 enum manifest = 3;
719 int notManifest;
720
721 static assert(isManifestConstant!(manifest));
722 static assert(!isManifestConstant!(notManifest));
723 }