1 // Written in the D programming language.
4 This module implements a variety of type constructors, i.e., templates
5 that allow construction of new, useful general-purpose types.
7 $(SCRIPT inhibitQuickIndex = 1;)
10 $(TR $(TH Category) $(TH Symbols))
24 $(TR $(TD Memory allocation) $(TD
25 $(LREF SafeRefCounted)
26 $(LREF safeRefCounted)
27 $(LREF RefCountedAutoInitialize)
31 $(TR $(TD Code generation) $(TD
34 $(LREF generateAssertTrap)
35 $(LREF generateEmptyFunction)
38 $(TR $(TD Nullable) $(TD
44 $(TR $(TD Proxies) $(TD
61 Copyright: Copyright the respective authors, 2008-
62 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
63 Source: $(PHOBOSSRC std/typecons.d)
64 Authors: $(HTTP erdani.org, Andrei Alexandrescu),
65 $(HTTP bartoszmilewski.wordpress.com, Bartosz Milewski),
72 import std
.format
.spec
: singleSpec
, FormatSpec
;
73 import std
.format
.write
: formatValue
;
74 import std
.meta
: AliasSeq
, allSatisfy
;
75 import std
.range
.primitives
: isOutputRange
;
77 import std
.internal
.attributes
: betterC
;
82 alias Coord
= Tuple
!(int, "x", int, "y", int, "z");
84 c
[1] = 1; // access by index
85 c
.z
= 1; // access by given name
86 assert(c
== Coord(0, 1, 1));
88 // names can be omitted, types can be mixed
89 alias DictEntry
= Tuple
!(string
, int);
90 auto dict
= DictEntry("seven", 7);
92 // element types can be inferred
93 assert(tuple(2, 3, 4)[1] == 3);
94 // type inference works with names too
95 auto tup
= tuple
!("x", "y", "z")(2, 3, 4);
99 /// Rebindable references to const and immutable objects
104 void foo() const @safe {}
106 const w1
= new Widget
, w2
= new Widget
;
108 // w1 = w2 would not work; can't rebind const object
110 auto r
= Rebindable
!(const Widget
)(w1
);
111 // invoke method as if r were a Widget object
113 // rebind r to refer to another object
118 Encapsulates unique ownership of a resource.
120 When a `Unique!T` goes out of scope it will call `destroy`
121 on the resource `T` that it manages, unless it is transferred.
122 One important consequence of `destroy` is that it will call the
123 destructor of the resource `T`. GC-managed references are not
124 guaranteed to be valid during a destructor call, but other members of
125 `T`, such as file handles or pointers to `malloc` memory, will
126 still be valid during the destructor call. This allows the resource
127 `T` to deallocate or clean up any non-GC resources.
129 If it is desirable to persist a `Unique!T` outside of its original
130 scope, then it can be transferred. The transfer can be explicit, by
131 calling `release`, or implicit, when returning Unique from a
132 function. The resource `T` can be a polymorphic class object or
133 instance of an interface, in which case Unique behaves polymorphically
136 If `T` is a value type, then `Unique!T` will be implemented
137 as a reference to a `T`.
141 /** Represents a reference to `T`. Resolves to `T*` if `T` is a value type. */
142 static if (is(T
== class) ||
is(T
== interface))
148 // Deferred in case we get some language support for checking uniqueness.
151 Allows safe construction of `Unique`. It creates the resource and
152 guarantees unique ownership of it (unless `T` publishes aliases of
154 Note: Nested structs/classes cannot be created.
156 args = Arguments to pass to `T`'s constructor.
159 auto u = Unique!(C).create();
162 static Unique
!T
create(A
...)(auto ref A args
)
163 if (__traits(compiles
, new T(args
)))
171 Constructor that takes an rvalue.
172 It will ensure uniqueness, as long as the rvalue
173 isn't just a view on an lvalue (e.g., a cast).
176 Unique!Foo f = new Foo;
184 Constructor that takes an lvalue. It nulls its source.
185 The nulling will ensure uniqueness as long as there
186 are no previous aliases to the source.
195 Constructor that takes a `Unique` of a type that is convertible to our type.
197 Typically used to transfer a `Unique` rvalue of derived type to
198 a `Unique` of base type.
204 Unique!Object uo = uc.release;
214 /// Transfer ownership from a `Unique` of a type that is convertible to our type.
215 void opAssign(U
)(Unique
!U u
)
218 // first delete any resource we own
228 static if (is(T
== class) ||
is(T
== interface))
236 /** Returns whether the resource exists. */
237 @property bool isEmpty() const
241 /** Transfer ownership to a `Unique` rvalue. Nullifies the current contents.
242 Same as calling std.algorithm.move on it.
246 import std
.algorithm
.mutation
: move
;
250 /** Forwards member access to contents. */
254 Postblit operator is undefined to prevent the cloning of `Unique` objects.
268 this(int i
){this.i
= i
;}
272 // Construct a unique instance of S on the heap
273 Unique
!S ut
= new S(5);
274 // Implicit transfer of ownership
277 // Borrow a unique resource by ref
278 void increment(ref Unique
!S ur
)
282 void consume(Unique
!S u2
)
285 // Resource automatically deleted here
293 //consume(u1); // Error: u1 is not copyable
294 // Transfer ownership of the resource
306 // check context pointer still exists - dtor also called before GC frees struct
319 // test conversion to base ref
325 // constructor conversion
326 Unique
!Object u
= Unique
!C(new C
);
327 static assert(!__traits(compiles
, {u
= new C
;}));
330 assert(deleted
== 1);
333 static assert(!__traits(compiles
, {Unique
!Object uo
= uc
;}));
334 Unique
!Object uo
= new C
;
335 // opAssign conversion, deleting uo resource first
339 assert(deleted
== 2);
346 ~this() { debug(Unique
) writeln(" Bar destructor"); }
347 int val() const { return 4; }
349 alias UBar
= Unique
!(Bar
);
352 debug(Unique
) writeln("inside g");
355 auto ub
= UBar(new Bar
);
358 static assert(!__traits(compiles
, {auto ub3
= g(ub
);}));
359 auto ub2
= g(ub
.release
);
361 assert(!ub2
.isEmpty
);
381 int val() const { return 4; }
383 alias UBar
= Unique
!Bar
;
386 debug(Unique
) writeln("inside g");
391 assert(u
.val() == 4);
392 // Resource automatically deleted here
394 auto ub
= UBar(new BarImpl
);
395 assert(BarImpl
.count
== 1);
398 static assert(!__traits(compiles
, {auto ub3
= g(ub
);}));
399 auto ub2
= g(ub
.release
);
401 assert(!ub2
.isEmpty
);
402 consume(ub2
.release
);
403 assert(BarImpl
.count
== 0);
411 int val() const { return 3; }
414 alias UFoo
= Unique
!(Foo
);
421 auto uf
= UFoo(new Foo
);
424 static assert(!__traits(compiles
, {auto uf3
= f(uf
);}));
425 auto uf2
= f(uf
.release
);
427 assert(!uf2
.isEmpty
);
430 // ensure Unique behaves correctly through const access paths
433 struct Bar
{int val
;}
436 Unique
!Bar bar
= new Bar
;
441 const Foo
* ptr
= &foo
;
442 static assert(is(typeof(ptr
) == const(Foo
*)));
443 static assert(is(typeof(ptr
.bar
) == const(Unique
!Bar
)));
444 static assert(is(typeof(ptr
.bar
.val
) == const(int)));
445 assert(ptr
.bar
.val
== 6);
447 assert(ptr
.bar
.val
== 7);
450 // Used in Tuple.toString
451 private template sharedToString(alias field
)
452 if (is(typeof(field
) == shared))
454 static immutable sharedToString
= typeof(field
).stringof
;
457 private template sharedToString(alias field
)
458 if (!is(typeof(field
) == shared))
460 alias sharedToString
= field
;
463 private enum bool distinctFieldNames(names
...) = __traits(compiles
,
465 static foreach (__name
; names
)
466 static if (is(typeof(__name
) : string
))
467 mixin("enum int " ~ __name
~ " = 0;");
472 static assert(!distinctFieldNames
!(string
, "abc", string
, "abc"));
473 static assert(distinctFieldNames
!(string
, "abc", int, "abd"));
474 static assert(!distinctFieldNames
!(int, "abc", string
, "abd", int, "abc"));
475 // https://issues.dlang.org/show_bug.cgi?id=19240
476 static assert(!distinctFieldNames
!(int, "int"));
480 // Parse (type,name) pairs (FieldSpecs) out of the specified
481 // arguments. Some fields would have name, others not.
482 private template parseSpecs(Specs
...)
484 static if (Specs
.length
== 0)
486 alias parseSpecs
= AliasSeq
!();
488 else static if (is(Specs
[0]))
490 static if (is(typeof(Specs
[1]) : string
))
493 AliasSeq
!(FieldSpec
!(Specs
[0 .. 2]),
494 parseSpecs
!(Specs
[2 .. $]));
499 AliasSeq
!(FieldSpec
!(Specs
[0]),
500 parseSpecs
!(Specs
[1 .. $]));
505 static assert(0, "Attempted to instantiate Tuple with an "
506 ~"invalid argument: "~ Specs
[0].stringof
);
510 private template FieldSpec(T
, string s
= "")
516 // Used with staticMap.
517 private alias extractType(alias spec
) = spec
.Type
;
518 private alias extractName(alias spec
) = spec
.name
;
519 private template expandSpec(alias spec
)
521 static if (spec
.name
.length
== 0)
522 alias expandSpec
= AliasSeq
!(spec
.Type
);
524 alias expandSpec
= AliasSeq
!(spec
.Type
, spec
.name
);
528 private enum areCompatibleTuples(Tup1
, Tup2
, string op
) =
529 isTuple
!(OriginalType
!Tup2
) && Tup1
.Types
.length
== Tup2
.Types
.length
&& is(typeof(
530 (ref Tup1 tup1
, ref Tup2 tup2
)
532 static foreach (i
; 0 .. Tup1
.Types
.length
)
534 auto lhs
= typeof(tup1
.field
[i
]).init
;
535 auto rhs
= typeof(tup2
.field
[i
]).init
;
536 static if (op
== "=")
539 auto result
= mixin("lhs "~op
~" rhs");
543 private enum areBuildCompatibleTuples(Tup1
, Tup2
) =
544 isTuple
!Tup2
&& Tup1
.Types
.length
== Tup2
.Types
.length
&& is(typeof(
546 static foreach (i
; 0 .. Tup1
.Types
.length
)
547 static assert(isBuildable
!(Tup1
.Types
[i
], Tup2
.Types
[i
]));
550 // Returns `true` iff a `T` can be initialized from a `U`.
551 private enum isBuildable(T
, U
) = is(typeof(
556 // Helper for partial instantiation
557 private template isBuildableFrom(U
)
559 enum isBuildableFrom(T
) = isBuildable
!(T
, U
);
562 private enum hasCopyCtor(T
) = __traits(hasCopyConstructor
, T
);
564 // T is expected to be an instantiation of Tuple.
565 private template noMemberHasCopyCtor(T
)
567 import std
.meta
: anySatisfy
;
568 enum noMemberHasCopyCtor
= !anySatisfy
!(hasCopyCtor
, T
.Types
);
572 _Tuple of values, for example $(D Tuple!(int, string)) is a record that
573 stores an `int` and a `string`. `Tuple` can be used to bundle
574 values together, notably when returning multiple values from a
575 function. If `obj` is a `Tuple`, the individual members are
576 accessible with the syntax `obj[0]` for the first field, `obj[1]`
577 for the second, and so on.
579 See_Also: $(LREF tuple).
582 Specs = A list of types (and optionally, member names) that the `Tuple` contains.
584 template Tuple(Specs
...)
585 if (distinctFieldNames
!(Specs
))
587 import std
.meta
: staticMap
;
589 alias fieldSpecs
= parseSpecs
!Specs
;
591 // Generates named fields as follows:
592 // alias name_0 = Identity!(field[0]);
593 // alias name_1 = Identity!(field[1]);
595 // NOTE: field[k] is an expression (which yields a symbol of a
596 // variable) and can't be aliased directly.
597 enum injectNamedFields
= ()
600 static foreach (i
, val
; fieldSpecs
)
602 immutable si
= i
.stringof
;
603 decl
~= "alias _" ~ si
~ " = Identity!(field[" ~ si
~ "]);";
604 if (val
.name
.length
!= 0)
606 decl
~= "alias " ~ val
.name
~ " = _" ~ si
~ ";";
612 // Returns Specs for a subtuple this[from .. to] preserving field
614 alias sliceSpecs(size_t from
, size_t to
) =
615 staticMap
!(expandSpec
, fieldSpecs
[from
.. to
]);
620 * The types of the `Tuple`'s components.
622 alias Types
= staticMap
!(extractType
, fieldSpecs
);
624 private alias _Fields
= Specs
;
627 static if (Specs
.length
== 0) @safe unittest
629 import std
.meta
: AliasSeq
;
630 alias Fields
= Tuple
!(int, "id", string
, float);
631 static assert(is(Fields
.Types
== AliasSeq
!(int, string
, float)));
635 * The names of the `Tuple`'s components. Unnamed fields have empty names.
637 alias fieldNames
= staticMap
!(extractName
, fieldSpecs
);
640 static if (Specs
.length
== 0) @safe unittest
642 import std
.meta
: AliasSeq
;
643 alias Fields
= Tuple
!(int, "id", string
, float);
644 static assert(Fields
.fieldNames
== AliasSeq
!("id", "", ""));
648 * Use `t.expand` for a `Tuple` `t` to expand it into its
649 * components. The result of `expand` acts as if the `Tuple`'s components
650 * were listed as a list of values. (Ordinarily, a `Tuple` acts as a
654 mixin(injectNamedFields());
657 static if (Specs
.length
== 0) @safe unittest
659 auto t1
= tuple(1, " hello ", 'a');
660 assert(t1
.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`);
662 void takeSeveralTypes(int n
, string s
, bool b
)
664 assert(n
== 4 && s
== "test" && b
== false);
667 auto t2
= tuple(4, "test", false);
668 //t.expand acting as a list of values
669 takeSeveralTypes(t2
.expand
);
672 static if (is(Specs
))
674 // This is mostly to make t[n] work.
680 ref inout(Tuple
!Types
) _Tuple_super() inout @trusted
682 static foreach (i
; 0 .. Types
.length
) // Rely on the field layout
684 static assert(typeof(return).init
.tupleof
[i
].offsetof
==
687 return *cast(typeof(return)*) &(field
[0]);
689 // This is mostly to make t[n] work.
690 alias _Tuple_super
this;
693 // backwards compatibility
694 alias field
= expand
;
697 * Constructor taking one value for each field.
700 * values = A list of values that are either the same
701 * types as those given by the `Types` field
702 * of this `Tuple`, or can implicitly convert
703 * to those types. They must be in the same
704 * order as they appear in `Types`.
706 static if (Types
.length
> 0)
715 static if (Specs
.length
== 0) @safe unittest
717 alias ISD
= Tuple
!(int, string
, double);
718 auto tup
= ISD(1, "test", 3.2);
719 assert(tup
.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`);
723 * Constructor taking a compatible array.
726 * values = A compatible static array to build the `Tuple` from.
727 * Array slices are not supported.
729 this(U
, size_t n
)(U
[n
] values
)
730 if (n
== Types
.length
&& allSatisfy
!(isBuildableFrom
!U
, Types
))
732 static foreach (i
; 0 .. Types
.length
)
734 field
[i
] = values
[i
];
739 static if (Specs
.length
== 0) @safe unittest
742 Tuple
!(int, int) t
= ints
;
746 * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible
747 * $(B iff) they are both of the same length, and, for each type `T` on the
748 * left-hand side, the corresponding type `U` on the right-hand side can
749 * implicitly convert to `T`.
752 * another = A compatible `Tuple` to build from. Its type must be
753 * compatible with the target `Tuple`'s type.
756 if (areBuildCompatibleTuples
!(typeof(this), U
) &&
757 (noMemberHasCopyCtor
!(typeof(this)) ||
!is(Unqual
!U
== Unqual
!(typeof(this)))))
759 field
[] = another
.field
[];
763 static if (Specs
.length
== 0) @safe unittest
765 alias IntVec
= Tuple
!(int, int, int);
766 alias DubVec
= Tuple
!(double, double, double);
768 IntVec iv
= tuple(1, 1, 1);
770 //Ok, int can implicitly convert to double
772 //Error: double cannot implicitly convert to int
777 * Comparison for equality. Two `Tuple`s are considered equal
778 * $(B iff) they fulfill the following criteria:
781 * $(LI Each `Tuple` is the same length.)
782 * $(LI For each type `T` on the left-hand side and each type
783 * `U` on the right-hand side, values of type `T` can be
784 * compared with values of type `U`.)
785 * $(LI For each value `v1` on the left-hand side and each value
786 * `v2` on the right-hand side, the expression `v1 == v2` is
790 * rhs = The `Tuple` to compare against. It must meeting the criteria
791 * for comparison between `Tuple`s.
794 * true if both `Tuple`s are equal, otherwise false.
796 bool opEquals(R
)(R rhs
)
797 if (areCompatibleTuples
!(typeof(this), R
, "=="))
799 return field
[] == rhs
.field
[];
803 bool opEquals(R
)(R rhs
) const
804 if (areCompatibleTuples
!(typeof(this), R
, "=="))
806 return field
[] == rhs
.field
[];
810 bool opEquals(R
...)(auto ref R rhs
)
811 if (R
.length
> 1 && areCompatibleTuples
!(typeof(this), Tuple
!R
, "=="))
813 static foreach (i
; 0 .. Types
.length
)
814 if (field
[i
] != rhs
[i
])
821 static if (Specs
.length
== 0) @safe unittest
823 Tuple
!(int, string
) t1
= tuple(1, "test");
824 Tuple
!(double, string
) t2
= tuple(1.0, "test");
825 //Ok, int can be compared with double and
826 //both have a value of 1
831 * Comparison for ordering.
834 * rhs = The `Tuple` to compare against. It must meet the criteria
835 * for comparison between `Tuple`s.
838 * For any values `v1` contained by the left-hand side tuple and any
839 * values `v2` contained by the right-hand side:
841 * 0 if `v1 == v2` for all members or the following value for the
842 * first position were the mentioned criteria is not satisfied:
845 * $(LI NaN, in case one of the operands is a NaN.)
846 * $(LI A negative number if the expression `v1 < v2` is true.)
847 * $(LI A positive number if the expression `v1 > v2` is true.))
850 if (areCompatibleTuples
!(typeof(this), R
, "<"))
852 static foreach (i
; 0 .. Types
.length
)
854 if (field
[i
] != rhs
.field
[i
])
856 import std
.math
.traits
: isNaN
;
857 static if (isFloatingPoint
!(Types
[i
]))
862 static if (isFloatingPoint
!(typeof(rhs
.field
[i
])))
864 if (isNaN(rhs
.field
[i
]))
867 static if (is(typeof(field
[i
].opCmp(rhs
.field
[i
]))) &&
868 isFloatingPoint
!(typeof(field
[i
].opCmp(rhs
.field
[i
]))))
870 if (isNaN(field
[i
].opCmp(rhs
.field
[i
])))
874 return field
[i
] < rhs
.field
[i
] ?
-1 : 1;
881 auto opCmp(R
)(R rhs
) const
882 if (areCompatibleTuples
!(typeof(this), R
, "<"))
884 static foreach (i
; 0 .. Types
.length
)
886 if (field
[i
] != rhs
.field
[i
])
888 import std
.math
.traits
: isNaN
;
889 static if (isFloatingPoint
!(Types
[i
]))
894 static if (isFloatingPoint
!(typeof(rhs
.field
[i
])))
896 if (isNaN(rhs
.field
[i
]))
899 static if (is(typeof(field
[i
].opCmp(rhs
.field
[i
]))) &&
900 isFloatingPoint
!(typeof(field
[i
].opCmp(rhs
.field
[i
]))))
902 if (isNaN(field
[i
].opCmp(rhs
.field
[i
])))
906 return field
[i
] < rhs
.field
[i
] ?
-1 : 1;
913 The first `v1` for which `v1 > v2` is true determines
914 the result. This could lead to unexpected behaviour.
916 static if (Specs
.length
== 0) @safe unittest
918 auto tup1
= tuple(1, 1, 1);
919 auto tup2
= tuple(1, 100, 100);
922 //Only the first result matters for comparison
929 Tuple concatenation is only allowed if all named fields are distinct (no named field of this tuple occurs in `t`
930 and no named field of `t` occurs in this tuple).
933 t = The `Tuple` to concatenate with
935 Returns: A concatenation of this tuple and `t`
937 auto opBinary(string op
, T
)(auto ref T t
)
938 if (op
== "~" && !(is(T
: U
[], U
) && isTuple
!U
))
940 static if (isTuple
!T
)
942 static assert(distinctFieldNames
!(_Fields
, T
._Fields
),
943 "Cannot concatenate tuples with duplicate fields: " ~ fieldNames
.stringof
~
944 " - " ~ T
.fieldNames
.stringof
);
945 return Tuple
!(_Fields
, T
._Fields
)(expand
, t
.expand
);
949 return Tuple
!(_Fields
, T
)(expand
, t
);
954 auto opBinaryRight(string op
, T
)(auto ref T t
)
955 if (op
== "~" && !(is(T
: U
[], U
) && isTuple
!U
))
957 static if (isTuple
!T
)
959 static assert(distinctFieldNames
!(_Fields
, T
._Fields
),
960 "Cannot concatenate tuples with duplicate fields: " ~ T
.stringof
~
961 " - " ~ fieldNames
.fieldNames
.stringof
);
962 return Tuple
!(T
._Fields
, _Fields
)(t
.expand
, expand
);
966 return Tuple
!(T
, _Fields
)(t
, expand
);
971 * Assignment from another `Tuple`.
974 * rhs = The source `Tuple` to assign from. Each element of the
975 * source `Tuple` must be implicitly assignable to each
976 * respective element of the target `Tuple`.
978 ref Tuple
opAssign(R
)(auto ref R rhs
)
979 if (areCompatibleTuples
!(typeof(this), R
, "="))
981 import std
.algorithm
.mutation
: swap
;
983 static if (is(R
: Tuple
!Types
) && !__traits(isRef
, rhs
) && isTuple
!R
)
987 // Cannot use swap at compile time
988 field
[] = rhs
.field
[];
992 // Use swap-and-destroy to optimize rvalue assignment
993 swap
!(Tuple
!Types
)(this, rhs
);
998 // Do not swap; opAssign should be called on the fields.
999 field
[] = rhs
.field
[];
1005 * Renames the elements of a $(LREF Tuple).
1007 * `rename` uses the passed `names` and returns a new
1008 * $(LREF Tuple) using these names, with the content
1010 * If fewer names are passed than there are members
1011 * of the $(LREF Tuple) then those trailing members are unchanged.
1012 * An empty string will remove the name for that member.
1013 * It is an compile-time error to pass more names than
1014 * there are members of the $(LREF Tuple).
1016 ref rename(names
...)() inout return
1017 if (names
.length
== 0 || allSatisfy
!(isSomeString
, typeof(names
)))
1019 import std
.algorithm
.comparison
: equal
;
1020 // to circumvent https://issues.dlang.org/show_bug.cgi?id=16418
1021 static if (names
.length
== 0 ||
equal([names
], [fieldNames
]))
1025 enum nT
= Types
.length
;
1026 enum nN
= names
.length
;
1027 static assert(nN
<= nT
, "Cannot have more names than tuple members");
1028 alias allNames
= AliasSeq
!(names
, fieldNames
[nN
.. $]);
1030 import std
.meta
: Alias
, aliasSeqOf
;
1032 template GetItem(size_t idx
)
1034 import std
.array
: empty
;
1035 static if (idx
< nT
)
1036 alias GetItem
= Alias
!(Types
[idx
]);
1037 else static if (allNames
[idx
- nT
].empty
)
1038 alias GetItem
= AliasSeq
!();
1040 alias GetItem
= Alias
!(allNames
[idx
- nT
]);
1043 import std
.range
: roundRobin
, iota
;
1044 alias NewTupleT
= Tuple
!(staticMap
!(GetItem
, aliasSeqOf
!(
1045 roundRobin(iota(nT
), iota(nT
, 2*nT
)))));
1046 return *(() @trusted => cast(NewTupleT
*)&this)();
1051 static if (Specs
.length
== 0) @safe unittest
1053 auto t0
= tuple(4, "hello");
1055 auto t0Named
= t0
.rename
!("val", "tag");
1056 assert(t0Named
.val
== 4);
1057 assert(t0Named
.tag
== "hello");
1059 Tuple
!(float, "dat", size_t
[2], "pos") t1
;
1061 auto t1Named
= t1
.rename
!"height";
1062 t1Named
.height
= 3.4f;
1063 assert(t1Named
.height
== 3.4f);
1064 assert(t1Named
.pos
== [2, 1]);
1065 t1Named
.rename
!"altitude".altitude
= 5;
1066 assert(t1Named
.height
== 5);
1068 Tuple
!(int, "a", int, int, "c") t2
;
1070 auto t2Named
= t2
.rename
!("", "b");
1071 // "a" no longer has a name
1072 static assert(!__traits(hasMember
, typeof(t2Named
), "a"));
1073 assert(t2Named
[0] == 3);
1074 assert(t2Named
.b
== 4);
1075 assert(t2Named
.c
== 5);
1077 // not allowed to specify more names than the tuple has members
1078 static assert(!__traits(compiles
, t2
.rename
!("a","b","c","d")));
1080 // use it in a range pipeline
1081 import std
.range
: iota
, zip
;
1082 import std
.algorithm
.iteration
: map
, sum
;
1083 auto res
= zip(iota(1, 4), iota(10, 13))
1084 .map
!(t
=> t
.rename
!("a", "b"))
1085 .map
!(t
=> t
.a
* t
.b
)
1089 const tup
= Tuple
!(int, "a", int, "b")(2, 3);
1090 const renamed
= tup
.rename
!("c", "d");
1091 assert(renamed
.c
+ renamed
.d
== 5);
1095 * Overload of $(LREF _rename) that takes an associative array
1096 * `translate` as a template parameter, where the keys are
1097 * either the names or indices of the members to be changed
1098 * and the new names are the corresponding values.
1099 * Every key in `translate` must be the name of a member of the
1101 * The same rules for empty strings apply as for the variadic
1102 * template overload of $(LREF _rename).
1104 ref rename(alias translate
)() inout
1105 if (is(typeof(translate
) : V
[K
], V
, K
) && isSomeString
!V
&&
1106 (isSomeString
!K ||
is(K
: size_t
)))
1108 import std
.meta
: aliasSeqOf
;
1109 import std
.range
: ElementType
;
1110 static if (isSomeString
!(ElementType
!(typeof(translate
.keys
))))
1113 import std
.conv
: to
;
1114 import std
.algorithm
.iteration
: filter
;
1115 import std
.algorithm
.searching
: canFind
;
1116 enum notFound
= translate
.keys
1117 .filter
!(k
=> fieldNames
.canFind(k
) == -1);
1118 static assert(notFound
.empty
, "Cannot find members "
1119 ~ notFound
.to
!string
~ " in type "
1120 ~ typeof(this).stringof
);
1122 return this.rename
!(aliasSeqOf
!(
1124 import std
.array
: empty
;
1125 auto names
= [fieldNames
];
1126 foreach (ref n
; names
)
1128 if (auto p
= n
in translate
)
1136 import std
.algorithm
.iteration
: filter
;
1137 import std
.conv
: to
;
1138 enum invalid
= translate
.keys
.
1139 filter
!(k
=> k
< 0 || k
>= this.length
);
1140 static assert(invalid
.empty
, "Indices " ~ invalid
.to
!string
1141 ~ " are out of bounds for tuple with length "
1142 ~ this.length
.to
!string
);
1144 return this.rename
!(aliasSeqOf
!(
1146 auto names
= [fieldNames
];
1147 foreach (k
, v
; translate
)
1155 static if (Specs
.length
== 0) @safe unittest
1157 //replacing names by their current name
1159 Tuple
!(float, "dat", size_t
[2], "pos") t1
;
1161 auto t1Named
= t1
.rename
!(["dat": "height"]);
1162 t1Named
.height
= 3.4;
1163 assert(t1Named
.pos
== [2, 1]);
1164 t1Named
.rename
!(["height": "altitude"]).altitude
= 5;
1165 assert(t1Named
.height
== 5);
1167 Tuple
!(int, "a", int, "b") t2
;
1169 auto t2Named
= t2
.rename
!(["a": "b", "b": "c"]);
1170 assert(t2Named
.b
== 3);
1171 assert(t2Named
.c
== 4);
1173 const t3
= Tuple
!(int, "a", int, "b")(3, 4);
1174 const t3Named
= t3
.rename
!(["a": "b", "b": "c"]);
1175 assert(t3Named
.b
== 3);
1176 assert(t3Named
.c
== 4);
1180 static if (Specs
.length
== 0) @system unittest
1182 //replace names by their position
1184 Tuple
!(float, "dat", size_t
[2], "pos") t1
;
1186 auto t1Named
= t1
.rename
!([0: "height"]);
1187 t1Named
.height
= 3.4;
1188 assert(t1Named
.pos
== [2, 1]);
1189 t1Named
.rename
!([0: "altitude"]).altitude
= 5;
1190 assert(t1Named
.height
== 5);
1192 Tuple
!(int, "a", int, "b", int, "c") t2
;
1193 t2
= tuple(3, 4, 5);
1194 auto t2Named
= t2
.rename
!([0: "c", 2: "a"]);
1195 assert(t2Named
.a
== 5);
1196 assert(t2Named
.b
== 4);
1197 assert(t2Named
.c
== 3);
1200 static if (Specs
.length
== 0) @system unittest
1202 //check that empty translations work fine
1203 enum string
[string
] a0
= null;
1204 enum string
[int] a1
= null;
1205 Tuple
!(float, "a", float, "b") t0
;
1207 auto t1
= t0
.rename
!a0
;
1211 auto t2
= t0
.rename
!a1
;
1214 auto t3
= t0
.rename
;
1220 * Takes a slice by-reference of this `Tuple`.
1223 * from = A `size_t` designating the starting position of the slice.
1224 * to = A `size_t` designating the ending position (exclusive) of the slice.
1227 * A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original.
1228 * It has the same types and values as the range `[from, to$(RPAREN)` in
1232 ref inout(Tuple
!(sliceSpecs
!(from
, to
))) slice(size_t from
, size_t to
)() inout @trusted
1233 if (from
<= to
&& to
<= Types
.length
)
1236 (typeof(this).alignof
% typeof(return).alignof
== 0) &&
1237 (expand
[from
].offsetof
% typeof(return).alignof
== 0),
1238 "Slicing by reference is impossible because of an alignment mistmatch" ~
1239 " (See https://issues.dlang.org/show_bug.cgi?id=15645).");
1241 return *cast(typeof(return)*) &(field
[from
]);
1245 static if (Specs
.length
== 0) @safe unittest
1247 Tuple
!(int, string
, float, double) a
;
1250 auto s
= a
.slice
!(1, 3);
1251 static assert(is(typeof(s
) == Tuple
!(string
, float)));
1252 assert(s
[0] == "abc" && s
[1] == 4.5);
1254 // https://issues.dlang.org/show_bug.cgi?id=15645
1255 Tuple
!(int, short, bool, double) b
;
1256 static assert(!__traits(compiles
, b
.slice
!(2, 4)));
1260 Creates a hash of this `Tuple`.
1263 A `size_t` representing the hash of this `Tuple`.
1265 size_t
toHash() const nothrow @safe
1268 static foreach (i
, T
; Types
)
1270 static if (__traits(compiles
, h
= .hashOf(field
[i
])))
1271 const k
= .hashOf(field
[i
]);
1274 // Workaround for when .hashOf is not both @safe and nothrow.
1275 static if (is(T
: shared U
, U
) && __traits(compiles
, (U
* a
) nothrow @safe => .hashOf(*a
))
1276 && !__traits(hasMember
, T
, "toHash"))
1277 // BUG: Improperly casts away `shared`!
1278 const k
= .hashOf(*(() @trusted => cast(U
*) &field
[i
])());
1280 // BUG: Improperly casts away `shared`!
1281 const k
= typeid(T
).getHash((() @trusted => cast(const void*) &field
[i
])());
1286 // As in boost::hash_combine
1287 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine
1288 h ^
= k
+ 0x9e3779b9 + (h
<< 6) + (h
>>> 2);
1294 * Converts to string.
1297 * The string representation of this `Tuple`.
1299 string
toString()() const
1301 import std
.array
: appender
;
1302 auto app
= appender
!string();
1303 this.toString((const(char)[] chunk
) => app
~= chunk
);
1307 import std
.format
.spec
: FormatSpec
;
1310 * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`.
1312 * $(TABLE2 Formats supported by Tuple,
1313 * $(THEAD Format, Description)
1314 * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.))
1315 * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`$(COMMA) so
1316 * it may contain as many formats as the `Tuple` has fields.))
1317 * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format$(COMMA) that is applied
1318 * on all fields of the `Tuple`. The inner format must be compatible to all
1322 * sink = A `char` accepting delegate
1323 * fmt = A $(REF FormatSpec, std,format)
1325 void toString(DG
)(scope DG sink
) const
1327 auto f
= FormatSpec
!char();
1332 void toString(DG
, Char
)(scope DG sink
, scope const ref FormatSpec
!Char fmt
) const
1334 import std
.format
: format
, FormatException
;
1335 import std
.format
.write
: formattedWrite
;
1336 import std
.range
: only
;
1341 foreach (i
, Type
; Types
)
1347 // TODO: Change this once formattedWrite() works for shared objects.
1348 static if (is(Type
== class) && is(Type
== shared))
1350 sink(Type
.stringof
);
1354 formattedWrite(sink
, fmt
.nested
, this.field
[i
]);
1360 formattedWrite(sink
, fmt
.nested
, staticMap
!(sharedToString
, this.expand
));
1363 else if (fmt
.spec
== 's')
1365 enum header
= Unqual
!(typeof(this)).stringof
~ "(",
1369 foreach (i
, Type
; Types
)
1375 // TODO: Change this once format() works for shared objects.
1376 static if (is(Type
== class) && is(Type
== shared))
1378 sink(Type
.stringof
);
1382 sink(format
!("%(%s%)")(only(field
[i
])));
1389 const spec
= fmt
.spec
;
1390 throw new FormatException(
1391 "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~
1392 Unqual
!(typeof(this)).stringof
~ "', not '%" ~ spec
~ "'.");
1397 static if (Specs
.length
== 0) @safe unittest
1399 import std
.format
: format
;
1401 Tuple
!(int, double)[3] tupList
= [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ];
1404 assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`);
1406 // One Format for each individual component
1407 assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`);
1408 assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand
) == `0x1 v 1.0000 w 0xa`);
1410 // One Format for all components
1411 assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`);
1414 assert(format("%(%(f(%d) = %.1f%); %)", tupList
) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`);
1418 static if (Specs
.length
== 0) @safe unittest
1420 import std
.exception
: assertThrown
;
1421 import std
.format
: format
, FormatException
;
1423 // Error: %( %) missing.
1424 assertThrown
!FormatException(
1425 format("%d, %f", tuple(1, 2.0)) == `1, 2.0`
1428 // Error: %( %| %) missing.
1429 assertThrown
!FormatException(
1430 format("%d", tuple(1, 2)) == `1, 2`
1433 // Error: %d inadequate for double
1434 assertThrown
!FormatException(
1435 format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0`
1444 Tuple
!(int, int) point
;
1445 // assign coordinates
1454 `Tuple` members can be named. It is legal to mix named and unnamed
1455 members. The method above is still applicable to all fields.
1459 alias Entry
= Tuple
!(int, "index", string
, "value");
1463 assert(e
[1] == "Hello");
1468 A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed
1469 fields, i.e. each naming imparts a separate type for the `Tuple`. Two
1470 `Tuple`s differing in naming only are still distinct, even though they
1471 might have the same structure.
1475 Tuple
!(int, "x", int, "y") point1
;
1476 Tuple
!(int, int) point2
;
1477 assert(!is(typeof(point1
) == typeof(point2
)));
1480 /// Use tuples as ranges
1483 import std
.algorithm
.iteration
: sum
;
1484 import std
.range
: only
;
1485 auto t
= tuple(1, 2);
1486 assert(t
.expand
.only
.sum
== 3);
1489 // https://issues.dlang.org/show_bug.cgi?id=4582
1492 static assert(!__traits(compiles
, Tuple
!(string
, "id", int, "id")));
1493 static assert(!__traits(compiles
, Tuple
!(string
, "str", int, "i", string
, "str", float)));
1496 /// Concatenate tuples
1499 import std
.meta
: AliasSeq
;
1500 auto t
= tuple(1, "2") ~ tuple(ushort(42), true);
1501 static assert(is(t
.Types
== AliasSeq
!(int, string
, ushort, bool)));
1502 assert(t
[1] == "2");
1504 assert(t
[3] == true);
1507 // https://issues.dlang.org/show_bug.cgi?id=14637
1511 auto t
= tuple
!"foo"(1.0) ~ tuple
!"bar"("3");
1512 static assert(is(t
.Types
== AliasSeq
!(double, string
)));
1513 static assert(t
.fieldNames
== tuple("foo", "bar"));
1514 assert(t
.foo
== 1.0);
1515 assert(t
.bar
== "3");
1518 // https://issues.dlang.org/show_bug.cgi?id=18824
1522 alias Type
= Tuple
!(int, string
);
1524 auto t
= tuple(2, "s");
1525 // Test opBinaryRight
1529 static assert(is(typeof(arr
) == Type
[]));
1532 static assert(is(typeof(c
) == immutable(Type
)[]));
1538 auto t
= tuple
!"foo"(1.0) ~ "3";
1539 static assert(is(t
.Types
== AliasSeq
!(double, string
)));
1540 assert(t
.foo
== 1.0);
1547 auto t
= "2" ~ tuple
!"foo"(1.0);
1548 static assert(is(t
.Types
== AliasSeq
!(string
, double)));
1549 assert(t
.foo
== 1.0);
1556 auto t
= "2" ~ tuple
!"foo"(1.0) ~ tuple(42, 3.0f) ~ real(1) ~ "a";
1557 static assert(is(t
.Types
== AliasSeq
!(string
, double, int, float, real, string
)));
1558 assert(t
.foo
== 1.0);
1559 assert(t
[0] == "2");
1560 assert(t
[1] == 1.0);
1562 assert(t
[3] == 3.0f);
1563 assert(t
[4] == 1.0);
1564 assert(t
[5] == "a");
1567 // ensure that concatenation of tuples with non-distinct fields is forbidden
1570 static assert(!__traits(compiles
,
1571 tuple
!("a")(0) ~ tuple
!("a")("1")));
1572 static assert(!__traits(compiles
,
1573 tuple
!("a", "b")(0, 1) ~ tuple
!("b", "a")("3", 1)));
1574 static assert(!__traits(compiles
,
1575 tuple
!("a")(0) ~ tuple
!("b", "a")("3", 1)));
1576 static assert(!__traits(compiles
,
1577 tuple
!("a1", "a")(1.0, 0) ~ tuple
!("a2", "a")("3", 0)));
1580 // Ensure that Tuple comparison with non-const opEquals works
1587 bool opEquals(Bad b
)
1593 auto t
= Tuple
!(int, Bad
, string
)(1, Bad(1), "asdf");
1595 //Error: mutable method Bad.opEquals is not callable using a const object
1596 assert(t
== AliasSeq
!(1, Bad(1), "asdf"));
1599 // Ensure Tuple.toHash works
1602 Tuple
!(int, int) point
;
1603 assert(point
.toHash
== typeof(point
).init
.toHash
);
1604 assert(tuple(1, 2) != point
);
1605 assert(tuple(1, 2) == tuple(1, 2));
1607 assert(tuple(1, 2) != point
);
1609 assert(tuple(1, 2) == point
);
1612 @safe @betterC unittest
1614 auto t
= tuple(1, 2);
1615 assert(t
== tuple(1, 2));
1616 auto t3
= tuple(1, 'd');
1619 // https://issues.dlang.org/show_bug.cgi?id=20850
1620 // Assignment to enum tuple
1623 enum T
: Tuple
!(int*) { a
= T(null) }
1628 // https://issues.dlang.org/show_bug.cgi?id=13663
1631 auto t
= tuple(real.nan
);
1641 float opCmp(S s
) { return float.nan
; }
1642 bool opEquals(S s
) { return false; }
1645 auto t
= tuple(S());
1651 // https://issues.dlang.org/show_bug.cgi?id=8015
1657 @property string
toStr()
1667 // https://issues.dlang.org/show_bug.cgi?id=24465
1673 this(ref return scope inout(S
) rhs
) scope @trusted inout pure nothrow {}
1676 static void foo(Tuple
!S
)
1683 auto t2
= Tuple
!S(t
);
1689 auto t2
= Tuple
!S(t
);
1691 // This can't be done if Tuple has a copy constructor, because it's not
1692 // allowed to have an rvalue constructor at that point, and the
1693 // compiler doesn't to something intelligent like transform it into a
1694 // move instead. However, it has been legal with Tuple for a while
1695 // (maybe even since it was first added) when the type doesn't have a
1696 // copy constructor, so this is testing to make sure that the fix to
1697 // make copy constructors work doesn't mess up the rvalue constructor
1698 // when none of the Tuple's members have copy constructors.
1699 auto t3
= Tuple
!S(Tuple
!S
.init
);
1704 Creates a copy of a $(LREF Tuple) with its fields in _reverse order.
1707 t = The `Tuple` to copy.
1712 auto reverse(T
)(T t
)
1715 import std
.meta
: Reverse
;
1716 // @@@BUG@@@ Cannot be an internal function due to forward reference issues.
1718 // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple
1719 // return tuple(Reverse!(t.expand));
1721 ReverseTupleType
!T result
;
1722 auto tup
= t
.expand
;
1723 result
.expand
= Reverse
!tup
;
1730 auto tup
= tuple(1, "2");
1731 assert(tup
.reverse
== tuple("2", 1));
1734 /* Get a Tuple type with the reverse specification of Tuple T. */
1735 private template ReverseTupleType(T
)
1738 static if (is(T
: Tuple
!A
, A
...))
1739 alias ReverseTupleType
= Tuple
!(ReverseTupleSpecs
!A
);
1742 /* Reverse the Specs of a Tuple. */
1743 private template ReverseTupleSpecs(T
...)
1745 static if (T
.length
> 1)
1747 static if (is(typeof(T
[$-1]) : string
))
1749 alias ReverseTupleSpecs
= AliasSeq
!(T
[$-2], T
[$-1], ReverseTupleSpecs
!(T
[0 .. $-2]));
1753 alias ReverseTupleSpecs
= AliasSeq
!(T
[$-1], ReverseTupleSpecs
!(T
[0 .. $-1]));
1758 alias ReverseTupleSpecs
= T
;
1762 // ensure that internal Tuple unittests are compiled
1772 Tuple
!(int, "a", int, "b") nosh
;
1773 static assert(nosh
.length
== 2);
1776 assert(nosh
.a
== 5);
1777 assert(nosh
.b
== 6);
1780 Tuple
!(short, double) b
;
1781 static assert(b
.length
== 2);
1783 auto a
= Tuple
!(int, real)(b
);
1784 assert(a
[0] == 0 && a
[1] == 5);
1785 a
= Tuple
!(int, real)(1, 2);
1786 assert(a
[0] == 1 && a
[1] == 2);
1787 auto c
= Tuple
!(int, "a", double, "b")(a
);
1788 assert(c
[0] == 1 && c
[1] == 2);
1791 Tuple
!(int, real) nosh
;
1794 assert(nosh
[0] == 5 && nosh
[1] == 0);
1795 assert(nosh
.to
!string
== "Tuple!(int, real)(5, 0)", nosh
.to
!string
);
1796 Tuple
!(int, int) yessh
;
1801 Tuple
!(int, shared A
) nosh
;
1803 assert(nosh
[0] == 5 && nosh
[1] is null);
1804 assert(nosh
.to
!string
== "Tuple!(int, shared(A))(5, shared(A))");
1807 Tuple
!(int, string
) t
;
1810 assert(t
[0] == 10 && t
[1] == "str");
1811 assert(t
.to
!string
== `Tuple!(int, string)(10, "str")`, t
.to
!string
);
1814 Tuple
!(int, "a", double, "b") x
;
1815 static assert(x
.a
.offsetof
== x
[0].offsetof
);
1816 static assert(x
.b
.offsetof
== x
[1].offsetof
);
1819 assert(x
[0] == 5 && x
[1] == 4.5);
1820 assert(x
.a
== 5 && x
.b
== 4.5);
1824 Tuple
!(int, real) t
;
1825 static assert(is(typeof(t
[0]) == int));
1826 static assert(is(typeof(t
[1]) == real));
1831 assert(*p0
== t
[0]);
1832 assert(*p1
== t
[1]);
1836 Tuple
!(int, "x", real, "y", double, "z", string
) t
;
1841 auto a
= t
.slice
!(0, 3);
1842 assert(a
.length
== 3);
1846 auto b
= t
.slice
!(2, 4);
1847 assert(b
.length
== 2);
1849 assert(b
[1] == t
[3]);
1853 Tuple
!(Tuple
!(int, real), Tuple
!(string
, "s")) t
;
1854 static assert(is(typeof(t
[0]) == Tuple
!(int, real)));
1855 static assert(is(typeof(t
[1]) == Tuple
!(string
, "s")));
1856 static assert(is(typeof(t
[0][0]) == int));
1857 static assert(is(typeof(t
[0][1]) == real));
1858 static assert(is(typeof(t
[1].s
) == string
));
1859 t
[0] = tuple(10, 20.0L);
1861 assert(t
[0][0] == 10);
1862 assert(t
[0][1] == 20.0L);
1863 assert(t
[1].s
== "abc");
1870 this(this) { ++count
; }
1871 ~this() { --count
; }
1872 void opAssign(S rhs
) { count
= rhs
.count
; }
1875 Tuple
!(S
, S
) ssCopy
= ss
;
1876 assert(ssCopy
[0].count
== 1);
1877 assert(ssCopy
[1].count
== 1);
1878 ssCopy
[1] = ssCopy
[0];
1879 assert(ssCopy
[1].count
== 2);
1881 // https://issues.dlang.org/show_bug.cgi?id=2800
1885 Tuple
!(int, int) _front
;
1886 @property ref Tuple
!(int, int) front() return { return _front
; }
1887 @property bool empty() { return _front
[0] >= 10; }
1888 void popFront() { ++_front
[0]; }
1892 static assert(is(typeof(a
) == Tuple
!(int, int)));
1893 assert(0 <= a
[0] && a
[0] < 10);
1897 // Construction with compatible elements
1899 auto t1
= Tuple
!(int, double)(1, 1);
1901 // https://issues.dlang.org/show_bug.cgi?id=8702
1902 auto t8702a
= tuple(tuple(1));
1903 auto t8702b
= Tuple
!(Tuple
!(int))(Tuple
!(int)(1));
1905 // Construction with compatible tuple
1910 Tuple
!(int, "a", double, "b") y
= x
;
1914 static assert(!__traits(compiles
, Tuple
!(int, int)(y
)));
1916 // https://issues.dlang.org/show_bug.cgi?id=6275
1920 alias T
= Tuple
!(const(int));
1923 // https://issues.dlang.org/show_bug.cgi?id=9431
1925 alias T
= Tuple
!(int[1][]);
1928 // https://issues.dlang.org/show_bug.cgi?id=7666
1930 auto tup
= tuple(1, "2");
1931 assert(tup
.reverse
== tuple("2", 1));
1934 Tuple
!(int, "x", string
, "y") tup
= tuple(1, "2");
1935 auto rev
= tup
.reverse
;
1936 assert(rev
== tuple("2", 1));
1937 assert(rev
.x
== 1 && rev
.y
== "2");
1940 Tuple
!(wchar, dchar, int, "x", string
, "y", char, byte, float) tup
;
1941 tup
= tuple('a', 'b', 3, "4", 'c', cast(byte) 0x0D, 0.00);
1942 auto rev
= tup
.reverse
;
1943 assert(rev
== tuple(0.00, cast(byte) 0x0D, 'c', "4", 3, 'b', 'a'));
1944 assert(rev
.x
== 3 && rev
.y
== "4");
1951 struct Equ1
{ bool opEquals(Equ1
) { return true; } }
1952 auto tm1
= tuple(Equ1
.init
);
1953 const tc1
= tuple(Equ1
.init
);
1954 static assert( is(typeof(tm1
== tm1
)));
1955 static assert(!is(typeof(tm1
== tc1
)));
1956 static assert(!is(typeof(tc1
== tm1
)));
1957 static assert(!is(typeof(tc1
== tc1
)));
1959 struct Equ2
{ bool opEquals(const Equ2
) const { return true; } }
1960 auto tm2
= tuple(Equ2
.init
);
1961 const tc2
= tuple(Equ2
.init
);
1962 static assert( is(typeof(tm2
== tm2
)));
1963 static assert( is(typeof(tm2
== tc2
)));
1964 static assert( is(typeof(tc2
== tm2
)));
1965 static assert( is(typeof(tc2
== tc2
)));
1967 // https://issues.dlang.org/show_bug.cgi?id=8686
1968 struct Equ3
{ bool opEquals(T
)(T
) { return true; } }
1969 auto tm3
= tuple(Equ3
.init
);
1970 const tc3
= tuple(Equ3
.init
);
1971 static assert( is(typeof(tm3
== tm3
)));
1972 static assert( is(typeof(tm3
== tc3
)));
1973 static assert(!is(typeof(tc3
== tm3
)));
1974 static assert(!is(typeof(tc3
== tc3
)));
1976 struct Equ4
{ bool opEquals(T
)(T
) const { return true; } }
1977 auto tm4
= tuple(Equ4
.init
);
1978 const tc4
= tuple(Equ4
.init
);
1979 static assert( is(typeof(tm4
== tm4
)));
1980 static assert( is(typeof(tm4
== tc4
)));
1981 static assert( is(typeof(tc4
== tm4
)));
1982 static assert( is(typeof(tc4
== tc4
)));
1986 struct Cmp1
{ int opCmp(Cmp1
) { return 0; } }
1987 auto tm1
= tuple(Cmp1
.init
);
1988 const tc1
= tuple(Cmp1
.init
);
1989 static assert( is(typeof(tm1
< tm1
)));
1990 static assert(!is(typeof(tm1
< tc1
)));
1991 static assert(!is(typeof(tc1
< tm1
)));
1992 static assert(!is(typeof(tc1
< tc1
)));
1994 struct Cmp2
{ int opCmp(const Cmp2
) const { return 0; } }
1995 auto tm2
= tuple(Cmp2
.init
);
1996 const tc2
= tuple(Cmp2
.init
);
1997 static assert( is(typeof(tm2
< tm2
)));
1998 static assert( is(typeof(tm2
< tc2
)));
1999 static assert( is(typeof(tc2
< tm2
)));
2000 static assert( is(typeof(tc2
< tc2
)));
2002 struct Cmp3
{ int opCmp(T
)(T
) { return 0; } }
2003 auto tm3
= tuple(Cmp3
.init
);
2004 const tc3
= tuple(Cmp3
.init
);
2005 static assert( is(typeof(tm3
< tm3
)));
2006 static assert( is(typeof(tm3
< tc3
)));
2007 static assert(!is(typeof(tc3
< tm3
)));
2008 static assert(!is(typeof(tc3
< tc3
)));
2010 struct Cmp4
{ int opCmp(T
)(T
) const { return 0; } }
2011 auto tm4
= tuple(Cmp4
.init
);
2012 const tc4
= tuple(Cmp4
.init
);
2013 static assert( is(typeof(tm4
< tm4
)));
2014 static assert( is(typeof(tm4
< tc4
)));
2015 static assert( is(typeof(tc4
< tm4
)));
2016 static assert( is(typeof(tc4
< tc4
)));
2018 // https://issues.dlang.org/show_bug.cgi?id=14890
2019 static void test14890(inout int[] dummy
)
2021 alias V
= Tuple
!(int, int);
2026 inout V wv
; // OK <- NG
2027 inout const V wcv
; // OK <- NG
2029 static foreach (v1
; AliasSeq
!(mv
, cv
, iv
, wv
, wcv
))
2030 static foreach (v2
; AliasSeq
!(mv
, cv
, iv
, wv
, wcv
))
2036 int[2] ints
= [ 1, 2 ];
2037 Tuple
!(int, int) t
= ints
;
2038 assert(t
[0] == 1 && t
[1] == 2);
2039 Tuple
!(long, uint) t2
= ints
;
2040 assert(t2
[0] == 1 && t2
[1] == 2);
2045 auto t1
= Tuple
!(int, "x", string
, "y")(1, "a");
2047 assert(t1
.y
== "a");
2048 void foo(Tuple
!(int, string
) t2
) {}
2051 Tuple
!(int, int)[] arr
;
2052 arr
~= tuple(10, 20); // OK
2053 arr
~= Tuple
!(int, "x", int, "y")(10, 20); // NG -> OK
2055 static assert(is(typeof(Tuple
!(int, "x", string
, "y").tupleof
) ==
2056 typeof(Tuple
!(int, string
).tupleof
)));
2060 // https://issues.dlang.org/show_bug.cgi?id=10686
2061 immutable Tuple
!(int) t1
;
2062 auto r1
= t1
[0]; // OK
2063 immutable Tuple
!(int, "x") t2
;
2064 auto r2
= t2
[0]; // error
2068 import std
.exception
: assertCTFEable
;
2070 // https://issues.dlang.org/show_bug.cgi?id=10218
2074 t
= tuple(2); // assignment
2080 Tuple
!(immutable(Foo
)[]) a
;
2085 //Test non-assignable
2090 alias IS
= immutable S
;
2091 static assert(!isAssignable
!IS
);
2095 alias TIS
= Tuple
!IS
;
2099 alias TISIS
= Tuple
!(IS
, IS
);
2100 TISIS d
= tuple(s
, s
);
2102 TISIS e
= TISIS(ss
);
2105 // https://issues.dlang.org/show_bug.cgi?id=9819
2108 alias T
= Tuple
!(int, "x", double, "foo");
2109 static assert(T
.fieldNames
[0] == "x");
2110 static assert(T
.fieldNames
[1] == "foo");
2112 alias Fields
= Tuple
!(int, "id", string
, float);
2113 static assert(Fields
.fieldNames
== AliasSeq
!("id", "", ""));
2116 // https://issues.dlang.org/show_bug.cgi?id=13837
2119 // New behaviour, named arguments.
2121 typeof(tuple
!("x")(1)) == Tuple
!(int, "x")));
2123 typeof(tuple
!("x")(1.0)) == Tuple
!(double, "x")));
2125 typeof(tuple
!("x")("foo")) == Tuple
!(string
, "x")));
2127 typeof(tuple
!("x", "y")(1, 2.0)) == Tuple
!(int, "x", double, "y")));
2129 auto a
= tuple
!("a", "b", "c")("1", 2, 3.0f);
2130 static assert(is(typeof(a
.a
) == string
));
2131 static assert(is(typeof(a
.b
) == int));
2132 static assert(is(typeof(a
.c
) == float));
2134 // Old behaviour, but with explicit type parameters.
2136 typeof(tuple
!(int, double)(1, 2.0)) == Tuple
!(int, double)));
2138 typeof(tuple
!(const int)(1)) == Tuple
!(const int)));
2140 typeof(tuple()) == Tuple
!()));
2142 // Nonsensical behaviour
2143 static assert(!__traits(compiles
, tuple
!(1)(2)));
2144 static assert(!__traits(compiles
, tuple
!("x")(1, 2)));
2145 static assert(!__traits(compiles
, tuple
!("x", "y")(1)));
2146 static assert(!__traits(compiles
, tuple
!("x")()));
2147 static assert(!__traits(compiles
, tuple
!("x", int)(2)));
2152 class C
{ override size_t
toHash() const nothrow @safe { return 0; } }
2153 Tuple
!(Rebindable
!(const C
)) a
;
2158 @nogc @safe unittest
2160 alias T
= Tuple
!(string
, "s");
2167 import std
.format
: format
, FormatException
;
2168 import std
.exception
: assertThrown
;
2170 //enum tupStr = tuple(1, 1.0).toString; // toString is *impure*.
2171 //static assert(tupStr == `Tuple!(int, double)(1, 1)`);
2174 // https://issues.dlang.org/show_bug.cgi?id=17803, parte uno
2177 auto a
= tuple(3, "foo");
2178 assert(__traits(compiles
, { a
= (a
= a
); }));
2183 Tuple
!(int[]) a
, b
, c
;
2184 a
= tuple([0, 1, 2]);
2186 assert(a
[0].length
== b
[0].length
&& b
[0].length
== c
[0].length
);
2187 assert(a
[0].ptr
== b
[0].ptr
&& b
[0].ptr
== c
[0].ptr
);
2191 Constructs a $(LREF Tuple) object instantiated and initialized according to
2192 the given arguments.
2195 Names = An optional list of strings naming each successive field of the `Tuple`
2196 or a list of types that the elements are being casted to.
2197 For a list of names,
2198 each name matches up with the corresponding field given by `Args`.
2199 A name does not have to be provided for every field, but as
2200 the names must proceed in order, it is not possible to skip
2201 one field and name the next after it.
2202 For a list of types,
2203 there must be exactly as many types as parameters.
2205 template tuple(Names
...)
2209 args = Values to initialize the `Tuple` with. The `Tuple`'s type will
2210 be inferred from the types of the values given.
2213 A new `Tuple` with its type inferred from the arguments given.
2215 auto tuple(Args
...)(Args args
)
2217 static if (Names
.length
== 0)
2219 // No specified names, just infer types from Args...
2220 return Tuple
!Args(args
);
2222 else static if (!is(typeof(Names
[0]) : string
))
2224 // Names[0] isn't a string, must be explicit types.
2225 return Tuple
!Names(args
);
2229 // Names[0] is a string, so must be specifying names.
2230 static assert(Names
.length
== Args
.length
,
2231 "Insufficient number of names given.");
2233 // Interleave(a, b).and(c, d) == (a, c, b, d)
2234 // This is to get the interleaving of types and names for Tuple
2235 // e.g. Tuple!(int, "x", string, "y")
2236 template Interleave(A
...)
2238 template and(B
...) if (B
.length
== 1)
2240 alias and = AliasSeq
!(A
[0], B
[0]);
2243 template and(B
...) if (B
.length
!= 1)
2245 alias and = AliasSeq
!(A
[0], B
[0],
2246 Interleave
!(A
[1..$]).and!(B
[1..$]));
2249 return Tuple
!(Interleave
!(Args
).and!(Names
))(args
);
2257 auto value
= tuple(5, 6.7, "hello");
2258 assert(value
[0] == 5);
2259 assert(value
[1] == 6.7);
2260 assert(value
[2] == "hello");
2262 // Field names can be provided.
2263 auto entry
= tuple
!("index", "value")(4, "Hello");
2264 assert(entry
.index
== 4);
2265 assert(entry
.value
== "Hello");
2269 Returns `true` if and only if `T` is an instance of `std.typecons.Tuple`.
2272 T = The type to check.
2275 true if `T` is a `Tuple` type, false otherwise.
2277 enum isTuple(T
) = __traits(compiles
,
2279 void f(Specs
...)(Tuple
!Specs tup
) {}
2286 static assert(isTuple
!(Tuple
!()));
2287 static assert(isTuple
!(Tuple
!(int)));
2288 static assert(isTuple
!(Tuple
!(int, real, string
)));
2289 static assert(isTuple
!(Tuple
!(int, "x", real, "y")));
2290 static assert(isTuple
!(Tuple
!(int, Tuple
!(real), string
)));
2295 static assert(isTuple
!(const Tuple
!(int)));
2296 static assert(isTuple
!(immutable Tuple
!(int)));
2298 static assert(!isTuple
!(int));
2299 static assert(!isTuple
!(const int));
2302 static assert(!isTuple
!(S
));
2305 // used by both Rebindable and UnqualRef
2306 private mixin template RebindableCommon(T
, U
, alias This
)
2307 if (is(T
== class) ||
is(T
== interface) || isAssociativeArray
!T
)
2315 void opAssign(return scope T another
) pure nothrow @nogc
2317 // If `T` defines `opCast` we must infer the safety
2318 static if (hasMember
!(T
, "opCast"))
2320 // This will allow the compiler to infer the safety of `T.opCast!U`
2321 // without generating any runtime cost
2322 if (false) { stripped
= cast(U
) another
; }
2324 () @trusted { stripped
= cast(U
) another
; }();
2327 void opAssign(typeof(this) another
) @trusted pure nothrow @nogc
2329 stripped
= another
.stripped
;
2332 static if (is(T
== const U
) && is(T
== const shared U
))
2334 // safely assign immutable to const / const shared
2335 void opAssign(This
!(immutable U
) another
) @trusted pure nothrow @nogc
2337 stripped
= another
.stripped
;
2341 this(T initializer
) pure nothrow @nogc
2343 // Infer safety from opAssign
2344 opAssign(initializer
);
2347 @property inout(T
) get() @trusted pure nothrow @nogc return scope inout
2352 bool opEquals()(auto ref const(typeof(this)) rhs
) const
2354 // Must forward explicitly because 'stripped' is part of a union.
2355 // The necessary 'toHash' is forwarded to the class via alias this.
2356 return stripped
== rhs
.stripped
;
2359 bool opEquals(const(U
) rhs
) const
2361 return stripped
== rhs
;
2368 `Rebindable!(T)` is a simple, efficient wrapper that behaves just
2369 like an object of type `T`, except that you can reassign it to
2370 refer to another object. For completeness, `Rebindable!(T)` aliases
2371 itself away to `T` if `T` is a non-const object type.
2373 You may want to use `Rebindable` when you want to have mutable
2374 storage referring to `const` objects, for example an array of
2375 references that must be sorted in place. `Rebindable` does not
2376 break the soundness of D's type system and does not incur any of the
2377 risks usually associated with `cast`.
2382 template Rebindable(T
)
2383 if (is(T
== class) ||
is(T
== interface) || isDynamicArray
!T || isAssociativeArray
!T
)
2385 static if (is(T
== const U
, U
) ||
is(T
== immutable U
, U
))
2387 static if (isDynamicArray
!T
)
2389 import std
.range
.primitives
: ElementEncodingType
;
2390 alias Rebindable
= const(ElementEncodingType
!T
)[];
2396 mixin RebindableCommon
!(T
, U
, Rebindable
);
2402 alias Rebindable
= T
;
2406 ///Regular `const` object references cannot be reassigned.
2409 class Widget
{ int x
; int y() @safe const { return x
; } }
2410 const a
= new Widget
;
2413 // error! can't modify const a
2415 // error! can't modify const a
2420 However, `Rebindable!(Widget)` does allow reassignment,
2421 while otherwise behaving exactly like a $(D const Widget).
2425 class Widget
{ int x
; int y() const @safe { return x
; } }
2426 auto a
= Rebindable
!(const Widget
)(new Widget
);
2429 // error! can't modify const a
2435 // https://issues.dlang.org/show_bug.cgi?id=16054
2438 Rebindable
!(immutable Object
) r
;
2439 static assert(__traits(compiles
, r
.get()));
2440 static assert(!__traits(compiles
, &r
.get()));
2444 struct Rebindable(T
)
2445 if (!is(T
== class) && !is(T
== interface) && !isDynamicArray
!T
&& !isAssociativeArray
!T
)
2448 static if (isAssignable
!(typeof(cast() T
.init
)))
2450 enum useQualifierCast
= true;
2452 typeof(cast() T
.init
) data
;
2456 enum useQualifierCast
= false;
2459 static struct Payload
2461 static if (hasIndirections
!T
)
2463 void[T
.sizeof
] data
;
2467 ubyte[T
.sizeof
] data
;
2476 static if (!__traits(compiles
, { T value
; }))
2482 * Constructs a `Rebindable` from a given value.
2484 this(T value
) @trusted
2486 static if (useQualifierCast
)
2488 this.data
= cast() value
;
2497 * Overwrites the currently stored value with `value`.
2499 void opAssign(this This
)(T value
) @trusted
2506 * Returns the value currently stored in the `Rebindable`.
2508 T
get(this This
)() @property @trusted
2510 static if (useQualifierCast
)
2512 return cast(T
) this.data
;
2516 return *cast(T
*) &this.data
;
2520 static if (!useQualifierCast
)
2533 void set(this This
)(T value
)
2535 static if (useQualifierCast
)
2537 this.data
= cast() value
;
2541 // As we're escaping a copy of `value`, deliberately leak a copy:
2542 static union DontCallDestructor
2546 DontCallDestructor copy
= DontCallDestructor(value
);
2547 this.data
= *cast(Payload
*) ©
;
2551 void clear(this This
)()
2553 // work around reinterpreting cast being impossible in CTFE
2559 // call possible struct destructors
2560 .destroy
!(No
.initialize
)(*cast(T
*) &this.data
);
2564 /// Using Rebindable in a generic algorithm:
2567 import std
.range
.primitives
: front
, popFront
;
2569 // simple version of std.algorithm.searching.maxElement
2570 typeof(R
.init
.front
) maxElement(R
)(R r
)
2572 auto max
= rebindable(r
.front
);
2576 max
= e
; // Rebindable allows const-correct reassignment
2582 alias arr
this; // for comparison
2584 // can't convert to mutable
2586 static assert(!__traits(compiles
, { S s
= cs
; }));
2589 CS
[] arr
= [CS("harp"), CS("apple"), CS("pot")];
2590 CS ms
= maxElement(arr
);
2591 assert(ms
.arr
== "pot");
2594 // https://issues.dlang.org/show_bug.cgi?id=18615
2595 // Rebindable!A should use A.opEqualsa
2601 override bool opEquals(Object rhsObj
)
2603 if (auto rhs
= cast(const(CustomOpEq
)) rhsObj
)
2604 return this.x
== rhs
.x
;
2609 CustomOpEq a
= new CustomOpEq();
2610 CustomOpEq b
= new CustomOpEq();
2612 assert(a
== b
, "a.x == b.x should be true (0 == 0).");
2614 Rebindable
!(const(CustomOpEq
)) ra
= a
;
2615 Rebindable
!(const(CustomOpEq
)) rb
= b
;
2617 assert(ra
== rb
, "Rebindable should use CustomOpEq's opEquals, not 'is'.");
2618 assert(ra
== b
, "Rebindable!(someQualifier(A)) should be comparable"
2619 ~ " against const(A) via A.opEquals.");
2620 assert(a
== rb
, "Rebindable!(someQualifier(A)) should be comparable"
2621 ~ " against const(A) via A.opEquals.");
2625 assert(ra
!= b
, "Rebindable!(someQualifier(A)) should be comparable"
2626 ~ " against const(A) via A.opEquals.");
2627 assert(a
!= rb
, "Rebindable!(someQualifier(A)) should be comparable"
2628 ~ " against const(A) via A.opEquals.");
2630 Rebindable
!(const(Object
)) o1
= new Object();
2631 Rebindable
!(const(Object
)) o2
= new Object();
2633 assert(o1
== o1
, "When the class doesn't provide its own opEquals,"
2634 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2635 assert(o1
!= o2
, "When the class doesn't provide its own opEquals,"
2636 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2637 assert(o1
!= new Object(), "Rebindable!(const(Object)) should be"
2638 ~ " comparable against Object itself and use Object.opEquals.");
2651 // Can't assign s.ptr to cs.ptr
2652 static assert(!__traits(compiles
, {s
= cs
;}));
2654 Rebindable
!(const S
) rs
= s
;
2655 assert(rs
.ptr
is s
.ptr
);
2657 static assert(!__traits(compiles
, {rs
.ptr
= null;}));
2659 // Can't assign s.ptr to rs.ptr
2660 static assert(!__traits(compiles
, {s
= rs
;}));
2666 assert(rs
.ptr
is null);
2669 // https://issues.dlang.org/show_bug.cgi?id=18755
2674 auto opCast(T
)() @system immutable pure nothrow
2676 *(cast(uint*) 0xdeadbeef) = 0xcafebabe;
2681 static assert(!__traits(compiles
, () @safe {
2682 auto r
= Rebindable
!(immutable Foo
)(new Foo
);
2684 static assert(__traits(compiles
, () @system {
2685 auto r
= Rebindable
!(immutable Foo
)(new Foo
);
2693 override size_t
toHash() const nothrow @trusted { return 42; }
2695 Rebindable
!(immutable(CustomToHash
)) a
= new immutable CustomToHash();
2696 assert(a
.toHash() == 42, "Rebindable!A should offer toHash()"
2697 ~ " by forwarding to A.toHash().");
2700 // Test Rebindable!immutable
2709 Rebindable
!(immutable S
) ri
= S(new int);
2710 assert(ri
.ptr
!is null);
2711 static assert(!__traits(compiles
, {ri
.ptr
= null;}));
2713 // ri is not compatible with mutable S
2714 static assert(!__traits(compiles
, {s
= ri
;}));
2715 static assert(!__traits(compiles
, {ri
= s
;}));
2718 assert(ri2
.ptr
== ri
.ptr
);
2721 static assert(!__traits(compiles
, {ri
= cs3
;}));
2723 immutable S si
= ri
;
2727 assert(ri
.ptr
is null);
2729 // Test RB!immutable -> RB!const
2730 Rebindable
!(const S
) rc
= ri
;
2731 assert(rc
.ptr
is null);
2734 assert(rc
.ptr
!is null);
2736 // test rebindable, opAssign
2738 assert(rc
.ptr
is null);
2739 rc
= rebindable(cs3
);
2740 rc
= rebindable(si
);
2741 assert(rc
.ptr
!is null);
2744 assert(ri
.ptr
is null);
2745 ri
= rebindable(si
);
2746 assert(ri
.ptr
!is null);
2749 // Test disabled default ctor
2756 this(int i
) inout {this.i
= i
;}
2758 static assert(!__traits(compiles
, Rebindable
!ND()));
2760 Rebindable
!(const ND
) rb
= const ND(1);
2762 rb
= immutable ND(2);
2764 rb
= rebindable(const ND(3));
2766 static assert(!__traits(compiles
, rb
.i
++));
2791 Rebindable
!S rc
= S(new int);
2793 assert(post
== del
- 1);
2817 Rebindable
!S rc
= S(0);
2819 assert(post
== del
- 1);
2823 Convenience function for creating a `Rebindable` using automatic type
2827 obj = A reference to a value to initialize the `Rebindable` with.
2830 A newly constructed `Rebindable` initialized with the given reference.
2832 Rebindable
!T
rebindable(T
)(T obj
)
2833 if (is(T
== class) ||
is(T
== interface) || isDynamicArray
!T || isAssociativeArray
!T
)
2846 this(int p
) { payload
= p
; }
2850 auto c2
= c
.rebindable
;
2851 assert(c2
.payload
== 1);
2852 // passing Rebindable to rebindable
2856 assert(c2
.payload
== 2);
2859 assert(c3
.payload
== 2);
2863 Rebindable
!T
rebindable(T
)(T value
)
2864 if (!is(T
== class) && !is(T
== interface) && !isDynamicArray
!T
&& !isAssociativeArray
!T
2865 && !is(T
: Rebindable
!U
, U
))
2867 return Rebindable
!T(value
);
2877 auto s1
= [3].idup
.rebindable
;
2878 s1
= [4].idup
.rebindable
;
2883 This function simply returns the `Rebindable` object passed in. It's useful
2884 in generic programming cases when a given object may be either a regular
2885 `class` or a `Rebindable`.
2888 obj = An instance of Rebindable!T.
2891 `obj` without any modification.
2893 Rebindable
!T
rebindable(T
)(Rebindable
!T obj
)
2898 // TODO: remove me once the rebindable overloads have been joined
2905 this(int p
) { payload
= p
; }
2909 auto c2
= c
.rebindable
;
2910 assert(c2
.payload
== 1);
2911 // passing Rebindable to rebindable
2913 assert(c2
.payload
== 1);
2918 interface CI
{ int foo() const; }
2920 int foo() const { return 42; }
2921 @property int bar() const { return 23; }
2923 Rebindable
!(C
) obj0
;
2924 static assert(is(typeof(obj0
) == C
));
2926 Rebindable
!(const(C
)) obj1
;
2927 static assert(is(typeof(obj1
.get
) == const(C
)), typeof(obj1
.get
).stringof
);
2928 static assert(is(typeof(obj1
.stripped
) == C
));
2930 assert(obj1
.get
!is null);
2931 obj1
= new const(C
);
2932 assert(obj1
.get
!is null);
2934 Rebindable
!(immutable(C
)) obj2
;
2935 static assert(is(typeof(obj2
.get
) == immutable(C
)));
2936 static assert(is(typeof(obj2
.stripped
) == C
));
2937 obj2
= new immutable(C
);
2938 assert(obj1
.get
!is null);
2941 assert(obj2
.foo() == 42);
2942 assert(obj2
.bar
== 23);
2944 interface I
{ final int foo() const { return 42; } }
2945 Rebindable
!(I
) obj3
;
2946 static assert(is(typeof(obj3
) == I
));
2948 Rebindable
!(const I
) obj4
;
2949 static assert(is(typeof(obj4
.get
) == const I
));
2950 static assert(is(typeof(obj4
.stripped
) == I
));
2951 static assert(is(typeof(obj4
.foo()) == int));
2952 obj4
= new class I
{};
2954 Rebindable
!(immutable C
) obj5i
;
2955 Rebindable
!(const C
) obj5c
;
2959 static assert(!__traits(compiles
, obj5i
= obj5c
));
2961 // Test the convenience functions.
2962 auto obj5convenience
= rebindable(obj5i
);
2963 assert(obj5convenience
is obj5i
);
2965 auto obj6
= rebindable(new immutable(C
));
2966 static assert(is(typeof(obj6
) == Rebindable
!(immutable C
)));
2967 assert(obj6
.foo() == 42);
2969 auto obj7
= rebindable(new C
);
2970 CI interface1
= obj7
;
2971 auto interfaceRebind1
= rebindable(interface1
);
2972 assert(interfaceRebind1
.foo() == 42);
2974 const interface2
= interface1
;
2975 auto interfaceRebind2
= rebindable(interface2
);
2976 assert(interfaceRebind2
.foo() == 42);
2978 auto arr
= [1,2,3,4,5];
2979 const arrConst
= arr
;
2980 assert(rebindable(arr
) == arr
);
2981 assert(rebindable(arrConst
) == arr
);
2983 // https://issues.dlang.org/show_bug.cgi?id=7654
2984 immutable(char[]) s7654
;
2985 Rebindable
!(typeof(s7654
)) r7654
= s7654
;
2987 static foreach (T
; AliasSeq
!(char, wchar, char, int))
2989 static assert(is(Rebindable
!(immutable(T
[])) == immutable(T
)[]));
2990 static assert(is(Rebindable
!(const(T
[])) == const(T
)[]));
2991 static assert(is(Rebindable
!(T
[]) == T
[]));
2994 // Pull request 3341
2995 Rebindable
!(immutable int[int]) pr3341
= [123:345];
2996 assert(pr3341
[123] == 345);
2997 immutable int[int] pr3341_aa
= [321:543];
2999 assert(pr3341
[321] == 543);
3000 assert(rebindable(pr3341_aa
)[321] == 543);
3003 package(std
) struct Rebindable2(T
)
3006 static if (isAssignable
!(typeof(cast() T
.init
)))
3008 enum useQualifierCast
= true;
3010 typeof(cast() T
.init
) data
;
3014 enum useQualifierCast
= false;
3017 static struct Payload
3019 static if (hasIndirections
!T
)
3021 void[T
.sizeof
] data
;
3025 ubyte[T
.sizeof
] data
;
3034 static if (!__traits(compiles
, { T value
; }))
3040 * Constructs a `Rebindable2` from a given value.
3042 this(T value
) @trusted
3044 static if (useQualifierCast
)
3046 this.data
= cast() value
;
3055 * Overwrites the currently stored value with `value`.
3057 void opAssign(this This
)(T value
) @trusted
3064 * Returns the value currently stored in the `Rebindable2`.
3066 T
get(this This
)() @property @trusted
3068 static if (useQualifierCast
)
3070 return cast(T
) this.data
;
3074 return *cast(T
*) &this.data
;
3079 inout(T
) get() inout @property @trusted
3081 static if (useQualifierCast
)
3083 return cast(inout(T
)) this.data
;
3087 return *cast(inout(T
)*) &this.data
;
3091 static if (!useQualifierCast
)
3101 void set(this This
)(T value
)
3103 static if (useQualifierCast
)
3105 this.data
= cast() value
;
3109 // As we're escaping a copy of `value`, deliberately leak a copy:
3110 static union DontCallDestructor
3114 DontCallDestructor copy
= DontCallDestructor(value
);
3115 this.data
= *cast(Payload
*) ©
;
3119 void clear(this This
)()
3121 // work around reinterpreting cast being impossible in CTFE
3127 // call possible struct destructors
3128 .destroy
!(No
.initialize
)(*cast(T
*) &this.data
);
3132 package(std
) Rebindable2
!T
rebindable2(T
)(T value
)
3134 return Rebindable2
!T(value
);
3138 Similar to `Rebindable!(T)` but strips all qualifiers from the reference as
3139 opposed to just constness / immutability. Primary intended use case is with
3140 shared (having thread-local reference to shared class data)
3143 T = A class or interface type.
3145 template UnqualRef(T
)
3146 if (is(T
== class) ||
is(T
== interface))
3148 static if (is(T
== immutable U
, U
)
3149 ||
is(T
== const shared U
, U
)
3150 ||
is(T
== const U
, U
)
3151 ||
is(T
== shared U
, U
))
3155 mixin RebindableCommon
!(T
, U
, UnqualRef
);
3160 alias UnqualRef
= T
;
3169 static shared(Data
) a
;
3170 static UnqualRef
!(shared Data
) b
;
3174 auto thread
= new core
.thread
.Thread({
3175 a
= new shared Data();
3176 b
= new shared Data();
3189 alias T
= UnqualRef
!(const shared C
);
3190 static assert(is(typeof(T
.stripped
) == C
));
3196 Order the provided members to minimize size while preserving alignment.
3197 Alignment is not always optimal for 80-bit reals, nor for structs declared
3201 E = A list of the types to be aligned, representing fields
3202 of an aggregate such as a `struct` or `class`.
3204 names = The names of the fields that are to be aligned.
3207 A string to be mixed in to an aggregate, such as a `struct` or `class`.
3209 string
alignForSize(E
...)(const char[][] names
...)
3211 // Sort all of the members by .alignof.
3212 // BUG: Alignment is not always optimal for align(1) structs
3213 // or 80-bit reals or 64-bit primitives on x86.
3214 // TRICK: Use the fact that .alignof is always a power of 2,
3215 // and maximum 16 on extant systems. Thus, we can perform
3216 // a very limited radix sort.
3217 // Contains the members with .alignof = 64,32,16,8,4,2,1
3219 assert(E
.length
== names
.length
,
3220 "alignForSize: There should be as many member names as the types");
3222 string
[7] declaration
= ["", "", "", "", "", "", ""];
3227 auto k
= a
>= 64?
0 : a
>= 32?
1 : a
>= 16?
2 : a
>= 8?
3 : a
>= 4?
4 : a
>= 2?
5 : 6;
3228 declaration
[k
] ~= T
.stringof
~ " " ~ names
[i
] ~ ";\n";
3232 foreach (decl
; declaration
)
3241 mixin(alignForSize
!(byte[6], double)(["name", "height"]));
3247 enum x
= alignForSize
!(int[], char[3], short, double[5])("x", "y","z", "w");
3248 struct Foo
{ int x
; }
3249 enum y
= alignForSize
!(ubyte, Foo
, double)("x", "y", "z");
3251 enum passNormalX
= x
== "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
3252 enum passNormalY
= y
== "double z;\nFoo y;\nubyte x;\n";
3254 enum passAbnormalX
= x
== "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
3255 enum passAbnormalY
= y
== "Foo y;\ndouble z;\nubyte x;\n";
3256 // ^ blame https://issues.dlang.org/show_bug.cgi?id=231
3258 static assert(passNormalX || passAbnormalX
&& double.alignof
<= (int[]).alignof
);
3259 static assert(passNormalY || passAbnormalY
&& double.alignof
<= int.alignof
);
3262 // https://issues.dlang.org/show_bug.cgi?id=12914
3265 immutable string
[] fieldNames
= ["x", "y"];
3268 mixin(alignForSize
!(byte, int)(fieldNames
));
3273 Defines a value paired with a distinctive "null" state that denotes
3274 the absence of a value. If default constructed, a $(D
3275 Nullable!T) object starts in the null state. Assigning it renders it
3276 non-null. Calling `nullify` can nullify it again.
3278 Practically `Nullable!T` stores a `T` and a `bool`.
3281 $(LREF apply), an alternative way to use the payload.
3285 private union DontCallDestructorT
3287 import std
.traits
: hasIndirections
;
3288 static if (hasIndirections
!T
)
3294 private DontCallDestructorT _value
= DontCallDestructorT
.init
;
3296 private bool _isNull
= true;
3299 * Constructor initializing `this` with `value`.
3302 * value = The value to initialize this `Nullable` with.
3304 static if (isCopyable
!T
)
3305 this(inout T value
) inout
3307 _value
.payload
= value
;
3313 import std
.algorithm
.mutation
: move
;
3314 _value
.payload
= move(value
);
3318 static if (hasElaborateDestructor
!T
)
3324 import std
.traits
: Unqual
;
3325 auto ptr
= () @trusted { return cast(Unqual
!T
*) &_value
.payload
; }();
3326 destroy
!false(*ptr
);
3331 static if (!isCopyable
!T
)
3332 @disable this(this);
3334 static if (__traits(hasPostblit
, T
))
3339 _value
.payload
.__xpostblit();
3342 else static if (__traits(hasCopyConstructor
, T
))
3344 this(ref return scope inout Nullable
!T rhs
) inout
3346 _isNull
= rhs
._isNull
;
3348 _value
.payload
= rhs
._value
.payload
;
3350 _value
= DontCallDestructorT
.init
;
3355 * If they are both null, then they are equal. If one is null and the other
3356 * is not, then they are not equal. If they are both non-null, then they are
3357 * equal if their values are equal.
3359 bool opEquals(this This
, Rhs
)(auto ref Rhs rhs
)
3360 if (!is(CommonType
!(This
, Rhs
) == void))
3362 static if (is(This
== Rhs
))
3368 return _value
.payload
== rhs
._value
.payload
;
3372 alias Common
= CommonType
!(This
, Rhs
);
3373 return cast(Common
) this == cast(Common
) rhs
;
3378 bool opEquals(this This
, Rhs
)(auto ref Rhs rhs
)
3379 if (is(CommonType
!(This
, Rhs
) == void) && is(typeof(this.get
== rhs
)))
3381 return _isNull ?
false : rhs
== _value
.payload
;
3388 Nullable
!int a
= 42;
3389 Nullable
!int b
= 42;
3390 Nullable
!int c
= 27;
3392 assert(empty
== empty
);
3393 assert(empty
== Nullable
!int.init
);
3401 assert(empty
!= 42);
3409 immutable Nullable
!int a
= 42;
3410 Nullable
!int b
= 42;
3411 immutable Nullable
!int c
= 29;
3412 Nullable
!int d
= 29;
3423 assert(a
== const Nullable
!int(42));
3424 assert(a
!= Nullable
!int(29));
3427 // https://issues.dlang.org/show_bug.cgi?id=17482
3430 import std
.variant
: Variant
;
3431 Nullable
!Variant a
= Variant(12);
3437 size_t
toHash() const @safe nothrow
3439 static if (__traits(compiles
, .hashOf(_value
.payload
)))
3440 return _isNull ?
0 : .hashOf(_value
.payload
);
3442 // Workaround for when .hashOf is not both @safe and nothrow.
3443 return _isNull ?
0 : typeid(T
).getHash(&_value
.payload
);
3447 * Gives the string `"Nullable.null"` if `isNull` is `true`. Otherwise, the
3448 * result is equivalent to calling $(REF formattedWrite, std,format) on the
3452 * writer = A `char` accepting
3453 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
3454 * fmt = A $(REF FormatSpec, std,format) which is used to represent
3455 * the value if this Nullable is not null
3457 * A `string` if `writer` and `fmt` are not set; `void` otherwise.
3461 import std
.array
: appender
;
3462 auto app
= appender
!string();
3463 auto spec
= singleSpec("%s");
3464 toString(app
, spec
);
3469 string
toString() const
3471 import std
.array
: appender
;
3472 auto app
= appender
!string();
3473 auto spec
= singleSpec("%s");
3474 toString(app
, spec
);
3479 void toString(W
)(ref W writer
, scope const ref FormatSpec
!char fmt
)
3480 if (isOutputRange
!(W
, char))
3482 import std
.range
.primitives
: put
;
3484 put(writer
, "Nullable.null");
3486 formatValue(writer
, _value
.payload
, fmt
);
3490 void toString(W
)(ref W writer
, scope const ref FormatSpec
!char fmt
) const
3491 if (isOutputRange
!(W
, char))
3493 import std
.range
.primitives
: put
;
3495 put(writer
, "Nullable.null");
3497 formatValue(writer
, _value
.payload
, fmt
);
3501 * Check if `this` is in the null state.
3504 * true $(B iff) `this` is in the null state, otherwise false.
3506 @property bool isNull() const @safe pure nothrow
3521 // https://issues.dlang.org/show_bug.cgi?id=14940
3524 import std
.array
: appender
;
3525 import std
.format
.write
: formattedWrite
;
3527 auto app
= appender
!string();
3529 formattedWrite(app
, "%s", a
);
3530 assert(app
.data
== "1");
3533 // https://issues.dlang.org/show_bug.cgi?id=19799
3536 import std
.format
: format
;
3538 const Nullable
!string a
= const(Nullable
!string
)();
3544 * Forces `this` to the null state.
3548 static if (is(T
== class) ||
is(T
== interface))
3549 _value
.payload
= null;
3551 .destroy(_value
.payload
);
3558 Nullable
!int ni
= 0;
3566 * Assigns `value` to the internally-held state. If the assignment
3567 * succeeds, `this` becomes non-null.
3570 * value = A value of type `T` to assign to this `Nullable`.
3572 ref Nullable
opAssign()(T value
) return
3574 import std
.algorithm
.mutation
: moveEmplace
, move
;
3578 // trusted since payload is known to be uninitialized.
3579 () @trusted { moveEmplace(value
, _value
.payload
); }();
3583 move(value
, _value
.payload
);
3590 * If this `Nullable` wraps a type that already has a null value
3591 * (such as a pointer), then assigning the null value to this
3592 * `Nullable` is no different than assigning any other value of
3593 * type `T`, and the resulting code will look very strange. It
3594 * is strongly recommended that this be avoided by instead using
3595 * the version of `Nullable` that takes an additional `nullValue`
3596 * template argument.
3601 Nullable
!(int*) npi
;
3606 assert(!npi
.isNull
);
3610 * Gets the value if not null. If `this` is in the null state, and the optional
3611 * parameter `fallback` was provided, it will be returned. Without `fallback`,
3612 * calling `get` with a null state is invalid.
3614 * When the fallback type is different from the Nullable type, `get(T)` returns
3618 * fallback = the value to return in case the `Nullable` is null.
3621 * The value held internally by this `Nullable`.
3623 @property ref inout(T
) get() inout @safe pure nothrow
3625 enum message
= "Called `get' on null Nullable!" ~ T
.stringof
~ ".";
3626 assert(!isNull
, message
);
3627 return _value
.payload
;
3631 @property inout(T
) get()(inout(T
) fallback
) inout
3633 return isNull ? fallback
: _value
.payload
;
3637 @property auto get(U
)(inout(U
) fallback
) inout
3639 return isNull ? fallback
: _value
.payload
;
3642 /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions.
3643 alias empty
= isNull
;
3646 alias popFront
= nullify
;
3649 alias popBack
= nullify
;
3652 @property ref inout(T
) front() inout @safe pure nothrow
3661 static if (isCopyable
!T
)
3662 @property inout(typeof(this)) save() inout
3668 static if (isCopyable
!T
)
3669 inout(typeof(this)) opIndex(size_t
[2] dim
) inout
3670 in (dim
[0] <= length
&& dim
[1] <= length
&& dim
[1] >= dim
[0])
3672 return (dim
[0] == 0 && dim
[1] == 1) ?
this : this.init
;
3675 size_t
[2] opSlice(size_t dim
: 0)(size_t from
, size_t to
) const
3681 @property size_t
length() const @safe pure nothrow
3687 alias opDollar(size_t dim
: 0) = length
;
3690 ref inout(T
) opIndex(size_t index
) inout @safe pure nothrow
3697 * Converts `Nullable` to a range. Works even when the contained type is `immutable`.
3699 auto opSlice(this This
)()
3701 static struct NullableRange
3705 // starts out true if value is null
3706 private bool empty_
;
3708 @property bool empty() const @safe pure nothrow
3713 void popFront() @safe pure nothrow
3718 alias popBack
= popFront
;
3720 @property ref inout(typeof(value
.get())) front() inout @safe pure nothrow
3727 @property inout(typeof(this)) save() inout
3732 size_t
[2] opSlice(size_t dim
: 0)(size_t from
, size_t to
) const
3737 @property size_t
length() const @safe pure nothrow
3742 alias opDollar(size_t dim
: 0) = length
;
3744 ref inout(typeof(value
.get())) opIndex(size_t index
) inout @safe pure nothrow
3750 inout(typeof(this)) opIndex(size_t
[2] dim
) inout
3751 in (dim
[0] <= length
&& dim
[1] <= length
&& dim
[1] >= dim
[0])
3753 return (dim
[0] == 0 && dim
[1] == 1) ?
this : this.init
;
3756 auto opIndex() inout
3761 return NullableRange(this, isNull
);
3766 auto nullable(T
)(T t
)
3768 return Nullable
!T(t
);
3774 struct CustomerRecord
3781 Nullable
!CustomerRecord
getByName(string name
)
3783 //A bunch of hairy stuff
3785 return Nullable
!CustomerRecord
.init
;
3788 auto queryResult
= getByName("Doe, John");
3789 if (!queryResult
.isNull
)
3791 //Process Mr. Doe's customer record
3792 auto address
= queryResult
.get
.address
;
3793 auto customerNum
= queryResult
.get
.customerNum
;
3795 //Do some things with this customer's info
3799 //Add the customer to the database
3806 import std
.exception
: assertThrown
;
3808 auto a
= 42.nullable
;
3810 assert(a
.get
== 42);
3814 assertThrown
!Throwable(a
.get
);
3819 import std
.algorithm
.iteration
: each
, joiner
;
3820 Nullable
!int a
= 42;
3822 // Add each value to an array
3824 a
.each
!((n
) => arr
~= n
);
3825 assert(arr
== [42]);
3826 b
.each
!((n
) => arr
~= n
);
3827 assert(arr
== [42]);
3828 // Take first value from an array of Nullables
3829 Nullable
!int[] c
= new Nullable
!int[](10);
3830 c
[7] = Nullable
!int(42);
3831 assert(c
.joiner
.front
== 42);
3835 auto k
= Nullable
!int(74);
3842 static int f(scope const Nullable
!int x
) {
3843 return x
.isNull ?
42 : x
.get
;
3854 import std
.exception
: assertThrown
;
3856 static struct S
{ int x
; }
3862 assert(s
.get
!= S(0));
3864 assert(s
.get
.x
== 9190);
3866 assertThrown
!Throwable(s
.get
.x
= 9441);
3870 // Ensure Nullable can be used in pure/nothrow/@safe environment.
3871 function() @safe pure nothrow
3884 // Ensure Nullable can be used when the value is not pure/nothrow/@safe
3888 this(this) @system {}
3895 assert(s
.get
.x
== 5);
3900 // https://issues.dlang.org/show_bug.cgi?id=9404
3903 alias N
= Nullable
!int;
3908 b
= a
; // `N b = a;` works fine
3915 //Check nullable immutable is constructable
3917 auto a1
= Nullable
!(immutable int)();
3918 auto a2
= Nullable
!(immutable int)(1);
3921 //Check immutable nullable is constructable
3923 auto a1
= immutable (Nullable
!int)();
3924 auto a2
= immutable (Nullable
!int)(1);
3930 alias NInt
= Nullable
!int;
3934 //from other Nullable null
3939 //from other Nullable non-null
3944 //Construct from similar nullable
3945 auto a3
= immutable(NInt
)();
3952 //from other Nullable null
3958 //from other Nullable non-null
3964 //Construct from similar nullable
3965 auto a3
= immutable(NInt
)();
3973 //Check nullable is nicelly embedable in a struct
3978 static struct S2
//inspired from 9404
3985 void opAssign(ref S2 other
)
3990 static foreach (S
; AliasSeq
!(S1
, S2
))
3999 // https://issues.dlang.org/show_bug.cgi?id=10268
4003 JSONValue value
= null;
4004 auto na
= Nullable
!JSONValue(value
);
4006 struct S1
{ int val
; }
4007 struct S2
{ int* val
; }
4008 struct S3
{ immutable int* val
; }
4012 immutable si
= immutable S1(1);
4013 auto x1
= Nullable
!S1(sm
);
4014 auto x2
= immutable Nullable
!S1(sm
);
4015 auto x3
= Nullable
!S1(si
);
4016 auto x4
= immutable Nullable
!S1(si
);
4017 assert(x1
.get
.val
== 1);
4018 assert(x2
.get
.val
== 1);
4019 assert(x3
.get
.val
== 1);
4020 assert(x4
.get
.val
== 1);
4028 immutable si
= immutable S2(&ni
);
4029 auto x1
= Nullable
!S2(sm
);
4030 static assert(!__traits(compiles
, { auto x2
= immutable Nullable
!S2(sm
); }));
4031 static assert(!__traits(compiles
, { auto x3
= Nullable
!S2(si
); }));
4032 auto x4
= immutable Nullable
!S2(si
);
4033 assert(*x1
.get
.val
== 10);
4034 assert(*x4
.get
.val
== 10);
4039 immutable si
= immutable S3(&ni
);
4040 auto x1
= Nullable
!S3(sm
);
4041 auto x2
= immutable Nullable
!S3(sm
);
4042 auto x3
= Nullable
!S3(si
);
4043 auto x4
= immutable Nullable
!S3(si
);
4044 assert(*x1
.get
.val
== 10);
4045 assert(*x2
.get
.val
== 10);
4046 assert(*x3
.get
.val
== 10);
4047 assert(*x4
.get
.val
== 10);
4051 // https://issues.dlang.org/show_bug.cgi?id=10357
4054 import std
.datetime
;
4055 Nullable
!SysTime time
= SysTime(0);
4058 // https://issues.dlang.org/show_bug.cgi?id=10915
4061 import std
.conv
: to
;
4064 Appender
!string buffer
;
4067 assert(ni
.to
!string() == "Nullable.null");
4068 assert((cast(const) ni
).to
!string() == "Nullable.null");
4070 struct Test
{ string s
; }
4071 alias NullableTest
= Nullable
!Test
;
4073 NullableTest nt
= Test("test");
4074 // test output range version
4075 assert(nt
.to
!string() == `Test("test")`);
4076 // test appender version
4077 assert(nt
.toString() == `Test("test")`);
4078 // test const version
4079 assert((cast(const) nt
).toString() == `const(Test)("test")`);
4081 NullableTest ntn
= Test("null");
4082 assert(ntn
.to
!string() == `Test("null")`);
4093 override string
toString()
4095 return d
.to
!string();
4098 Nullable
!TestToString ntts
= new TestToString(2.5);
4099 assert(ntts
.to
!string() == "2.5");
4102 // https://issues.dlang.org/show_bug.cgi?id=14477
4105 static struct DisabledDefaultConstructor
4110 Nullable
!DisabledDefaultConstructor var
;
4111 var
= DisabledDefaultConstructor(5);
4115 // https://issues.dlang.org/show_bug.cgi?id=17440
4118 static interface I
{ }
4125 canary
= 0x5050DEAD;
4130 auto nc
= nullable(c
);
4132 assert(c
.canary
== 0xA71FE);
4135 auto ni
= nullable(i
);
4137 assert(c
.canary
== 0xA71FE);
4140 // https://issues.dlang.org/show_bug.cgi?id=19037
4143 import std
.datetime
: SysTime
;
4149 static bool destroyed
;
4153 ~this() @safe { destroyed
= true; }
4155 // mustn't call opAssign on Test.init in Nullable!Test, because the invariant
4156 // will be called before opAssign on the Test.init that is in Nullable
4157 // and Test.init violates its invariant.
4158 void opAssign(Test rhs
) @safe { assert(false); }
4167 Test
.destroyed
= false;
4171 assert(Test
.destroyed
);
4173 Test
.destroyed
= false;
4175 // don't run destructor on T.init in Nullable on scope exit!
4176 assert(!Test
.destroyed
);
4178 // check that the contained type's destructor is called on assignment
4183 // can't be static, since we need a specific value's pointer
4188 if (this.destroyedRef
)
4190 *this.destroyedRef
= true;
4201 // reset from rvalue destruction in Nullable's opAssign
4204 // overwrite Nullable
4207 // the original S should be destroyed.
4208 assert(destroyed
== true);
4210 // check that the contained type's destructor is still called when required
4213 bool destructorCalled
= false;
4218 ~this() { *this.destroyed
= true; }
4224 assert(!destructorCalled
);
4226 Nullable
!S ns
= Nullable
!S(S(&destructorCalled
));
4228 destructorCalled
= false; // reset after S was destroyed in the NS constructor
4230 assert(destructorCalled
);
4233 // check that toHash on Nullable is forwarded to the contained type
4238 size_t
toHash() const @safe pure nothrow { return 5; }
4241 Nullable
!S s1
= S();
4242 Nullable
!S s2
= Nullable
!S();
4244 assert(typeid(Nullable
!S
).getHash(&s1
) == 5);
4245 assert(typeid(Nullable
!S
).getHash(&s2
) == 0);
4248 // https://issues.dlang.org/show_bug.cgi?id=21704
4251 import std
.array
: staticArray
;
4257 ~this() { destroyed
= true; }
4261 Nullable
!(Probe
[1]) test = [Probe()].staticArray
;
4267 // https://issues.dlang.org/show_bug.cgi?id=21705
4273 bool opEquals(S rhs
) { return n
== rhs
.n
; }
4276 Nullable
!S test1
= S(1), test2
= S(1);
4280 assert(test1
== test2
);
4283 // https://issues.dlang.org/show_bug.cgi?id=22101
4290 ~this() { impure
++; }
4297 // https://issues.dlang.org/show_bug.cgi?id=22100
4300 Nullable
!int a
, b
, c
;
4302 a
= b
= c
= nullable(5);
4305 // https://issues.dlang.org/show_bug.cgi?id=18374
4306 @safe pure nothrow unittest
4308 import std
.algorithm
.comparison
: equal
;
4309 import std
.range
: only
, takeNone
;
4310 import std
.range
.primitives
: hasAssignableElements
, hasLength
,
4311 hasLvalueElements
, hasSlicing
, hasSwappableElements
,
4312 isRandomAccessRange
;
4313 Nullable
!int a
= 42;
4315 assert(a
.front
== 42);
4316 assert(a
.back
== 42);
4318 assert(a
.equal(only(42)));
4319 assert(a
[0 .. $].equal(only(42)));
4321 assert(a
.equal(only(43)));
4323 assert(a
.equal(only(42)));
4326 assert(b
.equal(takeNone(b
)));
4327 Nullable
!int c
= a
.save();
4333 assert(isRandomAccessRange
!(Nullable
!int));
4334 assert(hasLength
!(Nullable
!int));
4335 assert(hasSlicing
!(Nullable
!int));
4336 assert(hasAssignableElements
!(Nullable
!int));
4337 assert(hasSwappableElements
!(Nullable
!int));
4338 assert(hasLvalueElements
!(Nullable
!int));
4341 // https://issues.dlang.org/show_bug.cgi?id=23640
4342 @safe pure nothrow unittest
4344 import std
.algorithm
.comparison
: equal
;
4345 import std
.range
: only
;
4346 import std
.range
.primitives
: hasLength
, hasSlicing
,
4347 isRandomAccessRange
;
4348 static immutable struct S
{ int[] array
; }
4349 auto value
= S([42]);
4350 alias ImmutableNullable
= immutable Nullable
!S
;
4351 auto a
= ImmutableNullable(value
)[];
4352 alias Range
= typeof(a
);
4353 assert(isRandomAccessRange
!Range
);
4354 assert(hasLength
!Range
);
4355 assert(hasSlicing
!Range
);
4357 assert(a
.front
== value
);
4358 assert(a
.back
== value
);
4359 assert(a
[0] == value
);
4360 assert(a
.equal(only(value
)));
4361 assert(a
[0 .. $].equal(only(value
)));
4369 // https://issues.dlang.org/show_bug.cgi?id=24403
4372 static bool destroyed
;
4373 static struct S
{ ~this() { destroyed
= true; } }
4376 Nullable
!S s
= S
.init
;
4382 Nullable
!(const S
) s
= S
.init
;
4388 Nullable
!(immutable S
) s
= S
.init
;
4394 Nullable
!(shared S
) s
= S
.init
;
4401 Just like `Nullable!T`, except that the null state is defined as a
4402 particular value. For example, $(D Nullable!(uint, uint.max)) is an
4403 `uint` that sets aside the value `uint.max` to denote a null
4404 state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D
4405 Nullable!T) because it does not need to store an extra `bool`.
4408 T = The wrapped type for which Nullable provides a null value.
4410 nullValue = The null value which denotes the null state of this
4411 `Nullable`. Must be of type `T`.
4413 struct Nullable(T
, T nullValue
)
4415 private T _value
= nullValue
;
4418 Constructor initializing `this` with `value`.
4421 value = The value to initialize this `Nullable` with.
4430 import std
.format
.spec
: FormatSpec
;
4431 import std
.format
.write
: formatValue
;
4432 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
4433 void toString()(scope void delegate(const(char)[]) sink
, scope const ref FormatSpec
!char fmt
)
4437 sink
.formatValue("Nullable.null", fmt
);
4441 sink
.formatValue(_value
, fmt
);
4445 void toString()(scope void delegate(const(char)[]) sink
, scope const ref FormatSpec
!char fmt
) const
4449 sink
.formatValue("Nullable.null", fmt
);
4453 sink
.formatValue(_value
, fmt
);
4460 import std
.conv
: to
;
4462 const Nullable
!(ulong, 0) x
= 1;
4463 assert(x
.to
!string
== "1");
4467 Check if `this` is in the null state.
4470 true $(B iff) `this` is in the null state, otherwise false.
4472 @property bool isNull() const
4474 //Need to use 'is' if T is a nullable type and
4475 //nullValue is null, or it's a compiler error
4476 static if (is(CommonType
!(T
, typeof(null)) == T
) && nullValue
is null)
4478 return _value
is nullValue
;
4480 //Need to use 'is' if T is a float type
4481 //because NaN != NaN
4482 else static if (__traits(isFloating
, T
) ||
__traits(compiles
, { static assert(!(nullValue
== nullValue
)); }))
4484 return _value
is nullValue
;
4488 return _value
== nullValue
;
4495 Nullable
!(int, -1) ni
;
4496 //Initialized to "null" state
4505 assert(typeof(this).init
.isNull
, typeof(this).stringof
~
4506 ".isNull does not work correctly because " ~ T
.stringof
~
4507 " has an == operator that is non-reflexive and could not be" ~
4508 " determined before runtime to be non-reflexive!");
4511 // https://issues.dlang.org/show_bug.cgi?id=11135
4512 // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed
4513 version (none
) @system unittest
4515 static foreach (T
; AliasSeq
!(float, double, real))
4517 Nullable
!(T
, T
.init
) nf
;
4518 //Initialized to "null" state
4520 assert(nf
is typeof(nf
).init
);
4531 Forces `this` to the null state.
4541 Nullable
!(int, -1) ni
= 0;
4549 Assigns `value` to the internally-held state. If the assignment
4550 succeeds, `this` becomes non-null. No null checks are made. Note
4551 that the assignment may leave `this` in the null state.
4554 value = A value of type `T` to assign to this `Nullable`.
4555 If it is `nullvalue`, then the internal state of
4556 this `Nullable` will be set to null.
4558 void opAssign()(T value
)
4560 import std
.algorithm
.mutation
: swap
;
4562 swap(value
, _value
);
4566 If this `Nullable` wraps a type that already has a null value
4567 (such as a pointer), and that null value is not given for
4568 `nullValue`, then assigning the null value to this `Nullable`
4569 is no different than assigning any other value of type `T`,
4570 and the resulting code will look very strange. It is strongly
4571 recommended that this be avoided by using `T`'s "built in"
4572 null value for `nullValue`.
4577 enum nullVal
= cast(int*) 0xCAFEBABE;
4578 Nullable
!(int*, nullVal
) npi
;
4583 assert(!npi
.isNull
);
4587 Gets the value. `this` must not be in the null state.
4588 This function is also called for the implicit conversion to `T`.
4590 Preconditions: `isNull` must be `false`.
4592 The value held internally by this `Nullable`.
4594 @property ref inout(T
) get() inout
4596 //@@@6169@@@: We avoid any call that might evaluate nullValue's %s,
4597 //Because it might messup get's purity and safety inference.
4598 enum message
= "Called `get' on null Nullable!(" ~ T
.stringof
~ ",nullValue).";
4599 assert(!isNull
, message
);
4606 import std
.exception
: assertThrown
, assertNotThrown
;
4608 Nullable
!(int, -1) ni
;
4609 //`get` is implicitly called. Will throw
4610 //an error in non-release mode
4611 assertThrown
!Throwable(ni
== 0);
4614 assertNotThrown
!Throwable(ni
== 0);
4618 Implicitly converts to `T`.
4619 `this` must not be in the null state.
4625 auto nullable(alias nullValue
, T
)(T t
)
4626 if (is (typeof(nullValue
) == T
))
4628 return Nullable
!(T
, nullValue
)(t
);
4634 Nullable
!(size_t
, size_t
.max
) indexOf(string
[] haystack
, string needle
)
4636 //Find the needle, returning -1 if not found
4638 return Nullable
!(size_t
, size_t
.max
).init
;
4641 void sendLunchInvite(string name
)
4645 //It's safer than C...
4646 auto coworkers
= ["Jane", "Jim", "Marry", "Fred"];
4647 auto pos
= indexOf(coworkers
, "Bob");
4650 //Send Bob an invitation to lunch
4651 sendLunchInvite(coworkers
[pos
]);
4655 //Bob not found; report the error
4658 //And there's no overhead
4659 static assert(Nullable
!(size_t
, size_t
.max
).sizeof
== size_t
.sizeof
);
4665 import std
.exception
: assertThrown
;
4667 Nullable
!(int, int.min
) a
;
4669 assertThrown
!Throwable(a
.get
);
4673 static assert(a
.sizeof
== int.sizeof
);
4679 auto a
= nullable
!(int.min
)(8);
4685 @nogc nothrow pure @safe unittest
4687 // https://issues.dlang.org/show_bug.cgi?id=19226
4688 // fully handle non-self-equal nullValue
4689 static struct Fraction
4694 return denominator
== 0;
4696 bool opEquals(const Fraction rhs
) const
4698 return !isNaN
&& denominator
== rhs
.denominator
;
4701 alias N
= Nullable
!(Fraction
, Fraction
.init
);
4702 assert(N
.init
.isNull
);
4707 static int f(scope const Nullable
!(int, int.min
) x
) {
4708 return x
.isNull ?
42 : x
.get
;
4710 Nullable
!(int, int.min
) a
;
4719 // Ensure Nullable can be used in pure/nothrow/@safe environment.
4720 function() @safe pure nothrow
4722 Nullable
!(int, int.min
) n
;
4733 // Ensure Nullable can be used when the value is not pure/nothrow/@system
4737 bool opEquals(const S s
) const @system { return s
.x
== x
; }
4740 Nullable
!(S
, S(711)) s
;
4750 //Check nullable is nicelly embedable in a struct
4753 Nullable
!(int, 0) ni
;
4755 static struct S2
//inspired from 9404
4757 Nullable
!(int, 0) ni
;
4762 void opAssign(S2 other
)
4767 static foreach (S
; AliasSeq
!(S1
, S2
))
4777 import std
.conv
: to
;
4779 // https://issues.dlang.org/show_bug.cgi?id=10915
4780 Nullable
!(int, 1) ni
= 1;
4781 assert(ni
.to
!string() == "Nullable.null");
4783 struct Test
{ string s
; }
4784 alias NullableTest
= Nullable
!(Test
, Test("null"));
4786 NullableTest nt
= Test("test");
4787 assert(nt
.to
!string() == `Test("test")`);
4789 NullableTest ntn
= Test("null");
4790 assert(ntn
.to
!string() == "Nullable.null");
4801 override string
toString()
4803 return d
.to
!string();
4806 alias NullableTestToString
= Nullable
!(TestToString
, null);
4808 NullableTestToString ntts
= new TestToString(2.5);
4809 assert(ntts
.to
!string() == "2.5");
4814 Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull.
4816 When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`,
4817 pass it to the function you provide and wrap the result in another `Nullable` (if necessary).
4818 If the `Nullable` is null, `apply` will return null itself.
4822 fun = a function operating on the content of the nullable
4825 `fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`.
4828 $(HTTPS en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad)
4830 template apply(alias fun
)
4832 import std
.functional
: unaryFun
;
4834 auto apply(T
)(auto ref T t
)
4835 if (isInstanceOf
!(Nullable
, T
))
4837 alias FunType
= typeof(unaryFun
!fun(T
.init
.get
));
4839 enum MustWrapReturn
= !isInstanceOf
!(Nullable
, FunType
);
4841 static if (MustWrapReturn
)
4843 alias ReturnType
= Nullable
!FunType
;
4847 alias ReturnType
= FunType
;
4852 static if (MustWrapReturn
)
4854 return unaryFun
!fun(t
.get
).nullable
;
4858 return unaryFun
!fun(t
.get
);
4863 return ReturnType
.init
;
4869 nothrow pure @nogc @safe unittest
4871 alias toFloat
= i
=> cast(float) i
;
4873 Nullable
!int sample
;
4875 // apply(null) results in a null `Nullable` of the function's return type.
4876 Nullable
!float f
= sample
.apply
!toFloat
;
4877 assert(sample
.isNull
&& f
.isNull
);
4881 // apply(non-null) calls the function and wraps the result in a `Nullable`.
4882 f
= sample
.apply
!toFloat
;
4883 assert(!sample
.isNull
&& !f
.isNull
);
4884 assert(f
.get
== 3.0f);
4888 nothrow pure @nogc @safe unittest
4890 alias greaterThree
= i
=> (i
> 3) ? i
.nullable
: Nullable
!(typeof(i
)).init
;
4892 Nullable
!int sample
;
4894 // when the function already returns a `Nullable`, that `Nullable` is not wrapped.
4895 auto result
= sample
.apply
!greaterThree
;
4896 assert(sample
.isNull
&& result
.isNull
);
4898 // The function may decide to return a null `Nullable`.
4900 result
= sample
.apply
!greaterThree
;
4901 assert(!sample
.isNull
&& result
.isNull
);
4903 // Or it may return a value already wrapped in a `Nullable`.
4905 result
= sample
.apply
!greaterThree
;
4906 assert(!sample
.isNull
&& !result
.isNull
);
4907 assert(result
.get
== 4);
4910 // test that Nullable.get(default) can merge types
4911 @safe @nogc nothrow pure
4914 Nullable
!ubyte sample
= Nullable
!ubyte();
4916 // Test that get(U) returns the common type of the Nullable type and the parameter type.
4917 assert(sample
.get(1000) == 1000);
4920 // Workaround for https://issues.dlang.org/show_bug.cgi?id=20670
4921 @safe @nogc nothrow pure
4924 immutable struct S
{ }
4926 S
[] array
= Nullable
!(S
[])().get(S
[].init
);
4929 // regression test for https://issues.dlang.org/show_bug.cgi?id=21199
4930 @safe @nogc nothrow pure
4934 assert(S(5).nullable
.apply
!"a.i" == 5);
4937 // regression test for https://issues.dlang.org/show_bug.cgi?id=22176
4938 @safe @nogc nothrow pure
4946 // Nullable shouldn't cause S to generate an
4947 // opAssign that would check the invariant.
4955 Just like `Nullable!T`, except that the object refers to a value
4956 sitting elsewhere in memory. This makes assignments overwrite the
4957 initially assigned value. Internally `NullableRef!T` only stores a
4958 pointer to `T` (i.e., $(D Nullable!T.sizeof == (T*).sizeof)).
4960 struct NullableRef(T
)
4965 Constructor binding `this` to `value`.
4968 value = The value to bind to.
4970 this(T
* value
) @safe pure nothrow
4977 import std
.format
.spec
: FormatSpec
;
4978 import std
.format
.write
: formatValue
;
4979 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
4980 void toString()(scope void delegate(const(char)[]) sink
, scope const ref FormatSpec
!char fmt
)
4984 sink
.formatValue("Nullable.null", fmt
);
4988 sink
.formatValue(*_value
, fmt
);
4992 void toString()(scope void delegate(const(char)[]) sink
, scope const ref FormatSpec
!char fmt
) const
4996 sink
.formatValue("Nullable.null", fmt
);
5000 sink
.formatValue(*_value
, fmt
);
5007 import std
.conv
: to
;
5009 const NullableRef
!(ulong) x
= new ulong(1);
5010 assert(x
.to
!string
== "1");
5014 Binds the internal state to `value`.
5017 value = A pointer to a value of type `T` to bind this `NullableRef` to.
5019 void bind(T
* value
) @safe pure nothrow
5027 NullableRef
!int nr
= new int(42);
5030 int* n
= new int(1);
5036 Returns `true` if and only if `this` is in the null state.
5039 true if `this` is in the null state, otherwise false.
5041 @property bool isNull() const @safe pure nothrow
5043 return _value
is null;
5052 int* n
= new int(42);
5054 assert(!nr
.isNull
&& nr
== 42);
5058 Forces `this` to the null state.
5060 void nullify() @safe pure nothrow
5068 NullableRef
!int nr
= new int(42);
5076 Assigns `value` to the internally-held state.
5079 value = A value of type `T` to assign to this `NullableRef`.
5080 If the internal state of this `NullableRef` has not
5081 been initialized, an error will be thrown in
5084 void opAssign()(T value
)
5085 if (isAssignable
!T
) //@@@9416@@@
5087 enum message
= "Called `opAssign' on null NullableRef!" ~ T
.stringof
~ ".";
5088 assert(!isNull
, message
);
5095 import std
.exception
: assertThrown
, assertNotThrown
;
5099 assertThrown
!Throwable(nr
= 42);
5101 nr
.bind(new int(0));
5103 assertNotThrown
!Throwable(nr
= 42);
5108 Gets the value. `this` must not be in the null state.
5109 This function is also called for the implicit conversion to `T`.
5111 @property ref inout(T
) get() inout @safe pure nothrow
5113 enum message
= "Called `get' on null NullableRef!" ~ T
.stringof
~ ".";
5114 assert(!isNull
, message
);
5121 import std
.exception
: assertThrown
, assertNotThrown
;
5124 //`get` is implicitly called. Will throw
5125 //an error in non-release mode
5126 assertThrown
!Throwable(nr
== 0);
5128 nr
.bind(new int(0));
5129 assertNotThrown
!Throwable(nr
== 0);
5133 Implicitly converts to `T`.
5134 `this` must not be in the null state.
5140 auto nullableRef(T
)(T
* t
)
5142 return NullableRef
!T(t
);
5148 import std
.exception
: assertThrown
;
5151 auto a
= nullableRef(&x
);
5162 assertThrown
!Throwable(a
.get
);
5163 assertThrown
!Throwable(a
= 71);
5171 static int f(scope const NullableRef
!int x
) {
5172 return x
.isNull ?
42 : x
.get
;
5175 auto a
= nullableRef(&x
);
5182 // Ensure NullableRef can be used in pure/nothrow/@safe environment.
5183 function() @safe pure nothrow
5185 auto storage
= new int;
5194 assert(*storage
== 2294);
5201 // Ensure NullableRef can be used when the value is not pure/nothrow/@safe
5205 this(this) @system {}
5206 bool opEquals(const S s
) const @system { return s
.x
== x
; }
5209 auto storage
= S(5);
5221 //Check nullable is nicelly embedable in a struct
5226 static struct S2
//inspired from 9404
5233 void opAssign(S2 other
)
5238 static foreach (S
; AliasSeq
!(S1
, S2
))
5247 // https://issues.dlang.org/show_bug.cgi?id=10915
5250 import std
.conv
: to
;
5252 NullableRef
!int nri
;
5253 assert(nri
.to
!string() == "Nullable.null");
5259 NullableRef
!Test nt
= new Test("test");
5260 assert(nt
.to
!string() == `Test("test")`);
5271 override string
toString()
5273 return d
.to
!string();
5276 TestToString tts
= new TestToString(2.5);
5277 NullableRef
!TestToString ntts
= &tts
;
5278 assert(ntts
.to
!string() == "2.5");
5283 `BlackHole!Base` is a subclass of `Base` which automatically implements
5284 all abstract member functions in `Base` as do-nothing functions. Each
5285 auto-implemented function just returns the default value of the return type
5286 without doing anything.
5289 $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole)
5290 Perl module by Sean M. Burke.
5293 Base = A non-final class for `BlackHole` to inherit from.
5296 $(LREF AutoImplement), $(LREF generateEmptyFunction)
5298 alias BlackHole(Base
) = AutoImplement
!(Base
, generateEmptyFunction
, isAbstractFunction
);
5303 import std
.math
.traits
: isNaN
;
5305 static abstract class C
5308 this(int v
) { m_value
= v
; }
5309 int value() @property { return m_value
; }
5311 abstract real realValue() @property;
5312 abstract void doSomething();
5315 auto c
= new BlackHole
!C(42);
5316 assert(c
.value
== 42);
5318 // Returns real.init which is NaN
5319 assert(c
.realValue
.isNaN
);
5320 // Abstract functions are implemented as do-nothing
5326 import std
.math
.traits
: isNaN
;
5330 interface I_1
{ real test(); }
5331 auto o
= new BlackHole
!I_1
;
5332 assert(o
.test().isNaN()); // NaN
5339 this(int v
) { m_value
= v
; }
5340 int value() @property { return m_value
; }
5342 abstract real realValue() @property;
5343 abstract void doSomething();
5346 auto c
= new BlackHole
!C(42);
5347 assert(c
.value
== 42);
5349 assert(c
.realValue
.isNaN
); // NaN
5353 // https://issues.dlang.org/show_bug.cgi?id=12058
5356 inout(Object
) foo() inout;
5361 nothrow pure @nogc @safe unittest
5365 I
foo() nothrow pure @nogc @safe return scope;
5368 scope cb
= new BlackHole
!I();
5374 `WhiteHole!Base` is a subclass of `Base` which automatically implements
5375 all abstract member functions as functions that always fail. These functions
5376 simply throw an `Error` and never return. `Whitehole` is useful for
5377 trapping the use of class member functions that haven't been implemented.
5380 $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole)
5381 Perl module by Michael G Schwern.
5384 Base = A non-final class for `WhiteHole` to inherit from.
5387 $(LREF AutoImplement), $(LREF generateAssertTrap)
5389 alias WhiteHole(Base
) = AutoImplement
!(Base
, generateAssertTrap
, isAbstractFunction
);
5394 import std
.exception
: assertThrown
;
5398 abstract void notYetImplemented();
5401 auto c
= new WhiteHole
!C
;
5402 assertThrown
!NotImplementedError(c
.notYetImplemented()); // throws an Error
5405 // https://issues.dlang.org/show_bug.cgi?id=20232
5406 nothrow pure @safe unittest
5410 I
foo() nothrow pure @safe return scope;
5413 if (0) // Just checking attribute interference
5415 scope cw
= new WhiteHole
!I();
5421 class NotImplementedError
: Error
5423 this(string method
) nothrow pure @safe
5425 super(method
~ " is not implemented");
5431 import std
.exception
: assertThrown
;
5439 auto o
= new WhiteHole
!I_1
;
5440 assertThrown
!NotImplementedError(o
.foo());
5441 assertThrown
!NotImplementedError(o
.bar());
5447 abstract void notYetImplemented();
5450 auto c
= new WhiteHole
!C
;
5453 c
.notYetImplemented();
5462 `AutoImplement` automatically implements (by default) all abstract member
5463 functions in the class or interface `Base` in specified way.
5465 The second version of `AutoImplement` automatically implements
5466 `Interface`, while deriving from `BaseClass`.
5469 how = template which specifies _how functions will be implemented/overridden.
5471 Two arguments are passed to `how`: the type `Base` and an alias
5472 to an implemented function. Then `how` must return an implemented
5473 function body as a string.
5475 The generated function body can use these keywords:
5477 $(LI `a0`, `a1`, …: arguments passed to the function;)
5478 $(LI `args`: a tuple of the arguments;)
5479 $(LI `self`: an alias to the function itself;)
5480 $(LI `parent`: an alias to the overridden function (if any).)
5483 You may want to use templated property functions (instead of Implicit
5484 Template Properties) to generate complex functions:
5485 --------------------
5486 // Prints log messages for each call to overridden functions.
5487 string generateLogger(C, alias fun)() @property
5490 enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
5493 stmt ~= q{ struct Importer { import std.stdio; } };
5494 stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
5495 static if (!__traits(isAbstractFunction, fun))
5497 static if (is(ReturnType!fun == void))
5498 stmt ~= q{ parent(args); };
5501 auto r = parent(args);
5502 Importer.writeln("--> ", r);
5508 --------------------
5510 what = template which determines _what functions should be
5511 implemented/overridden.
5513 An argument is passed to `what`: an alias to a non-final member
5514 function in `Base`. Then `what` must return a boolean value.
5515 Return `true` to indicate that the passed function should be
5516 implemented/overridden.
5518 --------------------
5519 // Sees if fun returns something.
5520 enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
5521 --------------------
5526 Generated code is inserted in the scope of `std.typecons` module. Thus,
5527 any useful functions outside `std.typecons` cannot be used in the generated
5528 code. To workaround this problem, you may `import` necessary things in a
5529 local struct, as done in the `generateLogger()` template in the above
5536 $(LI Variadic arguments to constructors are not forwarded to super.)
5537 $(LI Deep interface inheritance causes compile error with messages like
5538 "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar
5539 does not override any function". [$(BUGZILLA 2525)] )
5540 $(LI The `parent` keyword is actually a delegate to the super class'
5541 corresponding member function. [$(BUGZILLA 2540)] )
5542 $(LI Using alias template parameter in `how` and/or `what` may cause
5543 strange compile error. Use template tuple parameter instead to workaround
5544 this problem. [$(BUGZILLA 4217)] )
5547 class AutoImplement(Base
, alias how
, alias what
= isAbstractFunction
) : Base
5548 if (!is(how
== class))
5550 private alias autoImplement_helper_
=
5551 AutoImplement_Helper
!("autoImplement_helper_", "Base", Base
, typeof(this), how
, what
);
5552 mixin(autoImplement_helper_
.code
);
5556 class AutoImplement(
5557 Interface
, BaseClass
, alias how
,
5558 alias what
= isAbstractFunction
) : BaseClass
, Interface
5559 if (is(Interface
== interface) && is(BaseClass
== class))
5561 private alias autoImplement_helper_
= AutoImplement_Helper
!(
5562 "autoImplement_helper_", "Interface", Interface
, typeof(this), how
, what
);
5563 mixin(autoImplement_helper_
.code
);
5569 interface PackageSupplier
5575 static abstract class AbstractFallbackPackageSupplier
: PackageSupplier
5577 protected PackageSupplier default_
, fallback
;
5579 this(PackageSupplier default_
, PackageSupplier fallback
)
5581 this.default_
= default_
;
5582 this.fallback
= fallback
;
5589 template fallback(T
, alias func
)
5591 import std
.format
: format
;
5592 // for all implemented methods:
5593 // - try default first
5594 // - only on a failure run & return fallback
5598 return default_
.%1$s
(args
);
5602 return fallback
.%1$s
(args
);
5604 }.format(__traits(identifier
, func
));
5607 // combines two classes and use the second one as fallback
5608 alias FallbackPackageSupplier
= AutoImplement
!(AbstractFallbackPackageSupplier
, fallback
);
5610 class FailingPackageSupplier
: PackageSupplier
5612 int foo(){ throw new Exception("failure"); }
5613 int bar(){ return 2;}
5616 class BackupPackageSupplier
: PackageSupplier
5618 int foo(){ return -1; }
5619 int bar(){ return -1;}
5622 auto registry
= new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier());
5624 assert(registry
.foo() == -1);
5625 assert(registry
.bar() == 2);
5629 * Code-generating stuffs are encupsulated in this helper template so that
5630 * namespace pollution, which can cause name confliction with Base's public
5631 * members, should be minimized.
5633 private template AutoImplement_Helper(string myName
, string baseName
,
5634 Base
, Self
, alias generateMethodBody
, alias cherrypickMethod
)
5637 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5639 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5641 // Returns function overload sets in the class C, filtered with pred.
5642 template enumerateOverloads(C
, alias pred
)
5644 template Impl(names
...)
5646 import std
.meta
: Filter
;
5647 static if (names
.length
> 0)
5649 alias methods
= Filter
!(pred
, MemberFunctionsTuple
!(C
, names
[0]));
5650 alias next
= Impl
!(names
[1 .. $]);
5652 static if (methods
.length
> 0)
5653 alias Impl
= AliasSeq
!(OverloadSet
!(names
[0], methods
), next
);
5658 alias Impl
= AliasSeq
!();
5661 alias enumerateOverloads
= Impl
!(__traits(allMembers
, C
));
5664 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5666 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5668 // Add a non-final check to the cherrypickMethod.
5669 enum bool canonicalPicker(fun
.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) =
5670 !__traits(isFinalFunction
, fun
[0]) && cherrypickMethod
!(fun
);
5673 * A tuple of overload sets, each item of which consists of functions to be
5674 * implemented by the generated code.
5676 alias targetOverloadSets
= enumerateOverloads
!(Base
, canonicalPicker
);
5679 * Super class of this AutoImplement instance
5681 alias Super
= BaseTypeTuple
!(Self
)[0];
5682 static assert(is(Super
== class));
5683 static assert(is(Base
== interface) ||
is(Super
== Base
));
5686 * A tuple of the super class' constructors. Used for forwarding
5687 * constructor calls.
5689 static if (__traits(hasMember
, Super
, "__ctor"))
5690 alias ctorOverloadSet
= OverloadSet
!("__ctor", __traits(getOverloads
, Super
, "__ctor"));
5692 alias ctorOverloadSet
= OverloadSet
!("__ctor"); // empty
5695 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5697 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5700 * The generated code will be mixed into AutoImplement, which will be
5701 * instantiated in this module's scope. Thus, any user-defined types are
5702 * out of scope and cannot be used directly (i.e. by their names).
5704 * We will use FuncInfo instances for accessing return types and parameter
5705 * types of the implemented functions. The instances will be populated to
5706 * the AutoImplement's scope in a certain way; see the populate() below.
5709 // Returns the preferred identifier for the FuncInfo instance for the i-th
5710 // overloaded function with the name.
5711 template INTERNAL_FUNCINFO_ID(string name
, size_t i
)
5713 import std
.format
: format
;
5715 enum string INTERNAL_FUNCINFO_ID
= format("F_%s_%s", name
, i
);
5719 * Insert FuncInfo instances about all the target functions here. This
5720 * enables the generated code to access type information via, for example,
5721 * "autoImplement_helper_.F_foo_1".
5723 template populate(overloads
...)
5725 static if (overloads
.length
> 0)
5727 mixin populate
!(overloads
[0].name
, overloads
[0].contents
);
5728 mixin populate
!(overloads
[1 .. $]);
5731 template populate(string name
, methods
...)
5733 static if (methods
.length
> 0)
5735 mixin populate
!(name
, methods
[0 .. $ - 1]);
5737 alias target
= methods
[$ - 1];
5738 enum ith
= methods
.length
- 1;
5739 mixin("alias " ~ INTERNAL_FUNCINFO_ID
!(name
, ith
) ~ " = FuncInfo!target;");
5743 public mixin populate
!(targetOverloadSets
);
5744 public mixin populate
!( ctorOverloadSet
);
5747 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5748 // Code-generating policies
5749 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5751 /* Common policy configurations for generating constructors and methods. */
5752 template CommonGeneratingPolicy()
5754 // base class identifier which generated code should use
5755 enum string BASE_CLASS_ID
= baseName
;
5757 // FuncInfo instance identifier which generated code should use
5758 template FUNCINFO_ID(string name
, size_t i
)
5760 enum string FUNCINFO_ID
=
5761 myName
~ "." ~ INTERNAL_FUNCINFO_ID
!(name
, i
);
5765 /* Policy configurations for generating constructors. */
5766 template ConstructorGeneratingPolicy()
5768 mixin CommonGeneratingPolicy
;
5770 /* Generates constructor body. Just forward to the base class' one. */
5771 string
generateFunctionBody(ctor
.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
5773 enum varstyle
= variadicFunctionStyle
!(typeof(&ctor
[0]));
5775 static if (varstyle
& (Variadic
.c | Variadic
.d
))
5777 // the argptr-forwarding problem
5778 //pragma(msg, "Warning: AutoImplement!(", Base, ") ",
5779 // "ignored variadic arguments to the constructor ",
5780 // FunctionTypeOf!(typeof(&ctor[0])) );
5782 return "super(args);";
5786 /* Policy configurations for genearting target methods. */
5787 template MethodGeneratingPolicy()
5789 mixin CommonGeneratingPolicy
;
5791 /* Geneartes method body. */
5792 string
generateFunctionBody(func
.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
5794 return generateMethodBody
!(Base
, func
); // given
5799 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5801 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5803 alias ConstructorGenerator
= MemberFunctionGenerator
!(ConstructorGeneratingPolicy
!());
5804 alias MethodGenerator
= MemberFunctionGenerator
!(MethodGeneratingPolicy
!());
5806 public enum string code
=
5807 ConstructorGenerator
.generateCode
!( ctorOverloadSet
) ~ "\n" ~
5808 MethodGenerator
.generateCode
!(targetOverloadSets
);
5810 debug (SHOW_GENERATED_CODE
)
5812 pragma(msg
, "-------------------- < ", Base
, " >");
5814 pragma(msg
, "--------------------");
5818 //debug = SHOW_GENERATED_CODE;
5822 // no function to implement
5825 auto o
= new BlackHole
!I_1
;
5829 interface I_3
{ void test(int, in int, out int, ref int, lazy int); }
5830 auto o
= new BlackHole
!I_3
;
5832 // use of user-defined type
5835 interface I_4
{ S
test(); }
5836 auto o
= new BlackHole
!I_4
;
5846 auto o
= new BlackHole
!I_5
;
5848 // constructor forwarding
5852 this(int n
) { assert(n
== 42); }
5853 this(string s
) { assert(s
== "Deeee"); }
5856 auto o1
= new BlackHole
!C_6(42);
5857 auto o2
= new BlackHole
!C_6("Deeee");
5858 auto o3
= new BlackHole
!C_6(1, 2, 3, 4);
5865 int test_pure() pure;
5866 int test_nothrow() nothrow;
5867 int test_property() @property;
5868 int test_safe() @safe;
5869 int test_trusted() @trusted;
5870 int test_system() @system;
5871 int test_pure_nothrow() pure nothrow;
5873 auto o
= new BlackHole
!I_7
;
5879 void test_const() const;
5880 void test_immutable() immutable;
5881 void test_shared() shared;
5882 void test_shared_const() shared const;
5884 auto o
= new BlackHole
!I_8
;
5890 private string foo_
;
5896 protected string
boilerplate() @property
5898 return "Boilerplate stuff.";
5901 public string
foo() @property
5909 string
testMethod(size_t
);
5912 static string
generateTestMethod(C
, alias fun
)() @property
5914 return "return this.boilerplate[0 .. a0];";
5917 auto o
= new AutoImplement
!(I_10
, C_9
, generateTestMethod
)("Testing");
5918 assert(o
.testMethod(11) == "Boilerplate");
5919 assert(o
.foo
== "Testing");
5921 /+ // deep inheritance
5923 // https://issues.dlang.org/show_bug.cgi?id=2525
5924 // https://issues.dlang.org/show_bug.cgi?id=3525
5925 // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic()
5926 interface I { void foo(); }
5929 static abstract class C_9 : K {}
5930 auto o = new BlackHole!C_9;
5932 // test `parent` alias
5936 void simple(int) @safe;
5937 int anotherSimple(string
);
5938 int overloaded(int);
5940 void overloaded(string) @safe;
5946 import std
.traits
: Parameters
, ReturnType
;
5947 import std
.meta
: Alias
;
5949 protected ReturnType
!fn
_impl(alias fn
)(Parameters
!fn
)
5950 if (is(Alias
!(__traits(parent
, fn
)) == interface))
5952 static if (!is(typeof(return) == void))
5953 return typeof(return).init
;
5957 template tpl(I
, alias fn
)
5958 if (is(I
== interface) && __traits(isSame
, __traits(parent
, fn
), I
))
5960 enum string tpl
= q
{
5961 enum bool haveReturn
= !is(typeof(return) == void);
5963 static if (is(typeof(return) == void))
5966 return _impl
!parent(args
);
5970 auto o
= new AutoImplement
!(I_11
, C_11
, tpl
);
5974 // https://issues.dlang.org/show_bug.cgi?id=17177
5975 // AutoImplement fails on function overload sets with
5976 // "cannot infer type from overloaded function symbol"
5979 static class Issue17177
5984 Issue17177
overloaded(string n
)
5998 static string
how(C
, alias fun
)()
6000 static if (!is(ReturnType
!fun
== void))
6003 return parent(args
);
6014 import std
.meta
: templateNot
;
6015 alias Implementation
= AutoImplement
!(Issue17177
, how
, templateNot
!isFinalFunction
);
6018 version (StdUnittest
)
6020 // https://issues.dlang.org/show_bug.cgi?id=10647
6021 // Add prefix "issue10647_" as a workaround for
6022 // https://issues.dlang.org/show_bug.cgi?id=1238
6023 private string
issue10647_generateDoNothing(C
, alias fun
)() @property
6027 static if (is(ReturnType
!fun
== void))
6031 string returnType
= ReturnType
!fun
.stringof
;
6032 stmt
~= "return "~returnType
~".init;";
6037 private template issue10647_isAlwaysTrue(alias fun
)
6039 enum issue10647_isAlwaysTrue
= true;
6042 // Do nothing template
6043 private template issue10647_DoNothing(Base
)
6045 alias issue10647_DoNothing
= AutoImplement
!(Base
, issue10647_generateDoNothing
, issue10647_isAlwaysTrue
);
6048 // A class to be overridden
6049 private class issue10647_Foo
{
6056 auto foo
= new issue10647_DoNothing
!issue10647_Foo();
6061 Used by MemberFunctionGenerator.
6063 package template OverloadSet(string nam
, T
...)
6065 enum string name
= nam
;
6070 Used by MemberFunctionGenerator.
6072 package template FuncInfo(alias func
)
6073 if (is(typeof(&func
)))
6075 alias RT
= ReturnType
!(typeof(&func
));
6076 alias PT
= Parameters
!(typeof(&func
));
6078 package template FuncInfo(Func
)
6080 alias RT
= ReturnType
!Func
;
6081 alias PT
= Parameters
!Func
;
6085 General-purpose member function generator.
6086 --------------------
6087 template GeneratingPolicy()
6089 // [optional] the name of the class where functions are derived
6090 enum string BASE_CLASS_ID;
6092 // [optional] define this if you have only function types
6093 enum bool WITHOUT_SYMBOL;
6095 // [optional] Returns preferred identifier for i-th parameter.
6096 template PARAMETER_VARIABLE_ID(size_t i);
6098 // Returns the identifier of the FuncInfo instance for the i-th overload
6099 // of the specified name. The identifier must be accessible in the scope
6100 // where generated code is mixed.
6101 template FUNCINFO_ID(string name, size_t i);
6103 // Returns implemented function body as a string. When WITHOUT_SYMBOL is
6104 // defined, the latter is used.
6105 template generateFunctionBody(alias func);
6106 template generateFunctionBody(string name, FuncType);
6108 --------------------
6110 package template MemberFunctionGenerator(alias Policy
)
6113 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
6115 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
6117 alias format
= std
.format
.format
;
6119 enum CONSTRUCTOR_NAME
= "__ctor";
6121 // true if functions are derived from a base class
6122 enum WITH_BASE_CLASS
= __traits(hasMember
, Policy
, "BASE_CLASS_ID");
6124 // true if functions are specified as types, not symbols
6125 enum WITHOUT_SYMBOL
= __traits(hasMember
, Policy
, "WITHOUT_SYMBOL");
6127 // preferred identifier for i-th parameter variable
6128 static if (__traits(hasMember
, Policy
, "PARAMETER_VARIABLE_ID"))
6130 alias PARAMETER_VARIABLE_ID
= Policy
.PARAMETER_VARIABLE_ID
;
6134 enum string
PARAMETER_VARIABLE_ID(size_t i
) = format("a%s", i
);
6135 // default: a0, a1, ...
6138 // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach.
6139 template CountUp(size_t n
)
6142 alias CountUp
= AliasSeq
!(CountUp
!(n
- 1), n
- 1);
6144 alias CountUp
= AliasSeq
!();
6148 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
6150 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
6153 * Runs through all the target overload sets and generates D code which
6154 * implements all the functions in the overload sets.
6156 public string
generateCode(overloads
...)() @property
6160 // run through all the overload sets
6161 foreach (i_
; CountUp
!(0 + overloads
.length
)) // workaround
6163 enum i
= 0 + i_
; // workaround
6164 alias oset
= overloads
[i
];
6166 code
~= generateCodeForOverloadSet
!(oset
);
6168 static if (WITH_BASE_CLASS
&& oset
.name
!= CONSTRUCTOR_NAME
)
6170 // The generated function declarations may hide existing ones
6171 // in the base class (cf. HiddenFuncError), so we put an alias
6172 // declaration here to reveal possible hidden functions.
6173 code
~= format("alias %s = %s.%s;\n",
6175 // super: https://issues.dlang.org/show_bug.cgi?id=2540
6176 Policy
.BASE_CLASS_ID
,
6183 // handle each overload set
6184 string
generateCodeForOverloadSet(alias oset
)() @property
6188 foreach (i_
; CountUp
!(0 + oset
.contents
.length
)) // workaround
6190 enum i
= 0 + i_
; // workaround
6191 code
~= generateFunction
!(
6192 Policy
.FUNCINFO_ID
!(oset
.name
, i
), oset
.name
,
6193 oset
.contents
[i
]) ~ "\n";
6199 * Returns D code which implements the function func. This function
6200 * actually generates only the declarator part; the function body part is
6201 * generated by the functionGenerator() policy.
6203 public string
generateFunction(
6204 string myFuncInfo
, string name
, func
... )() @property
6206 import std
.format
: format
;
6208 enum isCtor
= (name
== CONSTRUCTOR_NAME
);
6210 string code
; // the result
6212 auto paramsRes
= generateParameters
!(myFuncInfo
, func
)();
6213 code
~= paramsRes
.imports
;
6215 /*** Function Declarator ***/
6217 alias Func
= FunctionTypeOf
!(func
);
6218 alias FA
= FunctionAttribute
;
6219 enum atts
= functionAttributes
!(func
);
6220 enum realName
= isCtor ?
"this" : name
;
6222 // FIXME?? Make it so that these aren't CTFE funcs any more, since
6223 // Format is deprecated, and format works at compile time?
6224 /* Made them CTFE funcs just for the sake of Format!(...) */
6226 // return type with optional "ref"
6227 static string
make_returnType()
6233 if (atts
& FA
.ref_
) rtype
~= "ref ";
6234 rtype
~= myFuncInfo
~ ".RT";
6238 enum returnType
= make_returnType();
6240 // function attributes attached after declaration
6241 static string
make_postAtts()
6244 if (atts
& FA
.pure_
) poatts
~= " pure";
6245 if (atts
& FA
.nothrow_
) poatts
~= " nothrow";
6246 if (atts
& FA
.property
) poatts
~= " @property";
6247 if (atts
& FA
.safe
) poatts
~= " @safe";
6248 if (atts
& FA
.trusted
) poatts
~= " @trusted";
6249 if (atts
& FA
.scope_
) poatts
~= " scope";
6250 if (atts
& FA
.return_
) poatts
~= " return";
6253 enum postAtts
= make_postAtts();
6255 // function storage class
6256 static string
make_storageClass()
6259 if (is(Func
== shared)) postc
~= " shared";
6260 if (is(Func
== const)) postc
~= " const";
6261 if (is(Func
== inout)) postc
~= " inout";
6262 if (is(Func
== immutable)) postc
~= " immutable";
6265 enum storageClass
= make_storageClass();
6268 if (__traits(isVirtualMethod
, func
))
6269 code
~= "override ";
6270 code
~= format("extern(%s) %s %s(%s) %s %s\n",
6271 functionLinkage
!(func
),
6275 postAtts
, storageClass
);
6278 /*** Function Body ***/
6281 enum nparams
= Parameters
!(func
).length
;
6283 /* Declare keywords: args, self and parent. */
6286 preamble
~= "alias args = AliasSeq!(" ~ enumerateParameters
!(nparams
) ~ ");\n";
6289 preamble
~= "alias self = " ~ name
~ ";\n";
6290 static if (WITH_BASE_CLASS
)
6291 preamble
~= `alias parent = __traits(getMember, ` ~ Policy
.BASE_CLASS_ID
~ `, "` ~ name
~ `");`;
6295 static if (WITHOUT_SYMBOL
)
6296 enum fbody
= Policy
.generateFunctionBody
!(name
, func
);
6298 enum fbody
= Policy
.generateFunctionBody
!(func
);
6309 * Returns D code which declares function parameters,
6310 * and optionally any imports (e.g. core.vararg)
6311 * "ref int a0, real a1, ..."
6313 static struct GenParams
{ string imports
, params
; }
6314 GenParams
generateParameters(string myFuncInfo
, func
...)()
6316 alias STC
= ParameterStorageClass
;
6317 alias stcs
= ParameterStorageClassTuple
!(func
);
6318 enum nparams
= stcs
.length
;
6320 string imports
= ""; // any imports required
6321 string params
= ""; // parameters
6323 foreach (i
, stc; stcs
)
6325 if (i
> 0) params
~= ", ";
6327 // Parameter storage classes.
6328 if (stc & STC
.scope_
) params
~= "scope ";
6329 if (stc & STC
.in_
) params
~= "in ";
6330 if (stc & STC
.out_
) params
~= "out ";
6331 if (stc & STC
.ref_
) params
~= "ref ";
6332 if (stc & STC
.lazy_
) params
~= "lazy ";
6334 // Take parameter type from the FuncInfo.
6335 params
~= format("%s.PT[%s]", myFuncInfo
, i
);
6337 // Declare a parameter variable.
6338 params
~= " " ~ PARAMETER_VARIABLE_ID
!(i
);
6341 // Add some ellipsis part if needed.
6342 auto style
= variadicFunctionStyle
!(func
);
6343 final switch (style
)
6348 case Variadic
.c
, Variadic
.d
:
6349 imports
~= "import core.vararg;\n";
6350 // (...) or (a, b, ...)
6351 params
~= (nparams
== 0) ?
"..." : ", ...";
6354 case Variadic
.typesafe
:
6359 return typeof(return)(imports
, params
);
6362 // Returns D code which enumerates n parameter variables using comma as the
6363 // separator. "a0, a1, a2, a3"
6364 string
enumerateParameters(size_t n
)() @property
6368 foreach (i_
; CountUp
!(n
))
6370 enum i
= 0 + i_
; // workaround
6371 if (i
> 0) params
~= ", ";
6372 params
~= PARAMETER_VARIABLE_ID
!(i
);
6380 Predefined how-policies for `AutoImplement`. These templates are also used by
6381 `BlackHole` and `WhiteHole`, respectively.
6383 template generateEmptyFunction(C
, func
.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)
6385 static if (is(ReturnType
!(func
) == void))
6386 enum string generateEmptyFunction
= q
{
6388 else static if (functionAttributes
!(func
) & FunctionAttribute
.ref_
)
6389 enum string generateEmptyFunction
= q
{
6390 static typeof(return) dummy
;
6394 enum string generateEmptyFunction
= q
{
6395 return typeof(return).init
;
6402 alias BlackHole(Base
) = AutoImplement
!(Base
, generateEmptyFunction
);
6410 auto i
= new BlackHole
!I();
6411 // generateEmptyFunction returns the default value of the return type without doing anything
6413 assert(i
.bar
is null);
6417 template generateAssertTrap(C
, func
...)
6419 enum string generateAssertTrap
=
6420 `throw new NotImplementedError("` ~ C
.stringof
~ "."
6421 ~ __traits(identifier
, func
) ~ `");`;
6427 import std
.exception
: assertThrown
;
6429 alias WhiteHole(Base
) = AutoImplement
!(Base
, generateAssertTrap
);
6437 auto i
= new WhiteHole
!I();
6438 // generateAssertTrap throws an exception for every unimplemented function of the interface
6439 assertThrown
!NotImplementedError(i
.foo
);
6440 assertThrown
!NotImplementedError(i
.bar
);
6445 pragma(mangle
, "_d_toObject")
6446 extern(C
) pure nothrow Object
typecons_d_toObject(void* p
);
6450 * Avoids opCast operator overloading.
6452 private template dynamicCast(T
)
6453 if (is(T
== class) ||
is(T
== interface))
6456 T
dynamicCast(S
)(inout S source
)
6457 if (is(S
== class) ||
is(S
== interface))
6459 static if (is(Unqual
!S
: Unqual
!T
))
6461 import std
.traits
: QualifierOf
;
6462 alias Qual
= QualifierOf
!S
; // SharedOf or MutableOf
6463 alias TmpT
= Qual
!(Unqual
!T
);
6464 inout(TmpT
) tmp
= source
; // bypass opCast by implicit conversion
6465 return *cast(T
*)(&tmp
); // + variable pointer cast + dereference
6469 return cast(T
) typecons_d_toObject(*cast(void**)(&source
));
6476 class C
{ @disable void opCast(T
)(); }
6478 static assert(!__traits(compiles
, cast(Object
) c
));
6479 auto o
= dynamicCast
!Object(c
);
6482 interface I
{ @disable void opCast(T
)(); Object
instance(); }
6483 interface J
{ @disable void opCast(T
)(); Object
instance(); }
6484 class D
: I
, J
{ Object
instance() { return this; } }
6486 static assert(!__traits(compiles
, cast(J
) i
));
6487 J j
= dynamicCast
!J(i
);
6488 assert(i
.instance() is j
.instance());
6492 Supports structural based typesafe conversion.
6494 If `Source` has structural conformance with the `interface` `Targets`,
6495 wrap creates an internal wrapper class which inherits `Targets` and
6496 wraps the `src` object, then returns it.
6498 `unwrap` can be used to extract objects which have been wrapped by `wrap`.
6500 template wrap(Targets
...)
6501 if (Targets
.length
>= 1 && allSatisfy
!(isMutable
, Targets
))
6503 import std
.meta
: staticMap
;
6506 auto wrap(Source
)(inout Source src
) @trusted pure nothrow
6507 if (Targets
.length
== 1 && is(Source
: Targets
[0]))
6509 alias T
= Select
!(is(Source
== shared), shared Targets
[0], Targets
[0]);
6510 return dynamicCast
!(inout T
)(src
);
6512 // structural upcast
6513 template wrap(Source
)
6514 if (!allSatisfy
!(Bind
!(isImplicitlyConvertible
, Source
), Targets
))
6516 auto wrap(inout Source src
)
6518 static assert(hasRequireMethods
!(),
6519 "Source "~Source
.stringof
~
6520 " does not have structural conformance to "~
6523 alias T
= Select
!(is(Source
== shared), shared Impl
, Impl
);
6524 return new inout T(src
);
6527 template FuncInfo(string s
, F
)
6533 // https://issues.dlang.org/show_bug.cgi?id=12064: Remove NVI members
6534 template OnlyVirtual(members
...)
6536 enum notFinal(alias T
) = !__traits(isFinalFunction
, T
);
6537 import std
.meta
: Filter
;
6538 alias OnlyVirtual
= Filter
!(notFinal
, members
);
6541 // Concat all Targets function members into one tuple
6542 template Concat(size_t i
= 0)
6544 static if (i
>= Targets
.length
)
6545 alias Concat
= AliasSeq
!();
6548 alias Concat
= AliasSeq
!(OnlyVirtual
!(GetOverloadedMethods
!(Targets
[i
]), Concat
!(i
+ 1)));
6552 // Remove duplicated functions based on the identifier name and function type covariance
6553 template Uniq(members
...)
6555 static if (members
.length
== 0)
6556 alias Uniq
= AliasSeq
!();
6559 alias func
= members
[0];
6560 enum name
= __traits(identifier
, func
);
6561 alias type
= FunctionTypeOf
!func
;
6562 template check(size_t i
, mem
...)
6564 static if (i
>= mem
.length
)
6565 enum ptrdiff_t check
= -1;
6568 enum ptrdiff_t check
=
6569 __traits(identifier
, func
) == __traits(identifier
, mem
[i
]) &&
6570 !is(DerivedFunctionType
!(type
, FunctionTypeOf
!(mem
[i
])) == void)
6571 ? i
: check
!(i
+ 1, mem
);
6574 enum ptrdiff_t x
= 1 + check
!(0, members
[1 .. $]);
6577 alias typex
= DerivedFunctionType
!(type
, FunctionTypeOf
!(members
[x
]));
6578 alias remain
= Uniq
!(members
[1 .. x
], members
[x
+ 1 .. $]);
6580 static if (remain
.length
>= 1 && remain
[0].name
== name
&&
6581 !is(DerivedFunctionType
!(typex
, remain
[0].type
) == void))
6583 alias F
= DerivedFunctionType
!(typex
, remain
[0].type
);
6584 alias Uniq
= AliasSeq
!(FuncInfo
!(name
, F
), remain
[1 .. $]);
6587 alias Uniq
= AliasSeq
!(FuncInfo
!(name
, typex
), remain
);
6591 alias Uniq
= AliasSeq
!(FuncInfo
!(name
, type
), Uniq
!(members
[1 .. $]));
6595 alias TargetMembers
= Uniq
!(Concat
!()); // list of FuncInfo
6596 alias SourceMembers
= GetOverloadedMethods
!Source
; // list of function symbols
6598 // Check whether all of SourceMembers satisfy covariance target in TargetMembers
6599 template hasRequireMethods(size_t i
= 0)
6601 static if (i
>= TargetMembers
.length
)
6602 enum hasRequireMethods
= true;
6605 enum hasRequireMethods
=
6606 findCovariantFunction
!(TargetMembers
[i
], Source
, SourceMembers
) != -1 &&
6607 hasRequireMethods
!(i
+ 1);
6611 // Internal wrapper class
6612 final class Impl
: Structural
, Targets
6615 Source _wrap_source
;
6617 this( inout Source s
) inout @safe pure nothrow { _wrap_source
= s
; }
6618 this(shared inout Source s
) shared inout @safe pure nothrow { _wrap_source
= s
; }
6620 // BUG: making private should work with NVI.
6621 protected final inout(Object
) _wrap_getSource() inout @trusted
6623 return dynamicCast
!(inout Object
)(_wrap_source
);
6626 import std
.conv
: to
;
6627 import core
.lifetime
: forward
;
6628 template generateFun(size_t i
)
6630 enum name
= TargetMembers
[i
].name
;
6631 enum fa
= functionAttributes
!(TargetMembers
[i
].type
);
6632 static @property stc()
6635 if (fa
& FunctionAttribute
.property
) r
~= "@property ";
6636 if (fa
& FunctionAttribute
.ref_
) r
~= "ref ";
6637 if (fa
& FunctionAttribute
.pure_
) r
~= "pure ";
6638 if (fa
& FunctionAttribute
.nothrow_
) r
~= "nothrow ";
6639 if (fa
& FunctionAttribute
.trusted
) r
~= "@trusted ";
6640 if (fa
& FunctionAttribute
.safe
) r
~= "@safe ";
6643 static @property mod()
6645 alias type
= AliasSeq
!(TargetMembers
[i
].type
)[0];
6647 static if (is(type
== immutable)) r
~= " immutable";
6650 static if (is(type
== shared)) r
~= " shared";
6651 static if (is(type
== const)) r
~= " const";
6652 else static if (is(type
== inout)) r
~= " inout";
6657 enum n
= to
!string(i
);
6658 static if (fa
& FunctionAttribute
.property
)
6660 static if (Parameters
!(TargetMembers
[i
].type
).length
== 0)
6661 enum fbody
= "_wrap_source."~name
;
6663 enum fbody
= "_wrap_source."~name
~" = forward!args";
6667 enum fbody
= "_wrap_source."~name
~"(forward!args)";
6670 "override "~stc~"ReturnType!(TargetMembers["~n
~"].type) "
6671 ~ name
~"(Parameters!(TargetMembers["~n
~"].type) args) "~mod
~
6672 "{ return "~fbody
~"; }";
6676 static foreach (i
; 0 .. TargetMembers
.length
)
6677 mixin(generateFun
!i
);
6682 template wrap(Targets
...)
6683 if (Targets
.length
>= 1 && !allSatisfy
!(isMutable
, Targets
))
6685 import std
.meta
: staticMap
;
6687 alias wrap
= .wrap
!(staticMap
!(Unqual
, Targets
));
6691 template unwrap(Target
)
6692 if (isMutable
!Target
)
6695 auto unwrap(Source
)(inout Source src
) @trusted pure nothrow
6696 if (is(Target
: Source
))
6698 alias T
= Select
!(is(Source
== shared), shared Target
, Target
);
6699 return dynamicCast
!(inout T
)(src
);
6701 // structural downcast
6702 auto unwrap(Source
)(inout Source src
) @trusted pure nothrow
6703 if (!is(Target
: Source
))
6705 alias T
= Select
!(is(Source
== shared), shared Target
, Target
);
6706 Object o
= dynamicCast
!(Object
)(src
); // remove qualifier
6709 if (auto a
= dynamicCast
!(Structural
)(o
))
6711 if (auto d
= dynamicCast
!(inout T
)(o
= a
._wrap_getSource()))
6714 else if (auto d
= dynamicCast
!(inout T
)(o
))
6724 template unwrap(Target
)
6725 if (!isMutable
!Target
)
6727 alias unwrap
= .unwrap
!(Unqual
!Target
);
6736 @property int height();
6740 @property int height();
6744 int quack() { return 1; }
6745 @property int height() { return 10; }
6749 int quack() { return 2; }
6750 @property int height() { return 20; }
6753 Duck d1
= new Duck();
6754 Human h1
= new Human();
6756 interface Refleshable
6761 // does not have structural conformance
6762 static assert(!__traits(compiles
, d1
.wrap
!Refleshable
));
6763 static assert(!__traits(compiles
, h1
.wrap
!Refleshable
));
6766 Quack qd
= d1
.wrap
!Quack
;
6768 assert(qd
.quack() == 1); // calls Duck.quack
6770 Duck d2
= qd
.unwrap
!Duck
;
6773 // structural upcast
6774 Quack qh
= h1
.wrap
!Quack
;
6775 assert(qh
.quack() == 2); // calls Human.quack
6776 // structural downcast
6777 Human h2
= qh
.unwrap
!Human
;
6780 // structural upcast (two steps)
6781 Quack qx
= h1
.wrap
!Quack
; // Human -> Quack
6782 Flyer fx
= qx
.wrap
!Flyer
; // Quack -> Flyer
6783 assert(fx
.height
== 20); // calls Human.height
6784 // structural downcast (two steps)
6785 Quack qy
= fx
.unwrap
!Quack
; // Flyer -> Quack
6786 Human hy
= qy
.unwrap
!Human
; // Quack -> Human
6788 // structural downcast (one step)
6789 Human hz
= fx
.unwrap
!Human
; // Flyer -> Human
6796 import std
.traits
: FunctionAttribute
, functionAttributes
;
6797 interface A
{ int run(); }
6798 interface B
{ int stop(); @property int status(); }
6801 int run() { return 1; }
6802 int stop() { return 2; }
6803 @property int status() { return 3; }
6807 auto ab
= x
.wrap
!(A
, B
);
6810 assert(a
.run() == 1);
6811 assert(b
.stop() == 2);
6812 assert(b
.status
== 3);
6813 static assert(functionAttributes
!(typeof(ab
).status
) & FunctionAttribute
.property
);
6816 // Internal class to support dynamic cross-casting
6817 private interface Structural
6819 inout(Object
) _wrap_getSource() inout @safe pure nothrow;
6826 int draw() { return 1; }
6827 int draw(int v
) { return v
; }
6829 int draw() const { return 2; }
6830 int draw() shared { return 3; }
6831 int draw() shared const { return 4; }
6832 int draw() immutable { return 5; }
6839 int draw() shared const;
6840 int draw() immutable;
6848 auto sa
= new shared A();
6849 auto ia
= new immutable A();
6851 Drawable md
= ma
.wrap
!Drawable
;
6852 const Drawable cd
= ma
.wrap
!Drawable
;
6853 shared Drawable sd
= sa
.wrap
!Drawable
;
6854 shared const Drawable scd
= sa
.wrap
!Drawable
;
6855 immutable Drawable id
= ia
.wrap
!Drawable
;
6856 assert( md
.draw() == 1);
6857 assert( cd
.draw() == 2);
6858 assert( sd
.draw() == 3);
6859 assert(scd
.draw() == 4);
6860 assert( id
.draw() == 5);
6863 Drawable2 d
= ma
.wrap
!Drawable2
;
6864 static assert(!__traits(compiles
, d
.draw()));
6865 assert(d
.draw(10) == 10);
6869 // https://issues.dlang.org/show_bug.cgi?id=10377
6872 import std
.range
, std
.algorithm
;
6874 interface MyInputRange(T
)
6876 @property T
front();
6878 @property bool empty();
6881 //auto o = iota(0,10,1).inputRangeObject();
6882 //pragma(msg, __traits(allMembers, typeof(o)));
6883 auto r
= iota(0,10,1).inputRangeObject().wrap
!(MyInputRange
!int)();
6884 assert(equal(r
, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6887 // https://issues.dlang.org/show_bug.cgi?id=10536
6896 int foo() { return 1; }
6897 @disable void opCast(T
, this X
)(); // !
6900 Interface i
= new Pluggable().wrap
!Interface
;
6901 assert(i
.foo() == 1);
6905 // Enhancement 10538
6913 int opDispatch(string name
, A
...)(A args
) { return 100; }
6916 Interface i
= wrap
!Interface(new Pluggable());
6917 assert(i
.foo() == 100);
6918 assert(i
.bar(10) == 100);
6921 // https://issues.dlang.org/show_bug.cgi?id=12064
6927 final int nvi1(){return foo();}
6933 final int nvi2(){return bar();}
6938 int foo() { return 42;}
6939 int bar() { return 12064;}
6942 auto baz
= new Baz();
6943 auto foobar
= baz
.wrap
!(I
, J
)();
6944 assert(foobar
.nvi1
== 42);
6945 assert(foobar
.nvi2
== 12064);
6948 // Make a tuple of non-static function symbols
6949 package template GetOverloadedMethods(T
)
6951 import std
.meta
: Filter
;
6953 alias allMembers
= __traits(allMembers
, T
);
6954 template follows(size_t i
= 0)
6956 static if (i
>= allMembers
.length
)
6958 alias follows
= AliasSeq
!();
6960 else static if (!__traits(compiles
, mixin("T."~allMembers
[i
])))
6962 alias follows
= follows
!(i
+ 1);
6966 enum name
= allMembers
[i
];
6968 template isMethod(alias f
)
6970 static if (is(typeof(&f
) F
== F
*) && is(F
== function))
6971 enum isMethod
= !__traits(isStaticFunction
, f
);
6973 enum isMethod
= false;
6975 alias follows
= AliasSeq
!(
6976 Filter
!(isMethod
, __traits(getOverloads
, T
, name
)),
6980 alias GetOverloadedMethods
= follows
!();
6982 // find a function from Fs that has same identifier and covariant type with f
6983 private template findCovariantFunction(alias finfo
, Source
, Fs
...)
6985 template check(size_t i
= 0)
6987 static if (i
>= Fs
.length
)
6988 enum ptrdiff_t check
= -1;
6991 enum ptrdiff_t check
=
6992 (finfo
.name
== __traits(identifier
, Fs
[i
])) &&
6993 isCovariantWith
!(FunctionTypeOf
!(Fs
[i
]), finfo
.type
)
6994 ? i
: check
!(i
+ 1);
6998 static if (x
== -1 && is(typeof(Source
.opDispatch
)))
7000 alias Params
= Parameters
!(finfo
.type
);
7001 enum ptrdiff_t findCovariantFunction
=
7002 is(typeof(( Source
).init
.opDispatch
!(finfo
.name
)(Params
.init
))) ||
7003 is(typeof(( const Source
).init
.opDispatch
!(finfo
.name
)(Params
.init
))) ||
7004 is(typeof(( immutable Source
).init
.opDispatch
!(finfo
.name
)(Params
.init
))) ||
7005 is(typeof(( shared Source
).init
.opDispatch
!(finfo
.name
)(Params
.init
))) ||
7006 is(typeof((shared const Source
).init
.opDispatch
!(finfo
.name
)(Params
.init
)))
7007 ? ptrdiff_t
.max
: -1;
7010 enum ptrdiff_t findCovariantFunction
= x
;
7013 private enum TypeModifier
7015 mutable
= 0, // type is mutable
7016 const_
= 1, // type is const
7017 immutable_
= 2, // type is immutable
7018 shared_
= 4, // type is shared
7019 inout_
= 8, // type is wild
7021 private template TypeMod(T
)
7023 static if (is(T
== immutable))
7025 enum mod1
= TypeModifier
.immutable_
;
7030 enum mod1
= is(T
== shared) ? TypeModifier
.shared_
: 0;
7031 static if (is(T
== const))
7032 enum mod2
= TypeModifier
.const_
;
7033 else static if (is(T
== inout))
7034 enum mod2
= TypeModifier
.inout_
;
7036 enum mod2
= TypeModifier
.mutable
;
7038 enum TypeMod
= cast(TypeModifier
)(mod1 | mod2
);
7043 template UnittestFuncInfo(alias f
)
7045 enum name
= __traits(identifier
, f
);
7046 alias type
= FunctionTypeOf
!f
;
7051 int draw() { return 1; }
7052 @property int value() { return 2; }
7053 final int run() { return 3; }
7055 alias methods
= GetOverloadedMethods
!A
;
7058 alias @property int F2();
7060 alias nothrow @trusted uint F4();
7061 alias int F5(Object
);
7062 alias bool F6(Object
);
7063 static assert(methods
.length
== 3 + 4);
7064 static assert(__traits(identifier
, methods
[0]) == "draw" && is(typeof(&methods
[0]) == F1
*));
7065 static assert(__traits(identifier
, methods
[1]) == "value" && is(typeof(&methods
[1]) == F2
*));
7066 static assert(__traits(identifier
, methods
[2]) == "run" && is(typeof(&methods
[2]) == F1
*));
7069 @property int value();
7072 static assert(findCovariantFunction
!(UnittestFuncInfo
!draw
, A
, methods
) == 0);
7073 static assert(findCovariantFunction
!(UnittestFuncInfo
!value
, A
, methods
) == 1);
7074 static assert(findCovariantFunction
!(UnittestFuncInfo
!opEquals
, A
, methods
) == -1);
7075 static assert(findCovariantFunction
!(UnittestFuncInfo
!nomatch
, A
, methods
) == -1);
7077 // considering opDispatch
7080 void opDispatch(string name
, A
...)(A
) {}
7082 alias methodsB
= GetOverloadedMethods
!B
;
7083 static assert(findCovariantFunction
!(UnittestFuncInfo
!draw
, B
, methodsB
) == ptrdiff_t
.max
);
7084 static assert(findCovariantFunction
!(UnittestFuncInfo
!value
, B
, methodsB
) == ptrdiff_t
.max
);
7085 static assert(findCovariantFunction
!(UnittestFuncInfo
!opEquals
, B
, methodsB
) == ptrdiff_t
.max
);
7086 static assert(findCovariantFunction
!(UnittestFuncInfo
!nomatch
, B
, methodsB
) == ptrdiff_t
.max
);
7089 package template DerivedFunctionType(T
...)
7091 static if (!T
.length
)
7093 alias DerivedFunctionType
= void;
7095 else static if (T
.length
== 1)
7097 static if (is(T
[0] == function))
7099 alias DerivedFunctionType
= T
[0];
7103 alias DerivedFunctionType
= void;
7106 else static if (is(T
[0] P0
== function) && is(T
[1] P1
== function))
7108 alias FA
= FunctionAttribute
;
7110 alias F0
= T
[0], R0
= ReturnType
!F0
, PSTC0
= ParameterStorageClassTuple
!F0
;
7111 alias F1
= T
[1], R1
= ReturnType
!F1
, PSTC1
= ParameterStorageClassTuple
!F1
;
7112 enum FA0
= functionAttributes
!F0
;
7113 enum FA1
= functionAttributes
!F1
;
7115 template CheckParams(size_t i
= 0)
7117 static if (i
>= P0
.length
)
7118 enum CheckParams
= true;
7121 enum CheckParams
= (is(P0
[i
] == P1
[i
]) && PSTC0
[i
] == PSTC1
[i
]) &&
7122 CheckParams
!(i
+ 1);
7125 static if (R0
.sizeof
== R1
.sizeof
&& !is(CommonType
!(R0
, R1
) == void) &&
7126 P0
.length
== P1
.length
&& CheckParams
!() && TypeMod
!F0
== TypeMod
!F1
&&
7127 variadicFunctionStyle
!F0
== variadicFunctionStyle
!F1
&&
7128 functionLinkage
!F0
== functionLinkage
!F1
&&
7129 ((FA0 ^ FA1
) & (FA
.ref_ | FA
.property
)) == 0)
7131 alias R
= Select
!(is(R0
: R1
), R0
, R1
);
7132 alias FX
= FunctionTypeOf
!(R
function(P0
));
7133 // @system is default
7134 alias FY
= SetFunctionAttributes
!(FX
, functionLinkage
!F0
, (FA0 | FA1
) & ~FA
.system
);
7135 alias DerivedFunctionType
= DerivedFunctionType
!(FY
, T
[2 .. $]);
7138 alias DerivedFunctionType
= void;
7141 alias DerivedFunctionType
= void;
7145 // attribute covariance
7147 static assert(is(DerivedFunctionType
!(F1
, F1
) == F1
));
7148 alias int F2() pure nothrow;
7149 static assert(is(DerivedFunctionType
!(F1
, F2
) == F2
));
7150 alias int F3() @safe;
7151 alias int F23() @safe pure nothrow;
7152 static assert(is(DerivedFunctionType
!(F2
, F3
) == F23
));
7154 // return type covariance
7156 static assert(is(DerivedFunctionType
!(F1
, F4
) == void));
7161 static assert(is(DerivedFunctionType
!(F5
, F6
) == F6
));
7162 alias typeof(null) F7();
7165 static assert(is(DerivedFunctionType
!(F5
, F7
) == F7
));
7166 static assert(is(DerivedFunctionType
!(F7
, F8
) == void));
7167 static assert(is(DerivedFunctionType
!(F7
, F9
) == F7
));
7169 // variadic type equality
7171 alias int F11(int...);
7172 alias int F12(int, ...);
7173 static assert(is(DerivedFunctionType
!(F10
, F11
) == void));
7174 static assert(is(DerivedFunctionType
!(F10
, F12
) == void));
7175 static assert(is(DerivedFunctionType
!(F11
, F12
) == void));
7178 alias extern(C
) int F13(int);
7179 alias extern(D
) int F14(int);
7180 alias extern(Windows
) int F15(int);
7181 static assert(is(DerivedFunctionType
!(F13
, F14
) == void));
7182 static assert(is(DerivedFunctionType
!(F13
, F15
) == void));
7183 static assert(is(DerivedFunctionType
!(F14
, F15
) == void));
7185 // ref & @property equality
7187 alias ref int F17(int);
7188 alias @property int F18(int);
7189 static assert(is(DerivedFunctionType
!(F16
, F17
) == void));
7190 static assert(is(DerivedFunctionType
!(F16
, F18
) == void));
7191 static assert(is(DerivedFunctionType
!(F17
, F18
) == void));
7194 package template Bind(alias Template
, args1
...)
7196 alias Bind(args2
...) = Template
!(args1
, args2
);
7201 Options regarding auto-initialization of a `SafeRefCounted` object (see
7202 the definition of `SafeRefCounted` below).
7204 enum RefCountedAutoInitialize
7206 /// Do not auto-initialize the object
7208 /// Auto-initialize the object
7215 import core
.exception
: AssertError
;
7216 import std
.exception
: assertThrown
;
7223 SafeRefCounted
!(Foo
, RefCountedAutoInitialize
.yes
) rcAuto
;
7224 SafeRefCounted
!(Foo
, RefCountedAutoInitialize
.no
) rcNoAuto
;
7226 assert(rcAuto
.refCountedPayload
.a
== 42);
7228 assertThrown
!AssertError(rcNoAuto
.refCountedPayload
);
7229 rcNoAuto
.refCountedStore
.ensureInitialized
;
7230 assert(rcNoAuto
.refCountedPayload
.a
== 42);
7233 // Same the above but for old RefCounted and not documented
7236 import core
.exception
: AssertError
;
7237 import std
.exception
: assertThrown
;
7244 RefCounted
!(Foo
, RefCountedAutoInitialize
.yes
) rcAuto
;
7245 RefCounted
!(Foo
, RefCountedAutoInitialize
.no
) rcNoAuto
;
7247 assert(rcAuto
.refCountedPayload
.a
== 42);
7249 assertThrown
!AssertError(rcNoAuto
.refCountedPayload
);
7250 rcNoAuto
.refCountedStore
.ensureInitialized
;
7251 assert(rcNoAuto
.refCountedPayload
.a
== 42);
7255 Defines a reference-counted object containing a `T` value as
7258 An instance of `SafeRefCounted` is a reference to a structure,
7259 which is referred to as the $(I store), or $(I storage implementation
7260 struct) in this documentation. The store contains a reference count
7261 and the `T` payload. `SafeRefCounted` uses `malloc` to allocate
7262 the store. As instances of `SafeRefCounted` are copied or go out of
7263 scope, they will automatically increment or decrement the reference
7264 count. When the reference count goes down to zero, `SafeRefCounted`
7265 will call `destroy` against the payload and call `free` to
7266 deallocate the store. If the `T` payload contains any references
7267 to GC-allocated memory, then `SafeRefCounted` will add it to the GC memory
7268 that is scanned for pointers, and remove it from GC scanning before
7269 `free` is called on the store.
7271 One important consequence of `destroy` is that it will call the
7272 destructor of the `T` payload. GC-managed references are not
7273 guaranteed to be valid during a destructor call, but other members of
7274 `T`, such as file handles or pointers to `malloc` memory, will
7275 still be valid during the destructor call. This allows the `T` to
7276 deallocate or clean up any non-GC resources immediately after the
7277 reference count has reached zero.
7279 Without -preview=dip1000, `SafeRefCounted` is unsafe and should be
7280 used with care. No references to the payload should be escaped outside
7281 the `SafeRefCounted` object.
7283 With -preview=dip1000, `SafeRefCounted` is safe if it's payload is accessed only
7284 with the $(LREF borrow) function. Scope semantics can also prevent accidental
7285 escaping of `refCountedPayload`, but it's still up to the user to not destroy
7286 the last counted reference while the payload is in use. Due to that,
7287 `refCountedPayload` remains accessible only in `@system` code.
7289 The `autoInit` option makes the object ensure the store is
7290 automatically initialized. Leaving $(D autoInit ==
7291 RefCountedAutoInitialize.yes) (the default option) is convenient but
7292 has the cost of a test whenever the payload is accessed. If $(D
7293 autoInit == RefCountedAutoInitialize.no), user code must call either
7294 `refCountedStore.isInitialized` or `refCountedStore.ensureInitialized`
7295 before attempting to access the payload. Not doing so results in null
7296 pointer dereference.
7298 If `T.this()` is annotated with `@disable` then `autoInit` must be
7299 `RefCountedAutoInitialize.no` in order to compile.
7304 struct SafeRefCounted(T
, RefCountedAutoInitialize autoInit
=
7305 RefCountedAutoInitialize
.yes
)
7306 if (!is(T
== class) && !(is(T
== interface)))
7310 private enum enableGCScan
= false;
7314 private enum enableGCScan
= hasIndirections
!T
;
7317 extern(C
) private pure nothrow @nogc static
7319 pragma(mangle
, "free") void pureFree( void *ptr
);
7320 static if (enableGCScan
)
7321 import core
.memory
: GC
;
7324 pragma(inline
, true) private void checkInit()()
7325 if (autoInit
== RefCountedAutoInitialize
.yes
)
7327 _refCounted
.ensureInitialized();
7330 pragma(inline
, true) private void checkInit()() inout
7331 if (autoInit
== RefCountedAutoInitialize
.no
)
7333 assert(_refCounted
.isInitialized
,
7334 "Attempted to use an uninitialized payload.");
7337 /// `SafeRefCounted` storage implementation.
7338 struct RefCountedStore
7346 private Impl
* _store
;
7348 private void initialize(A
...)(auto ref A args
)
7350 import core
.lifetime
: emplace
, forward
;
7353 version (D_Exceptions
) scope(failure
) () @trusted { deallocateStore(); }();
7354 emplace(&_store
._payload
, forward
!args
);
7358 private void move(ref T source
) nothrow pure
7360 import std
.algorithm
.mutation
: moveEmplace
;
7363 () @trusted { moveEmplace(source
, _store
._payload
); }();
7367 // 'nothrow': can only generate an Error
7368 private void allocateStore() nothrow pure
7370 static if (enableGCScan
)
7372 import std
.internal
.memory
: enforceCalloc
;
7373 auto ptr
= enforceCalloc(1, Impl
.sizeof
);
7374 _store
= () @trusted { return cast(Impl
*) ptr
; }();
7375 () @trusted { GC
.addRange(&_store
._payload
, T
.sizeof
); }();
7379 import std
.internal
.memory
: enforceMalloc
;
7380 auto ptr
= enforceMalloc(Impl
.sizeof
);
7381 _store
= () @trusted { return cast(Impl
*) ptr
; }();
7385 private void deallocateStore() nothrow pure
7387 static if (enableGCScan
)
7389 GC
.removeRange(&this._store
._payload
);
7396 Returns `true` if and only if the underlying store has been
7397 allocated and initialized.
7399 @property nothrow @safe pure @nogc
7400 bool isInitialized() const
7402 return _store
!is null;
7406 Returns underlying reference count if it is allocated and initialized
7407 (a positive integer), and `0` otherwise.
7409 @property nothrow @safe pure @nogc
7410 size_t
refCount() const
7412 return isInitialized ? _store
._count
: 0;
7416 Makes sure the payload was properly initialized. Such a
7417 call is typically inserted before using the payload.
7419 This function is unavailable if `T.this()` is annotated with
7423 void ensureInitialized()()
7425 // By checking for `@disable this()` and failing early we can
7426 // produce a clearer error message.
7427 static assert(__traits(compiles
, { static T t
; }),
7428 "Cannot automatically initialize `" ~ fullyQualifiedName
!T
~
7429 "` because `" ~ fullyQualifiedName
!T
~
7430 ".this()` is annotated with `@disable`.");
7431 if (!isInitialized
) initialize();
7435 RefCountedStore _refCounted
;
7437 /// Returns storage implementation struct.
7438 @property nothrow @safe
7439 ref inout(RefCountedStore
) refCountedStore() inout
7445 Constructor that initializes the payload.
7447 Postcondition: `refCountedStore.isInitialized`
7449 this(A
...)(auto ref A args
) if (A
.length
> 0)
7452 assert(refCountedStore
.isInitialized
);
7456 import core
.lifetime
: forward
;
7457 _refCounted
.initialize(forward
!args
);
7461 this(return scope T val
)
7463 _refCounted
.move(val
);
7467 Constructor that tracks the reference count appropriately. If $(D
7468 !refCountedStore.isInitialized), does nothing.
7470 this(this) @safe pure nothrow @nogc
7472 if (!_refCounted
.isInitialized
) return;
7473 ++_refCounted
._store
._count
;
7477 Destructor that tracks the reference count appropriately. If $(D
7478 !refCountedStore.isInitialized), does nothing. When the reference count goes
7479 down to zero, calls `destroy` agaist the payload and calls `free`
7480 to deallocate the corresponding resource.
7484 import std
.traits
: dip1000Enabled
;
7486 // This prevents the same reference from decrementing the count twice.
7487 scope(exit
) _refCounted
= _refCounted
.init
;
7489 if (!_refCounted
.isInitialized
) return;
7490 assert(_refCounted
._store
._count
> 0);
7491 if (--_refCounted
._store
._count
) return;
7492 // Done, destroy and deallocate
7493 .destroy(_refCounted
._store
._payload
);
7495 static if (dip1000Enabled
)
7497 () @trusted { _refCounted
.deallocateStore(); }();
7499 else _refCounted
.deallocateStore();
7503 Assignment operators.
7505 Note: You may not assign a new payload to an uninitialized SafeRefCounted, if
7506 auto initialization is off. Assigning another counted reference is still okay.
7508 void opAssign(typeof(this) rhs
)
7510 import std
.algorithm
.mutation
: swap
;
7512 swap(_refCounted
._store
, rhs
._refCounted
._store
);
7516 void opAssign(T rhs
)
7518 import std
.algorithm
.mutation
: move
;
7521 move(rhs
, _refCounted
._store
._payload
);
7524 //version to have a single properly ddoc'ed function (w/ correct sig)
7528 Returns a reference to the payload. If (autoInit ==
7529 RefCountedAutoInitialize.yes), calls $(D
7530 refCountedStore.ensureInitialized). Otherwise, just issues $(D
7531 assert(refCountedStore.isInitialized)). Used with $(D alias
7532 refCountedPayload this;), so callers can just use the `SafeRefCounted`
7535 $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
7536 So if $(D autoInit == RefCountedAutoInitialize.no)
7537 or called for a constant or immutable object, then
7538 `refCountedPayload` will also be qualified as nothrow
7539 (but will still assert if not initialized).
7542 ref T
refCountedPayload() return;
7545 @property nothrow @system pure @nogc
7546 ref inout(T
) refCountedPayload() inout return;
7550 static if (autoInit
== RefCountedAutoInitialize
.yes
)
7552 //Can't use inout here because of potential mutation
7554 ref T
refCountedPayload() return
7557 return _refCounted
._store
._payload
;
7562 @property nothrow @system pure @nogc
7563 ref inout(T
) refCountedPayload() inout return
7566 return _refCounted
._store
._payload
;
7572 Returns a reference to the payload. If (autoInit ==
7573 RefCountedAutoInitialize.yes), calls $(D
7574 refCountedStore.ensureInitialized). Otherwise, just issues $(D
7575 assert(refCountedStore.isInitialized)).
7577 alias refCountedPayload
this;
7579 static if (is(T
== struct) && !is(typeof((ref T t
) => t
.toString())))
7581 string
toString(this This
)()
7583 import std
.conv
: to
;
7585 static if (autoInit
)
7586 return to
!string(refCountedPayload
);
7589 if (!_refCounted
.isInitialized
)
7590 return This
.stringof
~ "(RefCountedStore(null))";
7592 return to
!string(_refCounted
._store
._payload
);
7599 @betterC pure @system nothrow @nogc unittest
7601 // A pair of an `int` and a `size_t` - the latter being the
7602 // reference count - will be dynamically allocated
7603 auto rc1
= SafeRefCounted
!int(5);
7605 // No more allocation, add just one extra reference count
7607 // Reference semantics
7610 // the pair will be freed when rc1 and rc2 go out of scope
7613 // This test can't be betterC because the test extractor won't see the private
7614 // `initialize` method accessed here
7615 pure @safe nothrow @nogc unittest
7617 auto rc1
= SafeRefCounted
!(int, RefCountedAutoInitialize
.no
)(5);
7618 rc1
._refCounted
.initialize();
7621 pure @system unittest
7623 foreach (MyRefCounted
; AliasSeq
!(SafeRefCounted
, RefCounted
))
7625 MyRefCounted
!int* p
;
7626 auto rc1
= MyRefCounted
!int(5);
7629 assert(rc1
._refCounted
._store
._count
== 1);
7632 assert(rc1
._refCounted
._store
._count
== 2);
7633 // Reference semantics
7637 assert(rc2
._refCounted
._store
._count
== 2);
7639 assert(rc1
._refCounted
._store
._count
== 2);
7641 // Artificially end scope of rc1 by calling ~this() explicitly
7643 assert(p
._refCounted
._store
== null);
7645 // [Safe]RefCounted as a member
7651 x
._refCounted
.initialize(y
);
7655 auto another
= this;
7661 assert(a
.x
._refCounted
._store
._count
== 2,
7662 "https://issues.dlang.org/show_bug.cgi?id=4356 still unfixed");
7666 @betterC pure @safe nothrow @nogc unittest
7668 import std
.algorithm
.mutation
: swap
;
7670 SafeRefCounted
!int p1
, p2
;
7674 // Same as above but for old RefCounted and not @safe
7675 @betterC pure @system nothrow @nogc unittest
7677 import std
.algorithm
.mutation
: swap
;
7679 RefCounted
!int p1
, p2
;
7683 // https://issues.dlang.org/show_bug.cgi?id=6606
7684 @betterC @safe pure nothrow @nogc unittest
7695 alias SRC
= SafeRefCounted
!S
;
7698 // Same as above but for old RefCounted and not @safe
7699 @betterC @system pure nothrow @nogc unittest
7710 alias SRC
= RefCounted
!S
;
7713 // https://issues.dlang.org/show_bug.cgi?id=6436
7714 @betterC @system pure unittest
7716 import std
.meta
: AliasSeq
;
7719 this(int rval
) { assert(rval
== 1); }
7720 this(ref int lval
) { assert(lval
== 3); ++lval
; }
7723 foreach (MyRefCounted
; AliasSeq
!(SafeRefCounted
, RefCounted
))
7725 auto s1
= MyRefCounted
!S(1);
7727 auto s2
= MyRefCounted
!S(lval
);
7732 // gc_addRange coverage
7733 @betterC @safe pure unittest
7735 struct S
{ int* p
; }
7737 auto s
= SafeRefCounted
!S(null);
7740 // Same as above but for old RefCounted and not @safe
7741 @betterC @system pure unittest
7743 struct S
{ int* p
; }
7745 auto s
= RefCounted
!S(null);
7748 @betterC @system pure nothrow @nogc unittest
7750 import std
.meta
: AliasSeq
;
7751 foreach (MyRefCounted
; AliasSeq
!(SafeRefCounted
, RefCounted
))
7754 a
= 5; //This should not assert
7758 b
= a
; //This should not assert either
7761 MyRefCounted
!(int*) c
;
7765 // https://issues.dlang.org/show_bug.cgi?id=21638
7766 @betterC @system pure nothrow @nogc unittest
7768 import std
.meta
: AliasSeq
;
7769 static struct NoDefaultCtor
7772 this(int x
) @nogc nothrow pure { this.x
= x
; }
7776 foreach (MyRefCounted
; AliasSeq
!(SafeRefCounted
, RefCounted
))
7778 auto rc
= MyRefCounted
!(NoDefaultCtor
, RefCountedAutoInitialize
.no
)(5);
7783 // https://issues.dlang.org/show_bug.cgi?id=20502
7786 alias Types
= AliasSeq
!(SafeRefCounted
, RefCounted
);
7787 alias funcs
= AliasSeq
!(safeRefCounted
, refCounted
);
7788 static foreach (aliasI
; 0 .. 2)
7790 alias MyRefCounted
= Types
[aliasI
];
7791 alias myRefCounted
= funcs
[aliasI
];
7792 import std
.conv
: to
;
7794 // Check that string conversion is transparent for refcounted
7795 // structs that do not have either toString or alias this.
7796 static struct A
{ Object a
; }
7797 auto a
= A(new Object());
7798 auto r
= myRefCounted(a
);
7799 assert(to
!string(r
) == to
!string(a
));
7800 assert(to
!string(cast(const) r
) == to
!string(cast(const) a
));
7801 // Check that string conversion is still transparent for refcounted
7802 // structs that have alias this.
7803 static struct B
{ int b
; alias b
this; }
7804 static struct C
{ B b
; alias b
this; }
7805 assert(to
!string(myRefCounted(C(B(123)))) == to
!string(C(B(123))));
7806 // https://issues.dlang.org/show_bug.cgi?id=22093
7807 // Check that uninitialized refcounted structs that previously could be
7808 // converted to strings still can be.
7809 alias R
= typeof(r
);
7811 cast(void) (((const ref R a
) => to
!string(a
))(r2
));
7812 cast(void) to
!string(MyRefCounted
!(A
, RefCountedAutoInitialize
.no
).init
);
7816 // We tried to make `refCountedPayload` `@safe` in
7817 // https://github.com/dlang/phobos/pull/8368 . It proved impossible, but it may
7818 // be possible in the future. This test checks for false `@safe` issues we
7827 int[] getArr1 (scope Container local
)
7829 // allowed because the argument is inferred as return scope.
7833 int[] getArr2 (scope Container local
)
7835 SafeRefCounted
!Container rc
= local
;
7836 // Escapes a reference to expired reference counted struct
7838 return rc
.refCountedPayload().data
;
7841 int destroyFirstAndUseLater()
7843 auto rc
= SafeRefCounted
!int(123);
7844 int* ptr
= &rc
.refCountedPayload();
7849 // This is here mainly to test that safety gets inferred correctly for the
7851 static assert(isSafe
!getArr1
);
7852 // https://github.com/dlang/phobos/pull/8101#issuecomment-843017282
7853 // This got apparently fixed automatically by compiler updates.
7854 static assert(!isSafe
!getArr2
);
7855 // As of writing, this is the issue that is still preventing payload access
7856 // from being `@safe`
7857 static assert(!isSafe
!destroyFirstAndUseLater
);
7861 Borrows the payload of $(LREF SafeRefCounted) for use in `fun`. Inferred as `@safe`
7862 if `fun` is `@safe` and does not escape a reference to the payload.
7863 The reference count will be incremented for the duration of the operation,
7864 so destroying the last reference will not leave dangling references in
7868 fun = A callable accepting the payload either by value or by reference.
7869 refCount = The counted reference to the payload.
7871 The return value of `fun`, if any. `ref` in the return value will be
7874 For yet unknown reason, code that uses this function with UFCS syntax
7875 will not be inferred as `@safe`. It will still compile if the code is
7876 explicitly marked `@safe` and nothing in `fun` prevents that.
7878 template borrow(alias fun
)
7880 import std
.functional
: unaryFun
;
7882 auto ref borrow(RC
)(RC refCount
) if
7884 isInstanceOf
!(SafeRefCounted
, RC
)
7885 && is(typeof(unaryFun
!fun(refCount
.refCountedPayload
)))
7888 refCount
.checkInit();
7890 // If `fun` escapes a reference to the payload, it will be inferred
7891 // as unsafe due to the scope storage class here.
7892 scope plPtr
= &refCount
._refCounted
._store
._payload
;
7893 return unaryFun
!fun(*plPtr
);
7895 // We destroy our copy of the reference here, automatically destroying
7896 // the payload if `fun` destroyed the last reference outside.
7900 /// This example can be marked `@safe` with `-preview=dip1000`.
7901 @safe pure nothrow unittest
7903 auto rcInt
= safeRefCounted(5);
7904 assert(rcInt
.borrow
!(theInt
=> theInt
) == 5);
7905 auto sameInt
= rcInt
;
7906 assert(sameInt
.borrow
!"a" == 5);
7908 // using `ref` in the function
7909 auto arr
= [0, 1, 2, 3, 4, 5, 6];
7910 sameInt
.borrow
!(ref (x
) => arr
[x
]) = 10;
7911 assert(arr
== [0, 1, 2, 3, 4, 10, 6]);
7913 // modifying the payload via an alias
7914 sameInt
.borrow
!"a*=2";
7915 assert(rcInt
.borrow
!"a" == 10);
7918 // Some memory safety penetration testing.
7922 int torpedoesFired
= 0;
7923 struct Destroyer
{ ~this() @safe { torpedoesFired
++; } }
7925 alias RcInt
= typeof(safeRefCounted(0));
7926 auto standardUsage(RcInt arg
)
7928 return borrow
!((ref x
) => x
)(arg
);
7930 ref harmlessRefReturn(RcInt arg
)
7932 return borrow
!(ref (ref x
) => *globalPtr
= x
)(arg
);
7934 ref problematicRefReturn(RcInt arg
)
7936 return borrow
!(ref (ref x
) => x
)(arg
);
7938 auto sideChannelEscape(RcInt arg
)
7940 return borrow
!((ref x
)
7946 auto destroyDuringApply()
7948 auto rc
= safeRefCounted(Destroyer());
7949 return borrow
!((ref x
)
7951 // Destroys the last reference to the payload, decrementing it's
7954 // Destroy again! rc should be set to it's init value so that this
7955 // won't decrement the reference count of the original payload.
7957 // The internal reference count increment done for duration of
7958 // `apply` should make sure that the payload destructor is not yet
7959 // run, and this value thus not incremented.
7960 return torpedoesFired
;
7964 // First, let's verify the dangerous functions really do what they are
7966 auto testRc
= safeRefCounted(42);
7967 assert(sideChannelEscape(testRc
) == 42);
7968 assert(&problematicRefReturn(testRc
) == globalPtr
);
7970 // Now, are the @safe attributes inferred correctly?
7971 assert(isSafe
!standardUsage
);
7972 assert(isSafe
!harmlessRefReturn
);
7973 assert(!isSafe
!problematicRefReturn
);
7974 assert(!isSafe
!sideChannelEscape
);
7975 assert(isSafe
!destroyDuringApply
);
7977 // Finally, we test protection against early destruction during `apply`.
7978 auto torpedoesUpToReturn
= destroyDuringApply();
7979 assert(torpedoesFired
== torpedoesUpToReturn
+ 1);
7983 * Initializes a `SafeRefCounted` with `val`. The template parameter
7984 * `T` of `SafeRefCounted` is inferred from `val`.
7985 * This function can be used to move non-copyable values to the heap.
7986 * It also disables the `autoInit` option of `SafeRefCounted`.
7989 * val = The value to be reference counted
7991 * An initialized `SafeRefCounted` containing `val`.
7993 * $(LREF refCounted)
7994 * $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared)
7996 SafeRefCounted
!(T
, RefCountedAutoInitialize
.no
) safeRefCounted(T
)(T val
)
7999 res
._refCounted
.move(val
);
8008 static size_t nDestroyed
;
8010 @disable this(this); // not copyable
8011 ~this() { name
= null; ++nDestroyed
; }
8014 auto file
= File("name");
8015 assert(file
.name
== "name");
8016 // file cannot be copied and has unique ownership
8017 static assert(!__traits(compiles
, {auto file2
= file
;}));
8019 assert(File
.nDestroyed
== 0);
8021 // make the file ref counted to share ownership
8023 // We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted.
8024 // This allows us to see (after the scope) what happens after all handles have been destroyed.
8026 // We move the content of `file` to a separate (and heap-allocated) `File` object,
8027 // managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles").
8029 // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`);
8030 // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`).
8031 // It appears that writing `name = null;` in the destructor is redundant,
8032 // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator),
8033 // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor.
8034 import std
.algorithm
.mutation
: move
;
8035 auto rcFile
= safeRefCounted(move(file
));
8036 assert(rcFile
.name
== "name");
8037 assert(File
.nDestroyed
== 1);
8038 assert(file
.name
== null);
8040 // We create another `SafeRefCounted!File` handle to the same separate `File` object.
8041 // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified).
8042 auto rcFile2
= rcFile
;
8043 assert(rcFile
.refCountedStore
.refCount
== 2);
8044 assert(File
.nDestroyed
== 1);
8046 // The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed
8047 // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`)
8048 // (=> `File.nDestroyed` is incremented again, from 1 to 2):
8049 assert(File
.nDestroyed
== 2);
8053 Creates a proxy for the value `a` that will forward all operations
8054 while disabling implicit conversions. The aliased item `a` must be
8055 an $(B lvalue). This is useful for creating a new type from the
8056 "base" type (though this is $(B not) a subtype-supertype
8057 relationship; the new type is not related to the old type in any way,
8060 The new type supports all operations that the underlying type does,
8061 including all operators such as `+`, `--`, `<`, `[]`, etc.
8064 a = The value to act as a proxy for all operations. It must
8067 mixin template Proxy(alias a
)
8069 private alias ValueType
= typeof({ return a
; }());
8071 /* Determine if 'T.a' can referenced via a const(T).
8072 * Use T* as the parameter because 'scope' inference needs a fully
8073 * analyzed T, which doesn't work when accessibleFrom() is used in a
8074 * 'static if' in the definition of Proxy or T.
8076 private enum bool accessibleFrom(T
) =
8077 is(typeof((T
* self
){ cast(void) mixin("(*self)."~__traits(identifier
, a
)); }));
8079 static if (is(typeof(this) == class))
8081 override bool opEquals(Object o
)
8083 if (auto b
= cast(typeof(this))o
)
8085 return a
== mixin("b."~__traits(identifier
, a
));
8090 bool opEquals(T
)(T b
)
8091 if (is(ValueType
: T
) ||
is(typeof(a
.opEquals(b
))) ||
is(typeof(b
.opEquals(a
))))
8093 static if (is(typeof(a
.opEquals(b
))))
8094 return a
.opEquals(b
);
8095 else static if (is(typeof(b
.opEquals(a
))))
8096 return b
.opEquals(a
);
8101 override int opCmp(Object o
)
8103 if (auto b
= cast(typeof(this))o
)
8105 return a
< mixin("b."~__traits(identifier
, a
)) ?
-1
8106 : a
> mixin("b."~__traits(identifier
, a
)) ?
+1 : 0;
8108 static if (is(ValueType
== class))
8111 throw new Exception("Attempt to compare a "~typeid(this).toString
~" and a "~typeid(o
).toString
);
8114 int opCmp(T
)(auto ref const T b
)
8115 if (is(ValueType
: T
) ||
is(typeof(a
.opCmp(b
))) ||
is(typeof(b
.opCmp(a
))))
8117 static if (is(typeof(a
.opCmp(b
))))
8119 else static if (is(typeof(b
.opCmp(a
))))
8122 return a
< b ?
-1 : a
> b ?
+1 : 0;
8125 static if (accessibleFrom
!(const typeof(this)))
8127 override size_t
toHash() const nothrow @safe
8129 static if (__traits(compiles
, .hashOf(a
)))
8132 // Workaround for when .hashOf is not both @safe and nothrow.
8134 static if (is(typeof(&a
) == ValueType
*))
8137 auto v
= a
; // if a is (property) function
8138 // BUG: Improperly casts away `shared`!
8139 return typeid(ValueType
).getHash((() @trusted => cast(const void*) &v
)());
8146 auto ref opEquals(this X
, B
)(auto ref B b
)
8148 static if (is(immutable B
== immutable typeof(this)))
8150 return a
== mixin("b."~__traits(identifier
, a
));
8156 auto ref opCmp(this X
, B
)(auto ref B b
)
8158 static if (is(typeof(a
.opCmp(b
))))
8160 else static if (is(typeof(b
.opCmp(a
))))
8162 else static if (isFloatingPoint
!ValueType || isFloatingPoint
!B
)
8163 return a
< b ?
-1 : a
> b ?
+1 : a
== b ?
0 : float.nan
;
8165 return a
< b ?
-1 : (a
> b
);
8168 static if (accessibleFrom
!(const typeof(this)))
8170 size_t
toHash() const nothrow @safe
8172 static if (__traits(compiles
, .hashOf(a
)))
8175 // Workaround for when .hashOf is not both @safe and nothrow.
8177 static if (is(typeof(&a
) == ValueType
*))
8180 auto v
= a
; // if a is (property) function
8181 // BUG: Improperly casts away `shared`!
8182 return typeid(ValueType
).getHash((() @trusted => cast(const void*) &v
)());
8188 auto ref opCall(this X
, Args
...)(auto ref Args args
) { return a(args
); }
8190 auto ref opCast(T
, this X
)() { return cast(T
) a
; }
8192 auto ref opIndex(this X
, D
...)(auto ref D i
) { return a
[i
]; }
8193 auto ref opSlice(this X
)() { return a
[]; }
8194 auto ref opSlice(this X
, B
, E
)(auto ref B b
, auto ref E e
) { return a
[b
.. e
]; }
8196 auto ref opUnary (string op
, this X
)() { return mixin(op
~"a"); }
8197 auto ref opIndexUnary(string op
, this X
, D
...)(auto ref D i
) { return mixin(op
~"a[i]"); }
8198 auto ref opSliceUnary(string op
, this X
)() { return mixin(op
~"a[]"); }
8199 auto ref opSliceUnary(string op
, this X
, B
, E
)(auto ref B b
, auto ref E e
) { return mixin(op
~"a[b .. e]"); }
8201 auto ref opBinary(string op
, this X
, B
)(auto ref B b
)
8202 if (op
== "in" && is(typeof(a
in b
)) || op
!= "in")
8204 return mixin("a "~op
~" b");
8206 auto ref opBinaryRight(string op
, this X
, B
)(auto ref B b
) { return mixin("b "~op
~" a"); }
8208 static if (!is(typeof(this) == class))
8211 static if (isAssignable
!ValueType
)
8213 auto ref opAssign(this X
)(auto ref typeof(this) v
)
8215 a
= mixin("v."~__traits(identifier
, a
));
8221 @disable void opAssign(this X
)(auto ref typeof(this) v
);
8225 auto ref opAssign (this X
, V
)(auto ref V v
) if (!is(V
== typeof(this))) { return a
= v
; }
8226 auto ref opIndexAssign(this X
, V
, D
...)(auto ref V v
, auto ref D i
) { return a
[i
] = v
; }
8227 auto ref opSliceAssign(this X
, V
)(auto ref V v
) { return a
[] = v
; }
8228 auto ref opSliceAssign(this X
, V
, B
, E
)(auto ref V v
, auto ref B b
, auto ref E e
) { return a
[b
.. e
] = v
; }
8230 auto ref opOpAssign (string op
, this X
, V
)(auto ref V v
)
8232 return mixin("a = a "~op
~" v");
8234 auto ref opIndexOpAssign(string op
, this X
, V
, D
...)(auto ref V v
, auto ref D i
)
8236 return mixin("a[i] " ~op
~"= v");
8238 auto ref opSliceOpAssign(string op
, this X
, V
)(auto ref V v
)
8240 return mixin("a[] " ~op
~"= v");
8242 auto ref opSliceOpAssign(string op
, this X
, V
, B
, E
)(auto ref V v
, auto ref B b
, auto ref E e
)
8244 return mixin("a[b .. e] "~op
~"= v");
8247 template opDispatch(string name
)
8249 static if (is(typeof(__traits(getMember
, a
, name
)) == function))
8251 // non template function
8252 auto ref opDispatch(this X
, Args
...)(auto ref Args args
) { return mixin("a."~name
~"(args)"); }
8254 else static if (is(typeof({ enum x
= mixin("a."~name
); })))
8256 // built-in type field, manifest constant, and static non-mutable field
8257 enum opDispatch
= mixin("a."~name
);
8259 else static if (__traits(isTemplate
, mixin("a."~name
)))
8262 template opDispatch(T
...)
8264 enum targs
= T
.length ?
"!T" : "";
8265 auto ref opDispatch(this X
, Args
...)(auto ref Args args
){ return mixin("a."~name
~targs
~"(args)"); }
8270 // field or property function
8271 @property auto ref opDispatch(this X
)() { return mixin("a."~name
); }
8272 @property auto ref opDispatch(this X
, V
)(auto ref V v
) { return mixin("a."~name
~" = v"); }
8277 import std
.traits
: isArray
;
8279 static if (isArray
!ValueType
)
8281 auto opDollar() const { return a
.length
; }
8283 else static if (is(typeof(a
.opDollar
!0)))
8285 auto ref opDollar(size_t pos
)() { return a
.opDollar
!pos(); }
8287 else static if (is(typeof(a
.opDollar
) == function))
8289 auto ref opDollar() { return a
.opDollar(); }
8291 else static if (is(typeof(a
.opDollar
)))
8293 alias opDollar
= a
.opDollar
;
8305 this(int n
){ value
= n
; }
8310 // Enable operations that original type has.
8313 assert(n
* 2 == 22);
8315 void func(int n
) { }
8317 // Disable implicit conversions to original type.
8322 ///The proxied value must be an $(B lvalue).
8327 //Won't work; the literal '1'
8328 //is an rvalue, not an lvalue
8331 //Okay, n is an lvalue
8335 this(int n
) { this.n
= n
; }
8343 struct NewObjectType
8346 //Ok, obj is an lvalue
8349 this (Object o
) { obj
= o
; }
8352 NewObjectType
not = new Object();
8353 assert(__traits(compiles
, not.toHash()));
8357 There is one exception to the fact that the new type is not related to the
8358 old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member)
8359 functions are usable with the new type; they will be forwarded on to the
8364 import std
.math
.traits
: isInfinity
;
8367 assert(!f
.isInfinity
);
8374 this(float f
) { _
= f
; }
8378 assert(!nf
.isInfinity
);
8387 this(int n
) inout { value
= n
; }
8390 static immutable arr
= [1,2,3];
8393 static foreach (T
; AliasSeq
!(MyInt
, const MyInt
, immutable MyInt
))
8396 static assert(!__traits(compiles
, { int x
= m
; }));
8397 static assert(!__traits(compiles
, { void func(int n
){} func(m
); }));
8403 assert(cast(double) m
== 10.0);
8404 assert(m
+ 10 == 20);
8406 assert(m
* 20 == 200);
8408 assert(10 + m
== 20);
8409 assert(15 - m
== 5);
8410 assert(20 * m
== 200);
8411 assert(50 / m
== 5);
8412 static if (is(T
== MyInt
)) // mutable
8415 assert(m
++ == 11); assert(m
== 12);
8417 assert(m
-- == 11); assert(m
== 10);
8419 m
= 20; assert(m
== 20);
8421 static assert(T
.max
== int.max
);
8422 static assert(T
.min
== int.min
);
8423 static assert(T
.init
== int.init
);
8424 static assert(T
.str == "str");
8425 static assert(T
.arr
== [1,2,3]);
8430 static struct MyArray
8432 private int[] value
;
8434 this(int[] arr
) { value
= arr
; }
8435 this(immutable int[] arr
) immutable { value
= arr
; }
8438 static foreach (T
; AliasSeq
!(MyArray
, const MyArray
, immutable MyArray
))
8440 static if (is(T
== immutable) && !is(typeof({ T a
= [1,2,3,4]; })))
8441 T a
= [1,2,3,4].idup
; // workaround until qualified ctor is properly supported
8444 assert(a
== [1,2,3,4]);
8445 assert(a
!= [5,6,7,8]);
8447 version (LittleEndian
)
8448 assert(cast(ulong[]) a
== [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]);
8450 assert(cast(ulong[]) a
== [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]);
8451 assert(a
~ [10,11] == [1,2,3,4,10,11]);
8453 assert(a
[] == [1,2,3,4]);
8454 assert(a
[2 .. 4] == [3,4]);
8455 static if (is(T
== MyArray
)) // mutable
8458 a
= [5,6,7,8]; assert(a
== [5,6,7,8]);
8459 a
[0] = 0; assert(a
== [0,6,7,8]);
8460 a
[] = 1; assert(a
== [1,1,1,1]);
8461 a
[0 .. 3] = 2; assert(a
== [2,2,2,1]);
8462 a
[0] += 2; assert(a
== [4,2,2,1]);
8463 a
[] *= 2; assert(a
== [8,4,4,2]);
8464 a
[0 .. 2] /= 2; assert(a
== [4,2,4,2]);
8474 @property int val1() const { return field
; }
8475 @property void val1(int n
) { field
= n
; }
8477 @property ref int val2() { return field
; }
8479 int func(int x
, int y
) const { return x
; }
8480 void func1(ref int a
) { a
= 9; }
8482 T
ifti1(T
)(T t
) { return t
; }
8483 void ifti2(Args
...)(Args args
) { }
8484 void ifti3(T
, Args
...)(Args args
) { }
8486 T
opCast(T
)(){ return T
.init
; }
8488 T
tempfunc(T
)() { return T
.init
; }
8494 this(Foo f
) { foo
= f
; }
8497 auto h
= new Hoge(new Foo());
8500 static assert(!__traits(compiles
, { Foo f
= h
; }));
8503 h
.field
= 1; // lhs of assign
8504 n
= h
.field
; // rhs of assign
8505 assert(h
.field
== 1); // lhs of BinExp
8506 assert(1 == h
.field
); // rhs of BinExp
8509 // getter/setter property function
8512 assert(h
.val1
== 4);
8513 assert(4 == h
.val1
);
8516 // ref getter property function
8519 assert(h
.val2
== 8);
8520 assert(8 == h
.val2
);
8524 assert(h
.func(2,4) == 2);
8529 assert(h
.ifti1(4) == 4);
8533 // https://issues.dlang.org/show_bug.cgi?id=5896 test
8534 assert(h
.opCast
!int() == 0);
8535 assert(cast(int) h
== 0);
8536 const ih
= new const Hoge(new Foo());
8537 static assert(!__traits(compiles
, ih
.opCast
!int()));
8538 static assert(!__traits(compiles
, cast(int) ih
));
8540 // template member function
8541 assert(h
.tempfunc
!int() == 0);
8544 @system unittest // about Proxy inside a class
8549 mixin Proxy
!payload
;
8550 this(int i
){ payload
= i
; }
8551 string
opCall(string msg
){ return msg
; }
8552 int pow(int i
){ return payload ^^ i
; }
8558 mixin Proxy
!payload
;
8559 this(int i
){ payload
= new MyClass(i
); }
8565 mixin Proxy
!payload
;
8566 this(int i
){ payload
= i
; }
8570 Object a
= new MyClass(5);
8571 Object b
= new MyClass(5);
8572 Object c
= new MyClass2(5);
8573 Object d
= new MyClass3(5);
8575 assert((cast(MyClass
) a
) == 5);
8576 assert(5 == (cast(MyClass
) b
));
8577 assert(5 == cast(MyClass2
) c
);
8581 // oops! above line is unexpected, isn't it?
8582 // the reason is below.
8583 // MyClass2.opEquals knows MyClass but,
8584 // MyClass.opEquals doesn't know MyClass2.
8585 // so, c.opEquals(a) is true, but a.opEquals(c) is false.
8586 // furthermore, opEquals(T) couldn't be invoked.
8587 assert((cast(MyClass2
) c
) != (cast(MyClass
) a
));
8590 Object e
= new MyClass2(7);
8591 assert(a
< cast(MyClass2
) e
); // OK. and
8592 assert(e
> a
); // OK, but...
8593 // assert(a < e); // RUNTIME ERROR!
8594 // assert((cast(MyClass) a) < e); // RUNTIME ERROR!
8595 assert(3 < cast(MyClass
) a
);
8596 assert((cast(MyClass2
) e
) < 11);
8599 assert((cast(MyClass2
) e
)("hello") == "hello");
8602 assert((cast(MyClass
)(cast(MyClass2
) c
)) == a
);
8603 assert((cast(int)(cast(MyClass2
) c
)) == 5);
8609 mixin Proxy
!payload
;
8610 this(string s
){ payload
= s
; }
8615 mixin Proxy
!payload
;
8616 this(string s
){ payload
= new MyClass4(s
); }
8618 auto f
= new MyClass4("hello");
8619 assert(f
[1] == 'e');
8620 auto g
= new MyClass5("hello");
8621 assert(f
[1] == 'e');
8624 assert(f
[2 .. 4] == "ll");
8627 assert(-(cast(MyClass2
) c
) == -5);
8630 assert((cast(MyClass
) a
) + (cast(MyClass2
) c
) == 10);
8631 assert(5 + cast(MyClass
) a
== 10);
8634 (cast(MyClass2
) c
) = 11;
8635 assert((cast(MyClass2
) c
) == 11);
8636 (cast(MyClass2
) c
) = new MyClass(13);
8637 assert((cast(MyClass2
) c
) == 13);
8640 assert((cast(MyClass2
) c
) += 4);
8641 assert((cast(MyClass2
) c
) == 17);
8644 assert((cast(MyClass2
) c
).pow(2) == 289);
8647 assert(f
[2..$-1] == "ll");
8653 assert(hash
[b
] == 19);
8654 assert(hash
[c
] == 21);
8663 mixin Proxy
!payload
;
8671 @disable void opAssign(typeof(this));
8677 mixin Proxy
!payload
;
8680 static assert(!__traits(compiles
, f
= f
));
8686 mixin Proxy
!payload
;
8688 // override default Proxy behavior
8689 void opAssign(typeof(this) rhs
){}
8695 // https://issues.dlang.org/show_bug.cgi?id=8613
8702 this(string s
) { val
= s
; }
8706 names
[Name("a")] = true;
8707 bool* b
= Name("a") in names
;
8710 // workaround for https://issues.dlang.org/show_bug.cgi?id=19669
8711 private enum isDIP1000
= __traits(compiles
, () @safe {
8716 // excludes struct S; it's 'mixin Proxy!foo' doesn't compile with -dip1000
8717 static if (isDIP1000
) {} else
8720 // https://issues.dlang.org/show_bug.cgi?id=14213
8721 // using function for the payload
8724 int foo() { return 12; }
8728 assert(s
+ 1 == 13);
8729 assert(s
* 2 == 24);
8736 int foo() { return 12; }
8742 // Check all floating point comparisons for both Proxy and Typedef,
8743 // also against int and a Typedef!int, to be as regression-proof
8744 // as possible. https://issues.dlang.org/show_bug.cgi?id=15561
8747 static struct MyFloatImpl
8752 static void allFail(T0
, T1
)(T0 a
, T1 b
)
8760 static foreach (T1
; AliasSeq
!(MyFloatImpl
, Typedef
!float, Typedef
!double,
8761 float, real, Typedef
!int, int))
8763 static foreach (T2
; AliasSeq
!(MyFloatImpl
, Typedef
!float))
8768 static if (isFloatingPoint
!T1 || isFloatingPoint
!(TypedefType
!T1
))
8791 $(B Typedef) allows the creation of a unique type which is
8792 based on an existing type. Unlike the `alias` feature,
8793 $(B Typedef) ensures the two types are not considered as equals.
8797 init = Optional initial value for the new type.
8798 cookie = Optional, used to create multiple unique types which are
8799 based on the same origin type `T`
8801 Note: If a library routine cannot handle the Typedef type,
8802 you can use the `TypedefType` template to extract the
8803 type which the Typedef wraps.
8805 struct Typedef(T
, T init
= T
.init
, string cookie
=null)
8807 private T Typedef_payload
= init
;
8809 // https://issues.dlang.org/show_bug.cgi?id=18415
8810 // prevent default construction if original type does too.
8811 static if ((is(T
== struct) ||
is(T
== union)) && !is(typeof({T t
;})))
8818 Typedef_payload
= init
;
8823 this(tdef
.Typedef_payload
);
8826 // We need to add special overload for cast(Typedef!X) exp,
8827 // thus we can't simply inherit Proxy!Typedef_payload
8828 T2
opCast(T2
: Typedef
!(T
, Unused
), this X
, T
, Unused
...)()
8830 return T2(cast(T
) Typedef_payload
);
8833 auto ref opCast(T2
, this X
)()
8835 return cast(T2
) Typedef_payload
;
8838 mixin Proxy
!Typedef_payload
;
8840 pure nothrow @nogc @safe @property
8842 alias TD
= typeof(this);
8843 static if (isIntegral
!T
)
8845 static TD
min() {return TD(T
.min
);}
8846 static TD
max() {return TD(T
.max
);}
8848 else static if (isFloatingPoint
!T
)
8850 static TD
infinity() {return TD(T
.infinity
);}
8851 static TD
nan() {return TD(T
.nan
);}
8852 static TD
dig() {return TD(T
.dig
);}
8853 static TD
epsilon() {return TD(T
.epsilon
);}
8854 static TD
mant_dig() {return TD(T
.mant_dig
);}
8855 static TD
max_10_exp() {return TD(T
.max_10_exp
);}
8856 static TD
max_exp() {return TD(T
.max_exp
);}
8857 static TD
min_10_exp() {return TD(T
.min_10_exp
);}
8858 static TD
min_exp() {return TD(T
.min_exp
);}
8859 static TD
max() {return TD(T
.max
);}
8860 static TD
min_normal() {return TD(T
.min_normal
);}
8861 TD
re() {return TD(Typedef_payload
.re
);}
8862 TD
im() {return TD(Typedef_payload
.im
);}
8867 * Convert wrapped value to a human readable string
8869 string
toString(this T
)()
8871 import std
.array
: appender
;
8872 auto app
= appender
!string();
8873 auto spec
= singleSpec("%s");
8874 toString(app
, spec
);
8879 void toString(this T
, W
)(ref W writer
, scope const ref FormatSpec
!char fmt
)
8880 if (isOutputRange
!(W
, char))
8882 formatValue(writer
, Typedef_payload
, fmt
);
8888 import std
.conv
: to
;
8891 auto td
= Typedef
!int(i
);
8892 assert(i
.to
!string
== td
.to
!string
);
8899 alias MyInt
= Typedef
!int;
8905 /// custom initialization values
8908 alias MyIntInit
= Typedef
!(int, 42);
8909 static assert(is(TypedefType
!MyIntInit
== int));
8910 static assert(MyIntInit() == 42);
8913 /// Typedef creates a new type
8916 alias MyInt
= Typedef
!int;
8917 static void takeInt(int) {}
8918 static void takeMyInt(MyInt
) {}
8922 static assert(!__traits(compiles
, takeMyInt(i
)));
8925 static assert(!__traits(compiles
, takeInt(myInt
)));
8926 takeMyInt(myInt
); // ok
8929 /// Use the optional `cookie` argument to create different types of the same base type
8932 alias TypeInt1
= Typedef
!int;
8933 alias TypeInt2
= Typedef
!int;
8935 // The two Typedefs are the same type.
8936 static assert(is(TypeInt1
== TypeInt2
));
8938 alias MoneyEuros
= Typedef
!(float, float.init
, "euros");
8939 alias MoneyDollars
= Typedef
!(float, float.init
, "dollars");
8941 // The two Typedefs are _not_ the same type.
8942 static assert(!is(MoneyEuros
== MoneyDollars
));
8945 // https://issues.dlang.org/show_bug.cgi?id=12461
8948 alias Int
= Typedef
!int;
8956 Get the underlying type which a `Typedef` wraps.
8957 If `T` is not a `Typedef` it will alias itself to `T`.
8959 template TypedefType(T
)
8961 static if (is(T
: Typedef
!Arg
, Arg
))
8962 alias TypedefType
= Arg
;
8964 alias TypedefType
= T
;
8970 import std
.conv
: to
;
8972 alias MyInt
= Typedef
!int;
8973 static assert(is(TypedefType
!MyInt
== int));
8975 /// Instantiating with a non-Typedef will return that type
8976 static assert(is(TypedefType
!int == int));
8980 // extract the needed type
8981 MyInt myInt
= MyInt( num
.to
!(TypedefType
!MyInt
) );
8984 // cast to the underlying type to get the value that's being wrapped
8985 int x
= cast(TypedefType
!MyInt
) myInt
;
8987 alias MyIntInit
= Typedef
!(int, 42);
8988 static assert(is(TypedefType
!MyIntInit
== int));
8989 static assert(MyIntInit() == 42);
8995 static assert(!__traits(compiles
, { int y
= x
; }));
8996 static assert(!__traits(compiles
, { long z
= x
; }));
9001 static assert(Typedef
!int.init
== int.init
);
9003 Typedef
!(float, 1.0) z
; // specifies the init
9006 static assert(typeof(z
).init
== 1.0);
9008 alias Dollar
= Typedef
!(int, 0, "dollar");
9009 alias Yen
= Typedef
!(int, 0, "yen");
9010 static assert(!is(Dollar
== Yen
));
9012 Typedef
!(int[3]) sa
;
9013 static assert(sa
.length
== 3);
9014 static assert(typeof(sa
).length
== 3);
9016 Typedef
!(int[3]) dollar1
;
9017 assert(dollar1
[0..$] is dollar1
[0 .. 3]);
9019 Typedef
!(int[]) dollar2
;
9021 assert(dollar2
[0..$] is dollar2
[0 .. 3]);
9023 static struct Dollar1
9025 static struct DollarToken
{}
9026 enum opDollar
= DollarToken
.init
;
9027 auto opSlice(size_t
, DollarToken
) { return 1; }
9028 auto opSlice(size_t
, size_t
) { return 2; }
9031 Typedef
!Dollar1 drange1
;
9032 assert(drange1
[0..$] == 1);
9033 assert(drange1
[0 .. 1] == 2);
9035 static struct Dollar2
9037 size_t
opDollar(size_t pos
)() { return pos
== 0 ?
1 : 100; }
9038 size_t
opIndex(size_t i
, size_t j
) { return i
+ j
; }
9041 Typedef
!Dollar2 drange2
;
9042 assert(drange2
[$, $] == 101);
9044 static struct Dollar3
9046 size_t
opDollar() { return 123; }
9047 size_t
opIndex(size_t i
) { return i
; }
9050 Typedef
!Dollar3 drange3
;
9051 assert(drange3
[$] == 123);
9054 // https://issues.dlang.org/show_bug.cgi?id=18415
9055 @safe @nogc pure nothrow unittest
9057 struct NoDefCtorS
{@disable this();}
9058 union NoDefCtorU
{@disable this();}
9059 static assert(!is(typeof({Typedef
!NoDefCtorS s
;})));
9060 static assert(!is(typeof({Typedef
!NoDefCtorU u
;})));
9063 // https://issues.dlang.org/show_bug.cgi?id=11703
9064 @safe @nogc pure nothrow unittest
9066 alias I
= Typedef
!int;
9067 static assert(is(typeof(I
.min
) == I
));
9068 static assert(is(typeof(I
.max
) == I
));
9070 alias F
= Typedef
!double;
9071 static assert(is(typeof(F
.infinity
) == F
));
9072 static assert(is(typeof(F
.epsilon
) == F
));
9075 assert(!is(typeof(F
.re
).stringof
== double));
9076 assert(!is(typeof(F
.im
).stringof
== double));
9081 // https://issues.dlang.org/show_bug.cgi?id=8655
9082 import std
.typecons
;
9083 import std
.bitmanip
;
9084 static import core
.stdc
.config
;
9086 alias c_ulong
= Typedef
!(core
.stdc
.config
.c_ulong
);
9091 c_ulong
, "NameOffset", 31,
9092 c_ulong
, "NameIsString", 1
9097 // https://issues.dlang.org/show_bug.cgi?id=12596
9100 import std
.typecons
;
9101 alias TD
= Typedef
!int;
9107 @safe unittest // about toHash
9109 import std
.typecons
;
9111 alias TD
= Typedef
!int;
9114 assert(td
[TD(1)] == 1);
9118 alias TD
= Typedef
!(int[]);
9120 td
[TD([1,2,3,4])] = 2;
9121 assert(td
[TD([1,2,3,4])] == 2);
9125 alias TD
= Typedef
!(int[][]);
9127 td
[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3;
9128 assert(td
[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3);
9132 struct MyStruct
{ int x
; }
9133 alias TD
= Typedef
!MyStruct
;
9135 td
[TD(MyStruct(10))] = 4;
9136 assert(TD(MyStruct(20)) !in td
);
9137 assert(td
[TD(MyStruct(10))] == 4);
9141 static struct MyStruct2
9144 size_t
toHash() const nothrow @safe { return x
; }
9145 bool opEquals(ref const MyStruct2 r
) const { return r
.x
== x
; }
9148 alias TD
= Typedef
!MyStruct2
;
9150 td
[TD(MyStruct2(50))] = 5;
9151 assert(td
[TD(MyStruct2(50))] == 5);
9156 alias TD
= Typedef
!MyClass
;
9158 auto c
= new MyClass
;
9160 assert(TD(new MyClass
) !in td
);
9161 assert(td
[TD(c
)] == 6);
9167 alias String
= Typedef
!(char[]);
9168 alias CString
= Typedef
!(const(char)[]);
9169 CString cs
= "fubar";
9170 String s
= cast(String
) cs
;
9172 char[] s2
= cast(char[]) cs
;
9173 const(char)[] cs2
= cast(const(char)[])s
;
9177 @system unittest // toString
9179 import std
.meta
: AliasSeq
;
9180 import std
.conv
: to
;
9185 static foreach (T
; AliasSeq
!(int, bool, float, double, real,
9188 int*, int[], int[2], int[int]))
9193 Typedef
!(const T
) ctd
;
9194 Typedef
!(immutable T
) itd
;
9196 assert(t
.to
!string() == td
.to
!string());
9198 static if (!(is(T
== TestS
) ||
is(T
== TestC
)))
9200 assert(t
.to
!string() == ctd
.to
!string());
9201 assert(t
.to
!string() == itd
.to
!string());
9206 @safe @nogc unittest // typedef'ed type with custom operators
9211 int opCmp(MyInt other
)
9213 if (value
< other
.value
)
9215 return !(value
== other
.value
);
9219 auto m1
= Typedef
!MyInt(MyInt(1));
9220 auto m2
= Typedef
!MyInt(MyInt(2));
9225 Allocates a `class` object right inside the current scope,
9226 therefore avoiding the overhead of `new`. This facility is unsafe;
9227 it is the responsibility of the user to not escape a reference to the
9228 object outside the scope.
9230 The class destructor will be called when the result of `scoped()` is
9233 Scoped class instances can be embedded in a parent `class` or `struct`,
9234 just like a child struct instance. Scoped member variables must have
9235 type `typeof(scoped!Class(args))`, and be initialized with a call to
9236 scoped. See below for an example.
9239 It's illegal to move a class instance even if you are sure there
9240 are no pointers to it. As such, it is illegal to move a scoped object.
9245 // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for
9246 // small objects). We will just use the maximum of filed alignments.
9247 enum alignment
= __traits(classInstanceAlignment
, T
);
9248 alias aligned
= _alignUp
!alignment
;
9250 static struct Scoped
9252 // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory.
9253 private void[aligned(__traits(classInstanceSize
, T
) + size_t
.sizeof
) + alignment
] Scoped_store
= void;
9255 @property inout(T
) Scoped_payload() inout
9257 void* alignedStore
= cast(void*) aligned(cast(size_t
) Scoped_store
.ptr
);
9258 // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly.
9259 immutable size_t d
= alignedStore
- Scoped_store
.ptr
;
9260 size_t
* currD
= cast(size_t
*) &Scoped_store
[$ - size_t
.sizeof
];
9263 import core
.stdc
.string
: memmove
;
9264 memmove(alignedStore
, Scoped_store
.ptr
+ *currD
, __traits(classInstanceSize
, T
));
9267 return cast(inout(T
)) alignedStore
;
9269 alias Scoped_payload
this;
9272 @disable this(this);
9276 // `destroy` will also write .init but we have no functions in druntime
9277 // for deterministic finalization and memory releasing for now.
9278 .destroy(Scoped_payload
);
9282 /** Returns the _scoped object.
9283 Params: args = Arguments to pass to `T`'s constructor.
9285 @system auto scoped(Args
...)(auto ref Args args
)
9287 import core
.lifetime
: emplace
, forward
;
9289 Scoped result
= void;
9290 void* alignedStore
= cast(void*) aligned(cast(size_t
) result
.Scoped_store
.ptr
);
9291 immutable size_t d
= alignedStore
- result
.Scoped_store
.ptr
;
9292 *cast(size_t
*) &result
.Scoped_store
[$ - size_t
.sizeof
] = d
;
9293 emplace
!(Unqual
!T
)(result
.Scoped_store
[d
.. $ - size_t
.sizeof
], forward
!args
);
9309 // Standard usage, constructing A on the stack
9310 auto a1
= scoped
!A();
9313 // Result of `scoped` call implicitly converts to a class reference
9315 assert(aRef
.x
== 42);
9317 // Scoped destruction
9319 auto a2
= scoped
!A(1);
9322 // a2 is destroyed here, calling A's destructor
9324 // aRef is now an invalid reference
9326 // Here the temporary scoped A is immediately destroyed.
9327 // This means the reference is then invalid.
9330 // Wrong, should use `auto`
9331 A invalid
= scoped
!A();
9337 import std
.algorithm
.mutation
: move
;
9338 auto invalid
= a1
.move
; // illegal, scoped objects can't be moved
9340 static assert(!is(typeof({
9341 auto e1
= a1
; // illegal, scoped objects can't be copied
9342 assert([a1
][0].x
== 42); // ditto
9344 static assert(!is(typeof({
9345 alias ScopedObject
= typeof(a1
);
9346 auto e2
= ScopedObject(); // illegal, must be built via scoped!A
9347 auto e3
= ScopedObject(1); // ditto
9351 alias makeScopedA
= scoped
!A
;
9352 auto a3
= makeScopedA();
9353 auto a4
= makeScopedA(1);
9355 // Use as member variable
9358 typeof(scoped
!A()) a
; // note the trailing parentheses
9370 assert(aRef
.x
== 5);
9371 destroy(b1
); // calls A's destructor for b1.a
9372 // aRef is now an invalid reference
9376 assert(b2
.a
.x
== 6);
9377 destroy(*b2
); // calls A's destructor for b2.a
9380 private size_t
_alignUp(size_t alignment
)(size_t n
)
9381 if (alignment
> 0 && !((alignment
- 1) & alignment
))
9383 enum badEnd
= alignment
- 1; // 0b11, 0b111, ...
9384 return (n
+ badEnd
) & ~badEnd
;
9387 // https://issues.dlang.org/show_bug.cgi?id=6580 testcase
9390 enum alignment
= (void*).alignof
;
9393 static class C1
{ byte b
; }
9394 static class C2
{ byte[2] b
; }
9395 static class C3
{ byte[3] b
; }
9396 static class C7
{ byte[7] b
; }
9397 static assert(scoped
!C0().sizeof
% alignment
== 0);
9398 static assert(scoped
!C1().sizeof
% alignment
== 0);
9399 static assert(scoped
!C2().sizeof
% alignment
== 0);
9400 static assert(scoped
!C3().sizeof
% alignment
== 0);
9401 static assert(scoped
!C7().sizeof
% alignment
== 0);
9403 enum longAlignment
= long.alignof
;
9406 long long_
; byte byte_
= 4;
9408 this(long _long
, ref int i
) { long_
= _long
; ++i
; }
9410 static class C2long
{ byte[2] byte_
= [5, 6]; long long_
= 7; }
9411 static assert(scoped
!C1long().sizeof
% longAlignment
== 0);
9412 static assert(scoped
!C2long().sizeof
% longAlignment
== 0);
9414 void alignmentTest()
9417 auto c1long
= scoped
!C1long(3, var
);
9419 auto c2long
= scoped
!C2long();
9420 assert(cast(uint)&c1long
.long_
% longAlignment
== 0);
9421 assert(cast(uint)&c2long
.long_
% longAlignment
== 0);
9422 assert(c1long
.long_
== 3 && c1long
.byte_
== 4);
9423 assert(c2long
.byte_
== [5, 6] && c2long
.long_
== 7);
9428 version (DigitalMars
)
9430 void test(size_t size
)
9432 import core
.stdc
.stdlib
: alloca
;
9433 cast(void) alloca(size
);
9436 foreach (i
; 0 .. 10)
9441 void test(size_t size
)()
9446 static foreach (i
; 0 .. 11)
9451 // Original https://issues.dlang.org/show_bug.cgi?id=6580 testcase
9454 class C
{ int i
; byte b
; }
9456 auto sa
= [scoped
!C(), scoped
!C()];
9457 assert(cast(uint)&sa
[0].i
% int.alignof
== 0);
9458 assert(cast(uint)&sa
[1].i
% int.alignof
== 0); // fails
9463 class A
{ int x
= 1; }
9464 auto a1
= scoped
!A();
9466 auto a2
= scoped
!A();
9474 class A
{ int x
= 1; this() { x
= 2; } }
9475 auto a1
= scoped
!A();
9477 auto a2
= scoped
!A();
9485 class A
{ int x
= 1; this(int y
) { x
= y
; } ~this() {} }
9486 auto a1
= scoped
!A(5);
9488 auto a2
= scoped
!A(42);
9496 class A
{ static bool dead
; ~this() { dead
= true; } }
9497 class B
: A
{ static bool dead
; ~this() { dead
= true; } }
9499 auto b
= scoped
!B();
9501 assert(B
.dead
, "asdasd");
9502 assert(A
.dead
, "asdasd");
9505 // https://issues.dlang.org/show_bug.cgi?id=8039 testcase
9509 static struct S
{ ~this(){ ++dels
; } }
9511 static class A
{ S s
; }
9512 dels
= 0; { scoped
!A(); }
9515 static class B
{ S
[2] s
; }
9516 dels
= 0; { scoped
!B(); }
9519 static struct S2
{ S
[3] s
; }
9520 static class C
{ S2
[2] s
; }
9521 dels
= 0; { scoped
!C(); }
9524 static class D
: A
{ S2
[2] s
; }
9525 dels
= 0; { scoped
!D(); }
9526 assert(dels
== 1+6);
9531 // https://issues.dlang.org/show_bug.cgi?id=4500
9534 this() { a
= this; }
9535 this(int i
) { a
= this; }
9537 bool check() { return this is a
; }
9540 auto a1
= scoped
!A();
9543 auto a2
= scoped
!A(1);
9556 this() { ++sdtor
; assert(sdtor
== 1); }
9557 ~this() { assert(sdtor
== 1); --sdtor
; }
9562 static class ABob
: A
, Bob
9564 this() { ++sdtor
; assert(sdtor
== 2); }
9565 ~this() { assert(sdtor
== 2); --sdtor
; }
9569 scope(exit
) assert(A
.sdtor
== 0);
9570 auto abob
= scoped
!ABob();
9575 static class A
{ this(int) {} }
9576 static assert(!__traits(compiles
, scoped
!A()));
9581 static class A
{ @property inout(int) foo() inout { return 1; } }
9583 auto a1
= scoped
!A();
9584 assert(a1
.foo
== 1);
9585 static assert(is(typeof(a1
.foo
) == int));
9587 auto a2
= scoped
!(const(A
))();
9588 assert(a2
.foo
== 1);
9589 static assert(is(typeof(a2
.foo
) == const(int)));
9591 auto a3
= scoped
!(immutable(A
))();
9592 assert(a3
.foo
== 1);
9593 static assert(is(typeof(a3
.foo
) == immutable(int)));
9595 const c1
= scoped
!A();
9596 assert(c1
.foo
== 1);
9597 static assert(is(typeof(c1
.foo
) == const(int)));
9599 const c2
= scoped
!(const(A
))();
9600 assert(c2
.foo
== 1);
9601 static assert(is(typeof(c2
.foo
) == const(int)));
9603 const c3
= scoped
!(immutable(A
))();
9604 assert(c3
.foo
== 1);
9605 static assert(is(typeof(c3
.foo
) == immutable(int)));
9612 this(int rval
) { assert(rval
== 1); }
9613 this(ref int lval
) { assert(lval
== 3); ++lval
; }
9616 auto c1
= scoped
!C(1);
9618 auto c2
= scoped
!C(lval
);
9630 alias makeScopedC
= scoped
!C
;
9632 auto a
= makeScopedC();
9633 auto b
= makeScopedC(1);
9634 auto c
= makeScopedC(1, 1);
9636 static assert(is(typeof(a
) == typeof(b
)));
9637 static assert(is(typeof(b
) == typeof(c
)));
9641 Defines a simple, self-documenting yes/no flag. This makes it easy for
9642 APIs to define functions accepting flags without resorting to $(D
9643 bool), which is opaque in calls, and without needing to define an
9644 enumerated type separately. Using `Flag!"Name"` instead of $(D
9645 bool) makes the flag's meaning visible in calls. Each yes/no flag has
9646 its own type, which makes confusions and mix-ups impossible.
9650 Code calling `getLine` (usually far away from its definition) can't be
9651 understood without looking at the documentation, even by users familiar with
9654 string getLine(bool keepTerminator)
9657 if (keepTerminator) ...
9661 auto line = getLine(false);
9664 Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong
9665 code compiles and runs with erroneous results.
9667 After replacing the boolean parameter with an instantiation of `Flag`, code
9668 calling `getLine` can be easily read and understood even by people not
9669 fluent with the API:
9672 string getLine(Flag!"keepTerminator" keepTerminator)
9675 if (keepTerminator) ...
9679 auto line = getLine(Yes.keepTerminator);
9682 The structs `Yes` and `No` are provided as shorthand for
9683 `Flag!"Name".yes` and `Flag!"Name".no` and are preferred for brevity and
9684 readability. These convenience structs mean it is usually unnecessary and
9685 counterproductive to create an alias of a `Flag` as a way of avoiding typing
9686 out the full type while specifying the affirmative or negative options.
9688 Passing categorical data by means of unstructured `bool`
9689 parameters is classified under "simple-data coupling" by Steve
9690 McConnell in the $(LUCKY Code Complete) book, along with three other
9691 kinds of coupling. The author argues citing several studies that
9692 coupling has a negative effect on code quality. `Flag` offers a
9693 simple structuring method for passing yes/no flags to APIs.
9695 template Flag(string name
) {
9700 When creating a value of type `Flag!"Name"`, use $(D
9701 Flag!"Name".no) for the negative option. When using a value
9702 of type `Flag!"Name"`, compare it against $(D
9703 Flag!"Name".no) or just `false` or `0`. */
9706 /** When creating a value of type `Flag!"Name"`, use $(D
9707 Flag!"Name".yes) for the affirmative option. When using a
9708 value of type `Flag!"Name"`, compare it against $(D
9720 assert(flag
== Flag
!"abc".no
);
9721 assert(flag
== No
.abc
);
9723 if (flag
) assert(0);
9729 auto flag
= Yes
.abc
;
9732 assert(flag
== Yes
.abc
);
9733 if (!flag
) assert(0);
9734 if (flag
) {} else assert(0);
9738 Convenience names that allow using e.g. `Yes.encryption` instead of
9739 `Flag!"encryption".yes` and `No.encryption` instead of $(D
9740 Flag!"encryption".no).
9744 template opDispatch(string name
)
9746 enum opDispatch
= Flag
!name
.yes
;
9749 //template yes(string name) { enum Flag!name yes = Flag!name.yes; }
9754 template opDispatch(string name
)
9756 enum opDispatch
= Flag
!name
.no
;
9765 assert(flag
== Flag
!"abc".no
);
9766 assert(flag
== No
.abc
);
9768 if (flag
) assert(0);
9774 auto flag
= Yes
.abc
;
9777 assert(flag
== Yes
.abc
);
9778 if (!flag
) assert(0);
9779 if (flag
) {} else assert(0);
9783 Detect whether an enum is of integral type and has only "flag" values
9784 (i.e. values with a bit count of exactly 1).
9785 Additionally, a zero value is allowed for compatibility with enums including
9788 template isBitFlagEnum(E
)
9790 static if (is(E Base
== enum) && isIntegral
!Base
)
9792 enum isBitFlagEnum
= (E
.min
>= 0) &&
9794 static foreach (immutable flag
; EnumMembers
!E
)
9798 if (value
!= 0) return false;
9805 enum isBitFlagEnum
= false;
9810 @safe pure nothrow unittest
9821 static assert(isBitFlagEnum
!A
);
9824 /// Test an enum with default (consecutive) values
9825 @safe pure nothrow unittest
9835 static assert(!isBitFlagEnum
!B
);
9838 /// Test an enum with non-integral values
9839 @safe pure nothrow unittest
9847 static assert(!isBitFlagEnum
!C
);
9851 A typesafe structure for storing combinations of enum values.
9853 This template defines a simple struct to represent bitwise OR combinations of
9854 enum values. It can be used if all the enum values are integral constants with
9855 a bit count of at most 1, or if the `unsafe` parameter is explicitly set to
9857 This is much safer than using the enum itself to store
9858 the OR combination, which can produce surprising effects like this:
9866 // will throw SwitchError
9876 struct BitFlags(E
, Flag
!"unsafe" unsafe
= No
.unsafe
)
9877 if (unsafe || isBitFlagEnum
!(E
))
9879 @safe @nogc pure nothrow:
9881 enum isBaseEnumType(T
) = is(E
== T
);
9882 alias Base
= OriginalType
!E
;
9892 if (allSatisfy
!(isBaseEnumType
, T
))
9897 bool opCast(B
: bool)() const
9902 Base
opCast(B
)() const
9908 auto opUnary(string op
)() const
9911 return BitFlags(cast(E
) cast(Base
) ~mValue
);
9914 auto ref opAssign(T
...)(T flags
)
9915 if (allSatisfy
!(isBaseEnumType
, T
))
9918 foreach (E flag
; flags
)
9925 auto ref opAssign(E flag
)
9931 auto ref opOpAssign(string op
: "|")(BitFlags flags
)
9933 mValue |
= flags
.mValue
;
9937 auto ref opOpAssign(string op
: "&")(BitFlags flags
)
9939 mValue
&= flags
.mValue
;
9943 auto ref opOpAssign(string op
: "|")(E flag
)
9949 auto ref opOpAssign(string op
: "&")(E flag
)
9955 auto opBinary(string op
)(BitFlags flags
) const
9956 if (op
== "|" || op
== "&")
9958 BitFlags result
= this;
9959 result
.opOpAssign
!op(flags
);
9963 auto opBinary(string op
)(E flag
) const
9964 if (op
== "|" || op
== "&")
9966 BitFlags result
= this;
9967 result
.opOpAssign
!op(flag
);
9971 auto opBinaryRight(string op
)(E flag
) const
9972 if (op
== "|" || op
== "&")
9974 return opBinary
!op(flag
);
9977 bool opDispatch(string name
)() const
9978 if (__traits(hasMember
, E
, name
))
9980 enum e
= __traits(getMember
, E
, name
);
9981 return (mValue
& e
) == e
;
9984 void opDispatch(string name
)(bool set
)
9985 if (__traits(hasMember
, E
, name
))
9987 enum e
= __traits(getMember
, E
, name
);
9995 /// Set values with the | operator and test with &
9996 @safe @nogc pure nothrow unittest
10003 // A default constructed BitFlags has no value set
10004 immutable BitFlags
!Enum flags_empty
;
10005 assert(!flags_empty
.A
);
10007 // Value can be set with the | operator
10008 immutable flags_A
= flags_empty | Enum
.A
;
10010 // and tested using property access
10013 // or the & operator
10014 assert(flags_A
& Enum
.A
);
10016 assert(Enum
.A
& flags_A
);
10019 /// A default constructed BitFlags has no value set
10020 @safe @nogc pure nothrow unittest
10030 immutable BitFlags
!Enum flags_empty
;
10031 assert(!(flags_empty
& (Enum
.A | Enum
.B | Enum
.C
)));
10032 assert(!(flags_empty
& Enum
.A
) && !(flags_empty
& Enum
.B
) && !(flags_empty
& Enum
.C
));
10035 // BitFlags can be variadically initialized
10036 @safe @nogc pure nothrow unittest
10038 import std
.traits
: EnumMembers
;
10047 // Values can also be set using property access
10048 BitFlags
!Enum flags
;
10050 assert(flags
& Enum
.A
);
10052 assert(!(flags
& Enum
.A
));
10054 // BitFlags can be variadically initialized
10055 immutable BitFlags
!Enum flags_AB
= BitFlags
!Enum(Enum
.A
, Enum
.B
);
10056 assert(flags_AB
.A
&& flags_AB
.B
&& !flags_AB
.C
);
10058 // You can use the EnumMembers template to set all flags
10059 immutable BitFlags
!Enum flags_all
= EnumMembers
!Enum
;
10060 assert(flags_all
.A
&& flags_all
.B
&& flags_all
.C
);
10063 /// Binary operations: subtracting and intersecting flags
10064 @safe @nogc pure nothrow unittest
10072 immutable BitFlags
!Enum flags_AB
= BitFlags
!Enum(Enum
.A
, Enum
.B
);
10073 immutable BitFlags
!Enum flags_BC
= BitFlags
!Enum(Enum
.B
, Enum
.C
);
10075 // Use the ~ operator for subtracting flags
10076 immutable BitFlags
!Enum flags_B
= flags_AB
& ~BitFlags
!Enum(Enum
.A
);
10077 assert(!flags_B
.A
&& flags_B
.B
&& !flags_B
.C
);
10079 // use & between BitFlags for intersection
10080 assert(flags_B
== (flags_BC
& flags_AB
));
10083 /// All the binary operators work in their assignment version
10084 @safe @nogc pure nothrow unittest
10092 BitFlags
!Enum flags_empty
, temp
, flags_AB
;
10093 flags_AB
= Enum
.A | Enum
.B
;
10096 assert(temp
== (flags_empty | flags_AB
));
10098 temp
= flags_empty
;
10100 assert(temp
== (flags_empty | Enum
.B
));
10102 temp
= flags_empty
;
10104 assert(temp
== (flags_empty
& flags_AB
));
10106 temp
= flags_empty
;
10108 assert(temp
== (flags_empty
& Enum
.A
));
10111 /// Conversion to bool and int
10112 @safe @nogc pure nothrow unittest
10120 BitFlags
!Enum flags
;
10122 // BitFlags with no value set evaluate to false
10125 // BitFlags with at least one value set evaluate to true
10129 // This can be useful to check intersection between BitFlags
10130 BitFlags
!Enum flags_AB
= Enum
.A | Enum
.B
;
10131 assert(flags
& flags_AB
);
10132 assert(flags
& Enum
.A
);
10134 // You can of course get you raw value out of flags
10135 auto value
= cast(int) flags
;
10136 assert(value
== Enum
.A
);
10139 /// You need to specify the `unsafe` parameter for enums with custom values
10140 @safe @nogc pure nothrow unittest
10149 static assert(!__traits(compiles
, { BitFlags
!UnsafeEnum flags
; }));
10150 BitFlags
!(UnsafeEnum
, Yes
.unsafe
) flags
;
10152 // property access tests for exact match of unsafe enums
10154 assert(!flags
.BC
); // only B
10156 assert(flags
.BC
); // both B and C
10158 assert(!flags
.BC
); // only C
10160 // property access sets all bits of unsafe enum group
10161 flags
= flags
.init
;
10163 assert(!flags
.A
&& flags
.B
&& flags
.C
);
10166 assert(flags
.A
&& !flags
.B
&& !flags
.C
);
10169 // Negation of BitFlags should work with any base type.
10170 // Double-negation of BitFlags should work.
10171 @safe @nogc pure nothrow unittest
10173 static foreach (alias Base
; AliasSeq
!(
10191 auto flags
= BitFlags
!Enum(Enum
.A
);
10193 assert(flags
== ~~flags
);
10197 private enum false_(T
) = false;
10201 Replaces all occurrences of `From` into `To`, in one or more types `T`. For
10202 example, `ReplaceType!(int, uint, Tuple!(int, float)[string])` yields
10203 `Tuple!(uint, float)[string]`. The types in which replacement is performed
10204 may be arbitrarily complex, including qualifiers, built-in type constructors
10205 (pointers, arrays, associative arrays, functions, and delegates), and template
10206 instantiations; replacement proceeds transitively through the type definition.
10207 However, member types in `struct`s or `class`es are not replaced because there
10208 are no ways to express the types resulting after replacement.
10210 This is an advanced type manipulation necessary e.g. for replacing the
10211 placeholder type `This` in $(REF Algebraic, std,variant).
10213 Returns: `ReplaceType` aliases itself to the type(s) that result after
10216 alias ReplaceType(From
, To
, T
...) = ReplaceTypeUnless
!(false_
, From
, To
, T
);
10222 is(ReplaceType
!(int, string
, int[]) == string
[]) &&
10223 is(ReplaceType
!(int, string
, int[int]) == string
[string
]) &&
10224 is(ReplaceType
!(int, string
, const(int)[]) == const(string
)[]) &&
10225 is(ReplaceType
!(int, string
, Tuple
!(int[], float))
10226 == Tuple
!(string
[], float))
10231 Like $(LREF ReplaceType), but does not perform replacement in types for which
10232 `pred` evaluates to `true`.
10234 template ReplaceTypeUnless(alias pred
, From
, To
, T
...)
10238 static if (T
.length
== 1)
10240 static if (pred
!(T
[0]))
10241 alias ReplaceTypeUnless
= T
[0];
10242 else static if (is(T
[0] == From
))
10243 alias ReplaceTypeUnless
= To
;
10244 else static if (is(T
[0] == const(U
), U
))
10245 alias ReplaceTypeUnless
= const(ReplaceTypeUnless
!(pred
, From
, To
, U
));
10246 else static if (is(T
[0] == immutable(U
), U
))
10247 alias ReplaceTypeUnless
= immutable(ReplaceTypeUnless
!(pred
, From
, To
, U
));
10248 else static if (is(T
[0] == shared(U
), U
))
10249 alias ReplaceTypeUnless
= shared(ReplaceTypeUnless
!(pred
, From
, To
, U
));
10250 else static if (is(T
[0] == U
*, U
))
10252 static if (is(U
== function))
10253 alias ReplaceTypeUnless
= replaceTypeInFunctionTypeUnless
!(pred
, From
, To
, T
[0]);
10255 alias ReplaceTypeUnless
= ReplaceTypeUnless
!(pred
, From
, To
, U
)*;
10257 else static if (is(T
[0] == delegate))
10259 alias ReplaceTypeUnless
= replaceTypeInFunctionTypeUnless
!(pred
, From
, To
, T
[0]);
10261 else static if (is(T
[0] == function))
10263 static assert(0, "Function types not supported," ~
10264 " use a function pointer type instead of " ~ T
[0].stringof
);
10266 else static if (is(T
[0] == U
!V
, alias U
, V
...))
10268 template replaceTemplateArgs(T
...)
10270 static if (is(typeof(T
[0]))) { // template argument is value or symbol
10271 static if (__traits(compiles
, { alias _
= T
[0]; }))
10273 alias replaceTemplateArgs
= T
[0];
10276 enum replaceTemplateArgs
= T
[0];
10278 alias replaceTemplateArgs
= ReplaceTypeUnless
!(pred
, From
, To
, T
[0]);
10280 alias ReplaceTypeUnless
= U
!(staticMap
!(replaceTemplateArgs
, V
));
10282 else static if (is(T
[0] == struct))
10283 // don't match with alias this struct below
10284 // https://issues.dlang.org/show_bug.cgi?id=15168
10285 alias ReplaceTypeUnless
= T
[0];
10286 else static if (is(T
[0] == U
[], U
))
10287 alias ReplaceTypeUnless
= ReplaceTypeUnless
!(pred
, From
, To
, U
)[];
10288 else static if (is(T
[0] == U
[n
], U
, size_t n
))
10289 alias ReplaceTypeUnless
= ReplaceTypeUnless
!(pred
, From
, To
, U
)[n
];
10290 else static if (is(T
[0] == U
[V
], U
, V
))
10291 alias ReplaceTypeUnless
=
10292 ReplaceTypeUnless
!(pred
, From
, To
, U
)[ReplaceTypeUnless
!(pred
, From
, To
, V
)];
10294 alias ReplaceTypeUnless
= T
[0];
10296 else static if (T
.length
> 1)
10298 alias ReplaceTypeUnless
= AliasSeq
!(ReplaceTypeUnless
!(pred
, From
, To
, T
[0]),
10299 ReplaceTypeUnless
!(pred
, From
, To
, T
[1 .. $]));
10303 alias ReplaceTypeUnless
= AliasSeq
!();
10310 import std
.traits
: isArray
;
10313 is(ReplaceTypeUnless
!(isArray
, int, string
, int*) == string
*) &&
10314 is(ReplaceTypeUnless
!(isArray
, int, string
, int[]) == int[]) &&
10315 is(ReplaceTypeUnless
!(isArray
, int, string
, Tuple
!(int, int[]))
10316 == Tuple
!(string
, int[]))
10320 private template replaceTypeInFunctionTypeUnless(alias pred
, From
, To
, fun
)
10322 alias RX
= ReplaceTypeUnless
!(pred
, From
, To
, ReturnType
!fun
);
10323 alias PX
= AliasSeq
!(ReplaceTypeUnless
!(pred
, From
, To
, Parameters
!fun
));
10324 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return
10325 // tuple if Parameters!fun.length == 1
10329 enum linkage
= functionLinkage
!fun
;
10330 alias attributes
= functionAttributes
!fun
;
10331 enum variadicStyle
= variadicFunctionStyle
!fun
;
10332 alias storageClasses
= ParameterStorageClassTuple
!fun
;
10336 result
~= "extern(" ~ linkage
~ ") ";
10337 static if (attributes
& FunctionAttribute
.ref_
)
10343 static if (is(fun
== delegate))
10344 result
~= " delegate";
10346 result
~= " function";
10349 static foreach (i
; 0 .. PX
.length
)
10353 if (storageClasses
[i
] & ParameterStorageClass
.scope_
)
10354 result
~= "scope ";
10355 if (storageClasses
[i
] & ParameterStorageClass
.in_
)
10357 if (storageClasses
[i
] & ParameterStorageClass
.out_
)
10359 if (storageClasses
[i
] & ParameterStorageClass
.ref_
)
10361 if (storageClasses
[i
] & ParameterStorageClass
.lazy_
)
10363 if (storageClasses
[i
] & ParameterStorageClass
.return_
)
10364 result
~= "return ";
10366 result
~= "PX[" ~ i
.stringof
~ "]";
10368 static if (variadicStyle
== Variadic
.typesafe
)
10370 else static if (variadicStyle
!= Variadic
.no
)
10374 static if (attributes
& FunctionAttribute
.pure_
)
10376 static if (attributes
& FunctionAttribute
.nothrow_
)
10377 result
~= " nothrow";
10378 static if (attributes
& FunctionAttribute
.property
)
10379 result
~= " @property";
10380 static if (attributes
& FunctionAttribute
.trusted
)
10381 result
~= " @trusted";
10382 static if (attributes
& FunctionAttribute
.safe
)
10383 result
~= " @safe";
10384 static if (attributes
& FunctionAttribute
.nogc
)
10385 result
~= " @nogc";
10386 static if (attributes
& FunctionAttribute
.system
)
10387 result
~= " @system";
10388 static if (attributes
& FunctionAttribute
.const_
)
10389 result
~= " const";
10390 static if (attributes
& FunctionAttribute
.immutable_
)
10391 result
~= " immutable";
10392 static if (attributes
& FunctionAttribute
.inout_
)
10393 result
~= " inout";
10394 static if (attributes
& FunctionAttribute
.shared_
)
10395 result
~= " shared";
10396 static if (attributes
& FunctionAttribute
.return_
)
10397 result
~= " return";
10398 static if (attributes
& FunctionAttribute
.live
)
10399 result
~= " @live";
10404 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";");
10409 template Test(Ts
...)
10411 static if (Ts
.length
)
10413 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", "
10414 // ~Ts[1].stringof~", "~Ts[2].stringof~")");
10415 static assert(is(ReplaceType
!(Ts
[0], Ts
[1], Ts
[2]) == Ts
[3]),
10416 "ReplaceType!("~Ts
[0].stringof
~", "~Ts
[1].stringof
~", "
10417 ~Ts
[2].stringof
~") == "
10418 ~ReplaceType
!(Ts
[0], Ts
[1], Ts
[2]).stringof
);
10419 alias Test
= Test
!(Ts
[4 .. $]);
10421 else alias Test
= void;
10424 //import core.stdc.stdio;
10425 alias RefFun1
= ref int function(float, long);
10426 alias RefFun2
= ref float function(float, long);
10427 extern(C
) int printf(const char*, ...) nothrow @nogc @system;
10428 extern(C
) float floatPrintf(const char*, ...) nothrow @nogc @system;
10432 struct S1
{ void foo() { x
= 1; } }
10433 struct S2
{ void bar() { x
= 2; } }
10435 alias Pass
= Test
!(
10436 int, float, typeof(&func
), float delegate(float),
10437 int, float, typeof(&printf
), typeof(&floatPrintf
),
10438 int, float, int function(out long, ...),
10439 float function(out long, ...),
10440 int, float, int function(ref float, long),
10441 float function(ref float, long),
10442 int, float, int function(ref int, long),
10443 float function(ref float, long),
10444 int, float, int function(out int, long),
10445 float function(out float, long),
10446 int, float, int function(lazy int, long),
10447 float function(lazy float, long),
10448 int, float, int function(out long, ref const int),
10449 float function(out long, ref const float),
10450 int, float, int function(in long, ref const int),
10451 float function(in long, ref const float),
10452 int, float, int function(long, in int),
10453 float function(long, in float),
10454 int, int, int, int,
10455 int, float, int, float,
10456 int, float, const int, const float,
10457 int, float, immutable int, immutable float,
10458 int, float, shared int, shared float,
10459 int, float, int*, float*,
10460 int, float, const(int)*, const(float)*,
10461 int, float, const(int*), const(float*),
10462 const(int)*, float, const(int*), const(float),
10463 int*, float, const(int)*, const(int)*,
10464 int, float, int[], float[],
10465 int, float, int[42], float[42],
10466 int, float, const(int)[42], const(float)[42],
10467 int, float, const(int[42]), const(float[42]),
10468 int, float, int[int], float[float],
10469 int, float, int[double], float[double],
10470 int, float, double[int], double[float],
10471 int, float, int function(float, long), float function(float, long),
10472 int, float, int function(float), float function(float),
10473 int, float, int function(float, int), float function(float, float),
10474 int, float, int delegate(float, long), float delegate(float, long),
10475 int, float, int delegate(float), float delegate(float),
10476 int, float, int delegate(float, int), float delegate(float, float),
10477 int, float, Unique
!int, Unique
!float,
10478 int, float, Tuple
!(float, int), Tuple
!(float, float),
10479 int, float, RefFun1
, RefFun2
,
10481 S1
[1][][S1
]* function(),
10482 S2
[1][][S2
]* function(),
10484 int[3] function( int[] arr
, int[2] ...) pure @trusted,
10485 string
[3] function(string
[] arr
, string
[2] ...) pure @trusted,
10488 // https://issues.dlang.org/show_bug.cgi?id=15168
10489 static struct T1
{ string s
; alias s
this; }
10490 static struct T2
{ char[10] s
; alias s
this; }
10491 static struct T3
{ string
[string
] s
; alias s
this; }
10492 alias Pass2
= Test
!(
10493 ubyte, ubyte, T1
, T1
,
10494 ubyte, ubyte, T2
, T2
,
10495 ubyte, ubyte, T3
, T3
,
10499 // https://issues.dlang.org/show_bug.cgi?id=17116
10502 alias ConstDg
= void delegate(float) const;
10503 alias B
= void delegate(int) const;
10504 alias A
= ReplaceType
!(float, int, ConstDg
);
10505 static assert(is(B
== A
));
10508 // https://issues.dlang.org/show_bug.cgi?id=19696
10511 static struct T(U
) {}
10512 static struct S
{ T
!int t
; alias t
this; }
10513 static assert(is(ReplaceType
!(float, float, S
) == S
));
10516 // https://issues.dlang.org/show_bug.cgi?id=19697
10521 static assert(is(ReplaceType
!(float, float, C
)));
10524 // https://issues.dlang.org/show_bug.cgi?id=16132
10529 static assert(is(ReplaceType
!(int, string
, C
) == C
));
10532 // https://issues.dlang.org/show_bug.cgi?id=22325
10535 static struct Foo(alias f
) {}
10536 static void bar() {}
10537 alias _
= ReplaceType
!(int, int, Foo
!bar
);
10541 Ternary type with three truth values:
10544 $(LI `Ternary.yes` for `true`)
10545 $(LI `Ternary.no` for `false`)
10546 $(LI `Ternary.unknown` as an unknown state)
10549 Also known as trinary, trivalent, or trilean.
10552 $(HTTP en.wikipedia.org/wiki/Three-valued_logic,
10553 Three Valued Logic on Wikipedia)
10557 @safe @nogc nothrow pure:
10559 private ubyte value
= 6;
10560 private static Ternary
make(ubyte b
)
10568 The possible states of the `Ternary`
10572 enum yes
= make(2);
10574 enum unknown
= make(6);
10577 Construct and assign from a `bool`, receiving `no` for `false` and `yes`
10580 this(bool b
) { value
= b
<< 1; }
10583 void opAssign(bool b
) { value
= b
<< 1; }
10586 Construct a ternary value from another ternary value
10588 this(const Ternary b
) { value
= b
.value
; }
10591 $(TABLE Truth table for logical operations,
10592 $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`))
10593 $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`))
10594 $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`))
10595 $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
10596 $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`))
10597 $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`))
10598 $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
10599 $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
10600 $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
10601 $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`))
10604 Ternary
opUnary(string s
)() if (s
== "~")
10606 return make((386 >> value
) & 6);
10610 Ternary
opBinary(string s
)(Ternary rhs
) if (s
== "|")
10612 return make((25_512 >> (value
+ rhs
.value
)) & 6);
10616 Ternary
opBinary(string s
)(Ternary rhs
) if (s
== "&")
10618 return make((26_144 >> (value
+ rhs
.value
)) & 6);
10622 Ternary
opBinary(string s
)(Ternary rhs
) if (s
== "^")
10624 return make((26_504 >> (value
+ rhs
.value
)) & 6);
10628 Ternary
opBinary(string s
)(bool rhs
)
10629 if (s
== "|" || s
== "&" || s
== "^")
10631 return this.opBinary
!s(Ternary(rhs
));
10636 @safe @nogc nothrow pure
10640 assert(a
== Ternary
.unknown
);
10642 assert(~Ternary
.yes
== Ternary
.no
);
10643 assert(~Ternary
.no
== Ternary
.yes
);
10644 assert(~Ternary
.unknown
== Ternary
.unknown
);
10647 @safe @nogc nothrow pure
10650 alias f
= Ternary
.no
, t
= Ternary
.yes
, u
= Ternary
.unknown
;
10651 Ternary
[27] truthTableAnd
=
10664 Ternary
[27] truthTableOr
=
10677 Ternary
[27] truthTableXor
=
10690 for (auto i
= 0; i
!= truthTableAnd
.length
; i
+= 3)
10692 assert((truthTableAnd
[i
] & truthTableAnd
[i
+ 1])
10693 == truthTableAnd
[i
+ 2]);
10694 assert((truthTableOr
[i
] | truthTableOr
[i
+ 1])
10695 == truthTableOr
[i
+ 2]);
10696 assert((truthTableXor
[i
] ^ truthTableXor
[i
+ 1])
10697 == truthTableXor
[i
+ 2]);
10701 assert(a
== Ternary
.unknown
);
10702 static assert(!is(typeof({ if (a
) {} })));
10703 assert(!is(typeof({ auto b
= Ternary(3); })));
10705 assert(a
== Ternary
.yes
);
10707 assert(a
== Ternary
.no
);
10708 a
= Ternary
.unknown
;
10709 assert(a
== Ternary
.unknown
);
10713 assert(~Ternary
.yes
== Ternary
.no
);
10714 assert(~Ternary
.no
== Ternary
.yes
);
10715 assert(~Ternary
.unknown
== Ternary
.unknown
);
10718 @safe @nogc nothrow pure
10721 Ternary a
= Ternary(true);
10722 assert(a
== Ternary
.yes
);
10723 assert((a
& false) == Ternary
.no
);
10724 assert((a |
false) == Ternary
.yes
);
10725 assert((a ^
true) == Ternary
.no
);
10726 assert((a ^
false) == Ternary
.yes
);
10729 // https://issues.dlang.org/show_bug.cgi?id=22511
10735 @disable this(this);
10736 this(ref return scope inout S rhs
) inout
10738 this.b
= rhs
.b
+ 1;
10742 Nullable
!S s1
= S(1);
10743 assert(s1
.get().b
== 2);
10744 Nullable
!S s2
= s1
;
10745 assert(s2
.get().b
== 3);
10753 this(this) { ++b
; }
10756 Nullable
!S s1
= S(1);
10757 assert(s1
.get().b
== 2);
10758 Nullable
!S s2
= s1
;
10759 assert(s2
.get().b
== 3);
10762 // https://issues.dlang.org/show_bug.cgi?id=24318
10767 @disable this(this);
10771 Nullable
!S s
= S(1);
10772 assert(s
.get().i
== 1);
10774 assert(s
.get().i
== 2);
10777 /// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed.
10778 /// Old code may be relying on `@safe`ty of some of the member functions which
10779 /// cannot be safe in the new scheme, and
10780 /// can avoid breakage by continuing to use this. `SafeRefCounted` should be
10781 /// preferred, as this type is outdated and unrecommended for new code.
10782 struct RefCounted(T
, RefCountedAutoInitialize autoInit
=
10783 RefCountedAutoInitialize
.yes
)
10785 version (D_BetterC
)
10787 private enum enableGCScan
= false;
10791 private enum enableGCScan
= hasIndirections
!T
;
10794 extern(C
) private pure nothrow @nogc static
10796 pragma(mangle
, "free") void pureFree( void *ptr
);
10797 static if (enableGCScan
)
10798 import core
.memory
: GC
;
10801 struct RefCountedStore
10803 private struct Impl
10809 private Impl
* _store
;
10811 private void initialize(A
...)(auto ref A args
)
10813 import core
.lifetime
: emplace
, forward
;
10816 version (D_Exceptions
) scope(failure
) deallocateStore();
10817 emplace(&_store
._payload
, forward
!args
);
10821 private void move(ref T source
) nothrow pure
10823 import std
.algorithm
.mutation
: moveEmplace
;
10826 moveEmplace(source
, _store
._payload
);
10830 // 'nothrow': can only generate an Error
10831 private void allocateStore() nothrow pure
10833 static if (enableGCScan
)
10835 import std
.internal
.memory
: enforceCalloc
;
10836 _store
= cast(Impl
*) enforceCalloc(1, Impl
.sizeof
);
10837 GC
.addRange(&_store
._payload
, T
.sizeof
);
10841 import std
.internal
.memory
: enforceMalloc
;
10842 _store
= cast(Impl
*) enforceMalloc(Impl
.sizeof
);
10846 private void deallocateStore() nothrow pure
10848 static if (enableGCScan
)
10850 GC
.removeRange(&this._store
._payload
);
10856 @property nothrow @safe pure @nogc
10857 bool isInitialized() const
10859 return _store
!is null;
10862 @property nothrow @safe pure @nogc
10863 size_t
refCount() const
10865 return isInitialized ? _store
._count
: 0;
10868 void ensureInitialized()()
10870 // By checking for `@disable this()` and failing early we can
10871 // produce a clearer error message.
10872 static assert(__traits(compiles
, { static T t
; }),
10873 "Cannot automatically initialize `" ~ fullyQualifiedName
!T
~
10874 "` because `" ~ fullyQualifiedName
!T
~
10875 ".this()` is annotated with `@disable`.");
10876 if (!isInitialized
) initialize();
10880 RefCountedStore _refCounted
;
10882 @property nothrow @safe
10883 ref inout(RefCountedStore
) refCountedStore() inout
10885 return _refCounted
;
10888 this(A
...)(auto ref A args
) if (A
.length
> 0)
10891 assert(refCountedStore
.isInitialized
);
10895 import core
.lifetime
: forward
;
10896 _refCounted
.initialize(forward
!args
);
10901 _refCounted
.move(val
);
10904 this(this) @safe pure nothrow @nogc
10906 if (!_refCounted
.isInitialized
) return;
10907 ++_refCounted
._store
._count
;
10912 if (!_refCounted
.isInitialized
) return;
10913 assert(_refCounted
._store
._count
> 0);
10914 if (--_refCounted
._store
._count
)
10916 // Done, destroy and deallocate
10917 .destroy(_refCounted
._store
._payload
);
10918 _refCounted
.deallocateStore();
10921 void opAssign(typeof(this) rhs
)
10923 import std
.algorithm
.mutation
: swap
;
10925 swap(_refCounted
._store
, rhs
._refCounted
._store
);
10928 void opAssign(T rhs
)
10930 import std
.algorithm
.mutation
: move
;
10932 static if (autoInit
== RefCountedAutoInitialize
.yes
)
10934 _refCounted
.ensureInitialized();
10938 assert(_refCounted
.isInitialized
);
10940 move(rhs
, _refCounted
._store
._payload
);
10943 static if (autoInit
== RefCountedAutoInitialize
.yes
)
10945 //Can't use inout here because of potential mutation
10947 ref T
refCountedPayload() return
10949 _refCounted
.ensureInitialized();
10950 return _refCounted
._store
._payload
;
10954 @property nothrow @safe pure @nogc
10955 ref inout(T
) refCountedPayload() inout return
10957 assert(_refCounted
.isInitialized
, "Attempted to access an uninitialized payload.");
10958 return _refCounted
._store
._payload
;
10961 alias refCountedPayload
this;
10963 static if (is(T
== struct) && !is(typeof((ref T t
) => t
.toString())))
10965 string
toString(this This
)()
10967 import std
.conv
: to
;
10969 static if (autoInit
)
10970 return to
!string(refCountedPayload
);
10973 if (!_refCounted
.isInitialized
)
10974 return This
.stringof
~ "(RefCountedStore(null))";
10976 return to
!string(_refCounted
._store
._payload
);
10983 @betterC pure @system nothrow @nogc unittest
10985 auto rc1
= RefCounted
!int(5);
10992 // More unit tests below SafeRefCounted
10995 * Like $(LREF safeRefCounted) but used to initialize $(LREF RefCounted)
10996 * instead. Intended for backwards compatibility, otherwise it is preferable
10997 * to use `safeRefCounted`.
10999 RefCounted
!(T
, RefCountedAutoInitialize
.no
) refCounted(T
)(T val
)
11001 typeof(return) res
;
11002 res
._refCounted
.move(val
);
11011 static size_t nDestroyed
;
11013 @disable this(this); // not copyable
11014 ~this() { name
= null; ++nDestroyed
; }
11017 auto file
= File("name");
11018 assert(file
.name
== "name");
11019 static assert(!__traits(compiles
, {auto file2
= file
;}));
11020 assert(File
.nDestroyed
== 0);
11023 import std
.algorithm
.mutation
: move
;
11024 auto rcFile
= refCounted(move(file
));
11025 assert(rcFile
.name
== "name");
11026 assert(File
.nDestroyed
== 1);
11027 assert(file
.name
== null);
11029 auto rcFile2
= rcFile
;
11030 assert(rcFile
.refCountedStore
.refCount
== 2);
11031 assert(File
.nDestroyed
== 1);
11034 assert(File
.nDestroyed
== 2);
11037 // More unit tests below safeRefCounted