2 * Contains traits for runtime internal usage.
4 * Copyright: Copyright Digital Mars 2014 -.
5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Martin Nowak
7 * Source: $(DRUNTIMESRC core/internal/_traits.d)
9 module core
.internal
.traits
;
11 alias AliasSeq(TList
...) = TList
;
15 static if (is(T
== struct) ||
is(T
== union))
16 alias Fields
= typeof(T
.tupleof
[0 .. $ - __traits(isNested
, T
)]);
17 else static if (is(T
== class) ||
is(T
== interface))
18 alias Fields
= typeof(T
.tupleof
);
20 alias Fields
= AliasSeq
!T
;
23 T
trustedCast(T
, U
)(auto ref U u
) @trusted pure nothrow
28 alias Unconst(T
: const U
, U
) = U
;
30 /// taken from std.traits.Unqual
31 template Unqual(T
: const U
, U
)
33 static if (is(U
== shared V
, V
))
39 template BaseElemOf(T
)
41 static if (is(OriginalType
!T
== E
[N
], E
, size_t N
))
42 alias BaseElemOf
= BaseElemOf
!E
;
49 static assert(is(BaseElemOf
!(int) == int));
50 static assert(is(BaseElemOf
!(int[1]) == int));
51 static assert(is(BaseElemOf
!(int[1][2]) == int));
52 static assert(is(BaseElemOf
!(int[1][]) == int[1][]));
53 static assert(is(BaseElemOf
!(int[][1]) == int[]));
54 enum E
: int[2]{ test = [0, 1] }
55 static assert(is(BaseElemOf
!(E
) == int));
59 template ModifyTypePreservingTQ(alias Modifier
, T
)
61 static if (is(T U
== immutable U
)) alias ModifyTypePreservingTQ
= immutable Modifier
!U
;
62 else static if (is(T U
== shared inout const U
)) alias ModifyTypePreservingTQ
= shared inout const Modifier
!U
;
63 else static if (is(T U
== shared inout U
)) alias ModifyTypePreservingTQ
= shared inout Modifier
!U
;
64 else static if (is(T U
== shared const U
)) alias ModifyTypePreservingTQ
= shared const Modifier
!U
;
65 else static if (is(T U
== shared U
)) alias ModifyTypePreservingTQ
= shared Modifier
!U
;
66 else static if (is(T U
== inout const U
)) alias ModifyTypePreservingTQ
= inout const Modifier
!U
;
67 else static if (is(T U
== inout U
)) alias ModifyTypePreservingTQ
= inout Modifier
!U
;
68 else static if (is(T U
== const U
)) alias ModifyTypePreservingTQ
= const Modifier
!U
;
69 else alias ModifyTypePreservingTQ
= Modifier
!T
;
73 alias Intify(T
) = int;
74 static assert(is(ModifyTypePreservingTQ
!(Intify
, real) == int));
75 static assert(is(ModifyTypePreservingTQ
!(Intify
, const real) == const int));
76 static assert(is(ModifyTypePreservingTQ
!(Intify
, inout real) == inout int));
77 static assert(is(ModifyTypePreservingTQ
!(Intify
, inout const real) == inout const int));
78 static assert(is(ModifyTypePreservingTQ
!(Intify
, shared real) == shared int));
79 static assert(is(ModifyTypePreservingTQ
!(Intify
, shared const real) == shared const int));
80 static assert(is(ModifyTypePreservingTQ
!(Intify
, shared inout real) == shared inout int));
81 static assert(is(ModifyTypePreservingTQ
!(Intify
, shared inout const real) == shared inout const int));
82 static assert(is(ModifyTypePreservingTQ
!(Intify
, immutable real) == immutable int));
85 // Substitute all `inout` qualifiers that appears in T to `const`
86 template substInout(T
)
88 static if (is(T
== immutable))
92 else static if (is(T
: shared const U
, U
) ||
is(T
: const U
, U
))
94 // U is top-unqualified
95 mixin("alias substInout = "
96 ~ (is(T
== shared) ?
"shared " : "")
97 ~ (is(T
== const) ||
is(T
== inout) ?
"const " : "") // substitute inout to const
98 ~ "substInoutForm!U;");
104 private template substInoutForm(T
)
106 static if (is(T
== struct) ||
is(T
== class) ||
is(T
== union) ||
is(T
== interface))
108 alias substInoutForm
= T
; // prevent matching to the form of alias-this-ed type
110 else static if (is(T
: V
[K
], K
, V
)) alias substInoutForm
= substInout
!V
[substInout
!K
];
111 else static if (is(T
: U
[n
], U
, size_t n
)) alias substInoutForm
= substInout
!U
[n
];
112 else static if (is(T
: U
[], U
)) alias substInoutForm
= substInout
!U
[];
113 else static if (is(T
: U
*, U
)) alias substInoutForm
= substInout
!U
*;
114 else alias substInoutForm
= T
;
117 /// used to declare an extern(D) function that is defined in a different module
118 template externDFunc(string fqn
, T
:FT
*, FT
) if (is(FT
== function))
120 static if (is(FT RT
== return) && is(FT Args
== function))
122 import core
.demangle
: mangleFunc
;
124 string s
= "extern(D) RT externDFunc(Args)";
125 foreach (attr
; __traits(getFunctionAttributes
, FT
))
129 pragma(mangle
, mangleFunc
!T(fqn
)) mixin(decl
);
135 template staticIota(int beg
, int end
)
137 static if (beg
+ 1 >= end
)
139 static if (beg
>= end
)
141 alias staticIota
= AliasSeq
!();
145 alias staticIota
= AliasSeq
!(+beg
);
150 enum mid
= beg
+ (end
- beg
) / 2;
151 alias staticIota
= AliasSeq
!(staticIota
!(beg
, mid
), staticIota
!(mid
, end
));
155 private struct __InoutWorkaroundStruct
{}
156 @property T
rvalueOf(T
)(T val
) { return val
; }
157 @property T
rvalueOf(T
)(inout __InoutWorkaroundStruct
= __InoutWorkaroundStruct
.init
);
158 @property ref T
lvalueOf(T
)(inout __InoutWorkaroundStruct
= __InoutWorkaroundStruct
.init
);
160 // taken from std.traits.isAssignable
161 template isAssignable(Lhs
, Rhs
= Lhs
)
163 enum isAssignable
= __traits(compiles
, lvalueOf
!Lhs
= rvalueOf
!Rhs
) && __traits(compiles
, lvalueOf
!Lhs
= lvalueOf
!Rhs
);
166 // taken from std.traits.isInnerClass
167 template isInnerClass(T
) if (is(T
== class))
169 static if (is(typeof(T
.outer
)))
171 template hasOuterMember(T
...)
173 static if (T
.length
== 0)
174 enum hasOuterMember
= false;
176 enum hasOuterMember
= T
[0] == "outer" || hasOuterMember
!(T
[1 .. $]);
178 enum isInnerClass
= __traits(isSame
, typeof(T
.outer
), __traits(parent
, T
)) && !hasOuterMember
!(__traits(allMembers
, T
));
181 enum isInnerClass
= false;
184 template dtorIsNothrow(T
)
186 enum dtorIsNothrow
= is(typeof(function{T t
=void;}) : void function() nothrow);
189 // taken from std.meta.allSatisfy
190 template allSatisfy(alias F
, T
...)
192 static foreach (Ti
; T
)
194 static if (!is(typeof(allSatisfy
) == bool) && // not yet defined
197 enum allSatisfy
= false;
200 static if (!is(typeof(allSatisfy
) == bool)) // if not yet defined
202 enum allSatisfy
= true;
206 // taken from std.meta.anySatisfy
207 template anySatisfy(alias F
, Ts
...)
209 static foreach (T
; Ts
)
211 static if (!is(typeof(anySatisfy
) == bool) && // not yet defined
214 enum anySatisfy
= true;
217 static if (!is(typeof(anySatisfy
) == bool)) // if not yet defined
219 enum anySatisfy
= false;
223 // simplified from std.traits.maxAlignment
224 template maxAlignment(Ts
...)
230 static foreach (T
; Ts
)
231 if (T
.alignof
> result
) result
= T
.alignof
;
236 template classInstanceAlignment(T
)
239 enum classInstanceAlignment
= __traits(classInstanceAlignment
, T
);
242 /// See $(REF hasElaborateMove, std,traits)
243 template hasElaborateMove(S
)
245 static if (__traits(isStaticArray
, S
))
247 enum bool hasElaborateMove
= S
.sizeof
&& hasElaborateMove
!(BaseElemOf
!S
);
249 else static if (is(S
== struct))
251 enum hasElaborateMove
= (is(typeof(S
.init
.opPostMove(lvalueOf
!S
))) &&
252 !is(typeof(S
.init
.opPostMove(rvalueOf
!S
)))) ||
253 anySatisfy
!(.hasElaborateMove
, Fields
!S
);
257 enum bool hasElaborateMove
= false;
261 // std.traits.hasElaborateDestructor
262 template hasElaborateDestructor(S
)
264 static if (__traits(isStaticArray
, S
))
266 enum bool hasElaborateDestructor
= S
.sizeof
&& hasElaborateDestructor
!(BaseElemOf
!S
);
268 else static if (is(S
== struct))
270 // Once https://issues.dlang.org/show_bug.cgi?id=24865 is fixed, then
271 // this should be the implementation, but until that's fixed, we need the
273 // enum hasElaborateDestructor = __traits(hasMember, S, "__xdtor");
275 enum hasElaborateDestructor
= hasDtor([__traits(allMembers
, S
)]);
279 enum bool hasElaborateDestructor
= false;
283 private bool hasDtor(string
[] members
)
285 foreach (name
; members
)
287 if (name
== "__xdtor")
296 static struct NoDestructor
{}
297 static assert(!hasElaborateDestructor
!NoDestructor
);
298 static assert(!hasElaborateDestructor
!(NoDestructor
[42]));
299 static assert(!hasElaborateDestructor
!(NoDestructor
[0]));
300 static assert(!hasElaborateDestructor
!(NoDestructor
[]));
302 static struct HasDestructor
{ ~this() {} }
303 static assert( hasElaborateDestructor
!HasDestructor
);
304 static assert( hasElaborateDestructor
!(HasDestructor
[42]));
305 static assert(!hasElaborateDestructor
!(HasDestructor
[0]));
306 static assert(!hasElaborateDestructor
!(HasDestructor
[]));
308 static struct HasDestructor2
{ HasDestructor s
; }
309 static assert( hasElaborateDestructor
!HasDestructor2
);
310 static assert( hasElaborateDestructor
!(HasDestructor2
[42]));
311 static assert(!hasElaborateDestructor
!(HasDestructor2
[0]));
312 static assert(!hasElaborateDestructor
!(HasDestructor2
[]));
314 static class HasFinalizer
{ ~this() {} }
315 static assert(!hasElaborateDestructor
!HasFinalizer
);
317 static struct HasUnion
{ union { HasDestructor s
; } }
318 static assert(!hasElaborateDestructor
!HasUnion
);
319 static assert(!hasElaborateDestructor
!(HasUnion
[42]));
320 static assert(!hasElaborateDestructor
!(HasUnion
[0]));
321 static assert(!hasElaborateDestructor
!(HasUnion
[]));
323 static assert(!hasElaborateDestructor
!int);
324 static assert(!hasElaborateDestructor
!(int[0]));
325 static assert(!hasElaborateDestructor
!(int[42]));
326 static assert(!hasElaborateDestructor
!(int[]));
329 // https://issues.dlang.org/show_bug.cgi?id=24865
332 static struct S2
{ ~this() {} }
333 static struct S3
{ S2 field
; }
334 static struct S6
{ S3
[0] field
; }
336 static assert( hasElaborateDestructor
!S2
);
337 static assert( hasElaborateDestructor
!S3
);
338 static assert(!hasElaborateDestructor
!S6
);
341 // std.traits.hasElaborateCopyDestructor
342 template hasElaborateCopyConstructor(S
)
344 static if (__traits(isStaticArray
, S
))
346 enum bool hasElaborateCopyConstructor
= S
.sizeof
&& hasElaborateCopyConstructor
!(BaseElemOf
!S
);
348 else static if (is(S
== struct))
350 enum hasElaborateCopyConstructor
= __traits(hasCopyConstructor
, S
) ||
__traits(hasPostblit
, S
);
354 enum bool hasElaborateCopyConstructor
= false;
363 this(return scope ref typeof(this) rhs
) { }
364 this(int x
, int y
) {}
367 static assert( hasElaborateCopyConstructor
!S
);
368 static assert(!hasElaborateCopyConstructor
!(S
[0][1]));
373 this(int x
, int y
) {}
376 static assert(!hasElaborateCopyConstructor
!S2
);
381 this(return scope ref typeof(this) rhs
, int x
= 42) { }
382 this(int x
, int y
) {}
385 static assert( hasElaborateCopyConstructor
!S3
);
387 static struct S4
{ union { S s
; } }
389 static assert(!hasElaborateCopyConstructor
!S4
);
392 template hasElaborateAssign(S
)
394 static if (__traits(isStaticArray
, S
))
396 enum bool hasElaborateAssign
= S
.sizeof
&& hasElaborateAssign
!(BaseElemOf
!S
);
398 else static if (is(S
== struct))
400 enum hasElaborateAssign
= is(typeof(S
.init
.opAssign(rvalueOf
!S
))) ||
401 is(typeof(S
.init
.opAssign(lvalueOf
!S
)));
405 enum bool hasElaborateAssign
= false;
413 static assert(!hasElaborateAssign
!S
);
414 static assert(!hasElaborateAssign
!(S
[10]));
415 static assert(!hasElaborateAssign
!(S
[0]));
416 static assert(!hasElaborateAssign
!(S
[]));
419 static struct S
{ int i
; }
420 static assert(!hasElaborateAssign
!S
);
421 static assert(!hasElaborateAssign
!(S
[10]));
422 static assert(!hasElaborateAssign
!(S
[0]));
423 static assert(!hasElaborateAssign
!(S
[]));
426 static struct S
{ void opAssign(S
) {} }
427 static assert( hasElaborateAssign
!S
);
428 static assert( hasElaborateAssign
!(S
[10]));
429 static assert(!hasElaborateAssign
!(S
[0]));
430 static assert(!hasElaborateAssign
!(S
[]));
433 static struct S
{ void opAssign(ref S
) {} }
434 static assert( hasElaborateAssign
!S
);
435 static assert( hasElaborateAssign
!(S
[10]));
436 static assert(!hasElaborateAssign
!(S
[0]));
437 static assert(!hasElaborateAssign
!(S
[]));
440 static struct S
{ void opAssign(int) {} }
441 static assert(!hasElaborateAssign
!S
);
442 static assert(!hasElaborateAssign
!(S
[10]));
443 static assert(!hasElaborateAssign
!(S
[0]));
444 static assert(!hasElaborateAssign
!(S
[]));
447 static struct S
{ this(this) {} }
448 static assert( hasElaborateAssign
!S
);
449 static assert( hasElaborateAssign
!(S
[10]));
450 static assert(!hasElaborateAssign
!(S
[0]));
451 static assert(!hasElaborateAssign
!(S
[]));
453 // https://issues.dlang.org/show_bug.cgi?id=24834
456 static struct S { this(ref S) {} }
457 static assert( hasElaborateAssign!S);
458 static assert( hasElaborateAssign!(S[10]));
459 static assert(!hasElaborateAssign!(S[0]));
460 static assert(!hasElaborateAssign!(S[]));
464 static struct S
{ ~this() {} }
465 static assert( hasElaborateAssign
!S
);
466 static assert( hasElaborateAssign
!(S
[10]));
467 static assert(!hasElaborateAssign
!(S
[0]));
468 static assert(!hasElaborateAssign
!(S
[]));
471 static struct S
{ @disable void opAssign(S
); }
472 static assert(!hasElaborateAssign
!S
);
473 static assert(!hasElaborateAssign
!(S
[10]));
474 static assert(!hasElaborateAssign
!(S
[0]));
475 static assert(!hasElaborateAssign
!(S
[]));
478 static struct Member
{}
479 static struct S
{ Member member
; }
480 static assert(!hasElaborateAssign
!S
);
481 static assert(!hasElaborateAssign
!(S
[10]));
482 static assert(!hasElaborateAssign
!(S
[0]));
483 static assert(!hasElaborateAssign
!(S
[]));
486 static struct Member
{ void opAssign(Member
) {} }
487 static struct S
{ Member member
; }
488 static assert( hasElaborateAssign
!S
);
489 static assert( hasElaborateAssign
!(S
[10]));
490 static assert(!hasElaborateAssign
!(S
[0]));
491 static assert(!hasElaborateAssign
!(S
[]));
494 static struct Member
{}
495 static struct S
{ Member member
; void opAssign(S
) {} }
496 static assert( hasElaborateAssign
!S
);
497 static assert( hasElaborateAssign
!(S
[10]));
498 static assert(!hasElaborateAssign
!(S
[0]));
499 static assert(!hasElaborateAssign
!(S
[]));
502 static struct Member
{ @disable void opAssign(Member
); }
503 static struct S
{ Member member
; }
504 static assert(!hasElaborateAssign
!S
);
505 static assert(!hasElaborateAssign
!(S
[10]));
506 static assert(!hasElaborateAssign
!(S
[0]));
507 static assert(!hasElaborateAssign
!(S
[]));
510 static struct Member
{ @disable void opAssign(Member
); }
511 static struct S
{ Member member
; void opAssign(S
) {} }
512 static assert( hasElaborateAssign
!S
);
513 static assert( hasElaborateAssign
!(S
[10]));
514 static assert(!hasElaborateAssign
!(S
[0]));
515 static assert(!hasElaborateAssign
!(S
[]));
518 static struct Member
{ void opAssign(Member
) {} }
519 static struct S
{ Member member
; @disable void opAssign(S
); }
520 static assert(!hasElaborateAssign
!S
);
521 static assert(!hasElaborateAssign
!(S
[10]));
522 static assert(!hasElaborateAssign
!(S
[0]));
523 static assert(!hasElaborateAssign
!(S
[]));
526 static struct Member
{ void opAssign(Member
) {} }
527 static struct S
{ union { Member member
; } }
528 static assert(!hasElaborateAssign
!S
);
529 static assert(!hasElaborateAssign
!(S
[10]));
530 static assert(!hasElaborateAssign
!(S
[0]));
531 static assert(!hasElaborateAssign
!(S
[]));
534 static assert(!hasElaborateAssign
!int);
535 static assert(!hasElaborateAssign
!(string
[]));
536 static assert(!hasElaborateAssign
!Object
);
539 template hasIndirections(T
)
541 static if (is(T
== enum))
542 enum hasIndirections
= hasIndirections
!(OriginalType
!T
);
543 else static if (is(T
== struct) ||
is(T
== union))
544 enum hasIndirections
= anySatisfy
!(.hasIndirections
, typeof(T
.tupleof
));
545 else static if (__traits(isAssociativeArray
, T
) ||
is(T
== class) ||
is(T
== interface))
546 enum hasIndirections
= true;
547 else static if (is(T
== E
[N
], E
, size_t N
))
548 enum hasIndirections
= T
.sizeof
&& (is(E
== void) || hasIndirections
!(BaseElemOf
!E
));
549 else static if (isFunctionPointer
!T
)
550 enum hasIndirections
= false;
552 enum hasIndirections
= isPointer
!T || isDelegate
!T || isDynamicArray
!T
;
557 static assert(!hasIndirections
!int);
558 static assert(!hasIndirections
!(const int));
560 static assert( hasIndirections
!(int*));
561 static assert( hasIndirections
!(const int*));
563 static assert( hasIndirections
!(int[]));
564 static assert(!hasIndirections
!(int[42]));
565 static assert(!hasIndirections
!(int[0]));
567 static assert( hasIndirections
!(int*));
568 static assert( hasIndirections
!(int*[]));
569 static assert( hasIndirections
!(int*[42]));
570 static assert(!hasIndirections
!(int*[0]));
572 static assert( hasIndirections
!string
);
573 static assert( hasIndirections
!(string
[]));
574 static assert( hasIndirections
!(string
[42]));
575 static assert(!hasIndirections
!(string
[0]));
577 static assert( hasIndirections
!(void[]));
578 static assert( hasIndirections
!(void[17]));
579 static assert(!hasIndirections
!(void[0]));
581 static assert( hasIndirections
!(string
[int]));
582 static assert( hasIndirections
!(string
[int]*));
583 static assert( hasIndirections
!(string
[int][]));
584 static assert( hasIndirections
!(string
[int][12]));
585 static assert(!hasIndirections
!(string
[int][0]));
587 static assert(!hasIndirections
!(int function(string
)));
588 static assert( hasIndirections
!(int delegate(string
)));
589 static assert(!hasIndirections
!(const(int function(string
))));
590 static assert( hasIndirections
!(const(int delegate(string
))));
591 static assert(!hasIndirections
!(immutable(int function(string
))));
592 static assert( hasIndirections
!(immutable(int delegate(string
))));
595 static assert( hasIndirections
!C
);
597 static interface I
{}
598 static assert( hasIndirections
!I
);
602 static assert(!hasIndirections
!E
);
606 static assert( hasIndirections
!E
);
609 enum E
: string
{ a
= "" }
610 static assert( hasIndirections
!E
);
613 enum E
: int[] { a
= null }
614 static assert( hasIndirections
!E
);
617 enum E
: int[3] { a
= [1, 2, 3] }
618 static assert(!hasIndirections
!E
);
621 enum E
: int*[3] { a
= [null, null, null] }
622 static assert( hasIndirections
!E
);
625 enum E
: int*[0] { a
= int*[0].init
}
626 static assert(!hasIndirections
!E
);
629 enum E
: C
{ a
= null }
630 static assert( hasIndirections
!E
);
633 enum E
: I
{ a
= null }
634 static assert( hasIndirections
!E
);
639 static assert(!hasIndirections
!S
);
641 enum E
: S
{ a
= S
.init
}
642 static assert(!hasIndirections
!S
);
645 static struct S
{ int i
; }
646 static assert(!hasIndirections
!S
);
648 enum E
: S
{ a
= S
.init
}
649 static assert(!hasIndirections
!S
);
652 static struct S
{ C c
; }
653 static assert( hasIndirections
!S
);
655 enum E
: S
{ a
= S
.init
}
656 static assert( hasIndirections
!S
);
659 static struct S
{ int[] arr
; }
660 static assert( hasIndirections
!S
);
662 enum E
: S
{ a
= S
.init
}
663 static assert( hasIndirections
!S
);
667 struct S
{ void foo() { ++local
; } }
668 static assert( hasIndirections
!S
);
670 enum E
: S
{ a
= S
.init
}
671 static assert( hasIndirections
!S
);
676 static assert(!hasIndirections
!U
);
679 static union U
{ int i
; }
680 static assert(!hasIndirections
!U
);
683 static union U
{ C c
; }
684 static assert( hasIndirections
!U
);
687 static union U
{ int[] arr
; }
688 static assert( hasIndirections
!U
);
692 // https://issues.dlang.org/show_bug.cgi?id=12000
697 static assert(hasIndirections
!T
);
708 template hasUnsharedIndirections(T
)
710 static if (is(T
== immutable))
711 enum hasUnsharedIndirections
= false;
712 else static if (is(T
== struct) ||
is(T
== union))
713 enum hasUnsharedIndirections
= anySatisfy
!(.hasUnsharedIndirections
, Fields
!T
);
714 else static if (is(T
: E
[N
], E
, size_t N
))
715 enum hasUnsharedIndirections
= is(E
== void) ?
false : hasUnsharedIndirections
!E
;
716 else static if (isFunctionPointer
!T
)
717 enum hasUnsharedIndirections
= false;
718 else static if (isPointer
!T
)
719 enum hasUnsharedIndirections
= !is(T
: shared(U
)*, U
) && !is(T
: immutable(U
)*, U
);
720 else static if (isDynamicArray
!T
)
721 enum hasUnsharedIndirections
= !is(T
: shared(V
)[], V
) && !is(T
: immutable(V
)[], V
);
722 else static if (is(T
== class) ||
is(T
== interface))
723 enum hasUnsharedIndirections
= !is(T
: shared(W
), W
);
725 enum hasUnsharedIndirections
= isDelegate
!T ||
__traits(isAssociativeArray
, T
); // TODO: how to handle these?
730 static struct Foo
{ shared(int)* val
; }
732 static assert(!hasUnsharedIndirections
!(immutable(char)*));
733 static assert(!hasUnsharedIndirections
!(string
));
735 static assert(!hasUnsharedIndirections
!(Foo
));
736 static assert( hasUnsharedIndirections
!(Foo
*));
737 static assert(!hasUnsharedIndirections
!(shared(Foo
)*));
738 static assert(!hasUnsharedIndirections
!(immutable(Foo
)*));
741 struct HasContextPointer
{ int opCall() { return ++local
; } }
742 static assert(hasIndirections
!HasContextPointer
);
745 enum bool isAggregateType(T
) = is(T
== struct) ||
is(T
== union) ||
746 is(T
== class) ||
is(T
== interface);
748 enum bool isPointer(T
) = is(T
== U
*, U
) && !isAggregateType
!T
;
750 enum bool isDynamicArray(T
) = is(DynamicArrayTypeOf
!T
) && !isAggregateType
!T
;
752 template OriginalType(T
)
756 static if (is(T U
== enum)) alias Impl
= OriginalType
!U
;
760 alias OriginalType
= ModifyTypePreservingTQ
!(Impl
, T
);
763 template DynamicArrayTypeOf(T
)
765 static if (is(AliasThisTypeOf
!T AT
) && !is(AT
[] == AT
))
766 alias X
= DynamicArrayTypeOf
!AT
;
768 alias X
= OriginalType
!T
;
770 static if (is(Unqual
!X
: E
[], E
) && !is(typeof({ enum n
= X
.length
; })))
771 alias DynamicArrayTypeOf
= X
;
773 static assert(0, T
.stringof
~ " is not a dynamic array");
776 private template AliasThisTypeOf(T
)
777 if (isAggregateType
!T
)
779 alias members
= __traits(getAliasThis
, T
);
781 static if (members
.length
== 1)
782 alias AliasThisTypeOf
= typeof(__traits(getMember
, T
.init
, members
[0]));
784 static assert(0, T
.stringof
~" does not have alias this type");
787 template isFunctionPointer(T
...)
790 static if (is(T
[0] U
) ||
is(typeof(T
[0]) U
))
792 static if (is(U F
: F
*) && is(F
== function))
793 enum bool isFunctionPointer
= true;
795 enum bool isFunctionPointer
= false;
798 enum bool isFunctionPointer
= false;
801 template isDelegate(T
...)
804 static if (is(typeof(& T
[0]) U
: U
*) && is(typeof(& T
[0]) U
== delegate))
806 // T is a (nested) function symbol.
807 enum bool isDelegate
= true;
809 else static if (is(T
[0] W
) ||
is(typeof(T
[0]) W
))
811 // T is an expression or a type. Take the type of it and examine.
812 enum bool isDelegate
= is(W
== delegate);
815 enum bool isDelegate
= false;
819 template Filter(alias pred
, TList
...)
821 static if (TList
.length
== 0)
823 alias Filter
= AliasSeq
!();
825 else static if (TList
.length
== 1)
827 static if (pred
!(TList
[0]))
828 alias Filter
= AliasSeq
!(TList
[0]);
830 alias Filter
= AliasSeq
!();
832 /* The next case speeds up compilation by reducing
833 * the number of Filter instantiations
835 else static if (TList
.length
== 2)
837 static if (pred
!(TList
[0]))
839 static if (pred
!(TList
[1]))
840 alias Filter
= AliasSeq
!(TList
[0], TList
[1]);
842 alias Filter
= AliasSeq
!(TList
[0]);
846 static if (pred
!(TList
[1]))
847 alias Filter
= AliasSeq
!(TList
[1]);
849 alias Filter
= AliasSeq
!();
856 Filter
!(pred
, TList
[ 0 .. $/2]),
857 Filter
!(pred
, TList
[$/2 .. $ ]));
861 // std.meta.staticMap
862 template staticMap(alias F
, T
...)
864 static if (T
.length
== 0)
866 alias staticMap
= AliasSeq
!();
868 else static if (T
.length
== 1)
870 alias staticMap
= AliasSeq
!(F
!(T
[0]));
872 /* Cases 2 to 8 improve compile performance by reducing
873 * the number of recursive instantiations of staticMap
875 else static if (T
.length
== 2)
877 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]));
879 else static if (T
.length
== 3)
881 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]), F
!(T
[2]));
883 else static if (T
.length
== 4)
885 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]), F
!(T
[2]), F
!(T
[3]));
887 else static if (T
.length
== 5)
889 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]), F
!(T
[2]), F
!(T
[3]), F
!(T
[4]));
891 else static if (T
.length
== 6)
893 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]), F
!(T
[2]), F
!(T
[3]), F
!(T
[4]), F
!(T
[5]));
895 else static if (T
.length
== 7)
897 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]), F
!(T
[2]), F
!(T
[3]), F
!(T
[4]), F
!(T
[5]), F
!(T
[6]));
899 else static if (T
.length
== 8)
901 alias staticMap
= AliasSeq
!(F
!(T
[0]), F
!(T
[1]), F
!(T
[2]), F
!(T
[3]), F
!(T
[4]), F
!(T
[5]), F
!(T
[6]), F
!(T
[7]));
907 staticMap
!(F
, T
[ 0 .. $/2]),
908 staticMap
!(F
, T
[$/2 .. $ ]));
912 // std.exception.assertCTFEable
913 version (CoreUnittest
) package(core
)
914 void assertCTFEable(alias dg
)()
916 static assert({ cast(void) dg(); return true; }());
920 // std.traits.FunctionTypeOf
922 Get the function type from a callable object `func`.
924 Using builtin `typeof` on a property function yields the types of the
925 property value, not of the property function itself. Still,
926 `FunctionTypeOf` is able to obtain function types of properties.
929 Do not confuse function types with function pointer types; function types are
930 usually used for compile-time reflection purposes.
932 template FunctionTypeOf(func
...)
933 if (func
.length
== 1 /*&& isCallable!func*/)
935 static if (is(typeof(& func
[0]) Fsym
: Fsym
*) && is(Fsym
== function) ||
is(typeof(& func
[0]) Fsym
== delegate))
937 alias FunctionTypeOf
= Fsym
; // HIT: (nested) function symbol
939 else static if (is(typeof(& func
[0].opCall
) Fobj
== delegate))
941 alias FunctionTypeOf
= Fobj
; // HIT: callable object
943 else static if (is(typeof(& func
[0].opCall
) Ftyp
: Ftyp
*) && is(Ftyp
== function))
945 alias FunctionTypeOf
= Ftyp
; // HIT: callable type
947 else static if (is(func
[0] T
) ||
is(typeof(func
[0]) T
))
949 static if (is(T
== function))
950 alias FunctionTypeOf
= T
; // HIT: function
951 else static if (is(T Fptr
: Fptr
*) && is(Fptr
== function))
952 alias FunctionTypeOf
= Fptr
; // HIT: function pointer
953 else static if (is(T Fdlg
== delegate))
954 alias FunctionTypeOf
= Fdlg
; // HIT: delegate
966 int value() @property { return 0; }
968 static assert(is( typeof(C
.value
) == int ));
969 static assert(is( FunctionTypeOf
!(C
.value
) == function ));
975 int propGet() @property;
976 int propSet(int a
) @property;
977 int function(int) test_fp
;
978 int delegate(int) test_dg
;
979 static assert(is( typeof(test) == FunctionTypeOf
!(typeof(test)) ));
980 static assert(is( typeof(test) == FunctionTypeOf
!test ));
981 static assert(is( typeof(test) == FunctionTypeOf
!test_fp
));
982 static assert(is( typeof(test) == FunctionTypeOf
!test_dg
));
983 alias int GetterType() @property;
984 alias int SetterType(int) @property;
985 static assert(is( FunctionTypeOf
!propGet
== GetterType
));
986 static assert(is( FunctionTypeOf
!propSet
== SetterType
));
988 interface Prop
{ int prop() @property; }
990 static assert(is( FunctionTypeOf
!(Prop
.prop
) == GetterType
));
991 static assert(is( FunctionTypeOf
!(prop
.prop
) == GetterType
));
993 class Callable
{ int opCall(int) { return 0; } }
994 auto call = new Callable
;
995 static assert(is( FunctionTypeOf
!call == typeof(test) ));
997 struct StaticCallable
{ static int opCall(int) { return 0; } }
998 StaticCallable stcall_val
;
999 StaticCallable
* stcall_ptr
;
1000 static assert(is( FunctionTypeOf
!stcall_val
== typeof(test) ));
1001 static assert(is( FunctionTypeOf
!stcall_ptr
== typeof(test) ));
1008 int test() @property;
1010 alias ov
= __traits(getVirtualMethods
, Overloads
, "test");
1011 alias F_ov0
= FunctionTypeOf
!(ov
[0]);
1012 alias F_ov1
= FunctionTypeOf
!(ov
[1]);
1013 alias F_ov2
= FunctionTypeOf
!(ov
[2]);
1014 alias F_ov3
= FunctionTypeOf
!(ov
[3]);
1015 static assert(is(F_ov0
* == void function(string
)));
1016 static assert(is(F_ov1
* == real function(real)));
1017 static assert(is(F_ov2
* == int function(int)));
1018 static assert(is(F_ov3
* == int function() @property));
1020 alias F_dglit
= FunctionTypeOf
!((int a
){ return a
; });
1021 static assert(is(F_dglit
* : int function(int)));
1024 // std.traits.ReturnType
1026 Get the type of the return value from a function,
1027 a pointer to function, a delegate, a struct
1028 with an opCall, a pointer to a struct with an opCall,
1029 or a class with an `opCall`. Please note that $(D_KEYWORD ref)
1030 is not part of a type, but the attribute of the function
1031 (see template $(LREF functionAttributes)).
1033 template ReturnType(func
...)
1034 if (func
.length
== 1 /*&& isCallable!func*/)
1036 static if (is(FunctionTypeOf
!func R
== return))
1037 alias ReturnType
= R
;
1039 static assert(0, "argument has no return type");
1046 ReturnType
!foo x
; // x is declared as int
1053 int opCall (int i
) { return 1;}
1056 alias ShouldBeInt
= ReturnType
!G
;
1057 static assert(is(ShouldBeInt
== int));
1060 static assert(is(ReturnType
!g
== int));
1063 alias pg
= ReturnType
!p
;
1064 static assert(is(pg
== int));
1068 int opCall (int i
) { return 1;}
1071 static assert(is(ReturnType
!C
== int));
1074 static assert(is(ReturnType
!c
== int));
1078 int prop() @property { return 0; }
1080 alias R_Test_prop
= ReturnType
!(Test
.prop
);
1081 static assert(is(R_Test_prop
== int));
1083 alias R_dglit
= ReturnType
!((int a
) { return a
; });
1084 static assert(is(R_dglit
== int));
1087 // std.traits.Parameters
1089 Get, as a tuple, the types of the parameters to a function, a pointer
1090 to function, a delegate, a struct with an `opCall`, a pointer to a
1091 struct with an `opCall`, or a class with an `opCall`.
1093 template Parameters(func
...)
1094 if (func
.length
== 1 /*&& isCallable!func*/)
1096 static if (is(FunctionTypeOf
!func P
== function))
1097 alias Parameters
= P
;
1099 static assert(0, "argument has no parameters");
1106 void bar(Parameters
!foo
); // declares void bar(int, long);
1107 void abc(Parameters
!foo
[1]); // declares void abc(long);
1112 int foo(int i
, bool b
) { return 0; }
1113 static assert(is(Parameters
!foo
== AliasSeq
!(int, bool)));
1114 static assert(is(Parameters
!(typeof(&foo
)) == AliasSeq
!(int, bool)));
1116 struct S
{ real opCall(real r
, int i
) { return 0.0; } }
1118 static assert(is(Parameters
!S
== AliasSeq
!(real, int)));
1119 static assert(is(Parameters
!(S
*) == AliasSeq
!(real, int)));
1120 static assert(is(Parameters
!s
== AliasSeq
!(real, int)));
1124 int prop() @property { return 0; }
1126 alias P_Test_prop
= Parameters
!(Test
.prop
);
1127 static assert(P_Test_prop
.length
== 0);
1129 alias P_dglit
= Parameters
!((int a
){});
1130 static assert(P_dglit
.length
== 1);
1131 static assert(is(P_dglit
[0] == int));
1134 // Return `true` if `Type` has `member` that evaluates to `true` in a static if condition
1135 enum isTrue(Type
, string member
) = __traits(compiles
, { static if (__traits(getMember
, Type
, member
)) {} else static assert(0); });
1151 static assert( isTrue
!(T
, "a"));
1152 static assert(!isTrue
!(T
, "b"));
1153 static assert( isTrue
!(T
, "c"));
1154 static assert( isTrue
!(T
, "d"));
1155 static assert( isTrue
!(T
, "e"));
1156 static assert( isTrue
!(T
, "f"));
1157 static assert(!isTrue
!(T
, "g"));
1158 static assert(!isTrue
!(T
, "h"));
1161 template hasUDA(alias symbol
, alias attribute
)
1163 enum isAttr(T
) = is(T
== attribute
);
1165 enum hasUDA
= anySatisfy
!(isAttr
, __traits(getAttributes
, symbol
));
1175 @SomeUDA int oneUDA
;
1176 @SomeUDA @SomeUDA int twoUDAs
;
1179 static assert(hasUDA
!(Test
.oneUDA
, SomeUDA
));
1180 static assert(hasUDA
!(Test
.twoUDAs
, SomeUDA
));
1181 static assert(!hasUDA
!(Test
.woUDA
, SomeUDA
));