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);
564 _Tuple of values, for example $(D Tuple!(int, string)) is a record that
565 stores an `int` and a `string`. `Tuple` can be used to bundle
566 values together, notably when returning multiple values from a
567 function. If `obj` is a `Tuple`, the individual members are
568 accessible with the syntax `obj[0]` for the first field, `obj[1]`
569 for the second, and so on.
571 See_Also: $(LREF tuple).
574 Specs = A list of types (and optionally, member names) that the `Tuple` contains.
576 template Tuple(Specs...)
577 if (distinctFieldNames!(Specs))
579 import std.meta : staticMap;
581 alias fieldSpecs = parseSpecs!Specs;
583 // Generates named fields as follows:
584 // alias name_0 = Identity!(field[0]);
585 // alias name_1 = Identity!(field[1]);
587 // NOTE: field[k] is an expression (which yields a symbol of a
588 // variable) and can't be aliased directly.
589 enum injectNamedFields = ()
592 static foreach (i, val; fieldSpecs)
594 immutable si = i.stringof;
595 decl ~= "alias _" ~ si ~ " = Identity!(field[" ~ si ~ "]);";
596 if (val.name.length != 0)
598 decl ~= "alias " ~ val.name ~ " = _" ~ si ~ ";";
604 // Returns Specs for a subtuple this[from .. to] preserving field
606 alias sliceSpecs(size_t from, size_t to) =
607 staticMap!(expandSpec, fieldSpecs[from .. to]);
612 * The types of the `Tuple`'s components.
614 alias Types = staticMap!(extractType, fieldSpecs);
616 private alias _Fields = Specs;
619 static if (Specs.length == 0) @safe unittest
621 import std.meta : AliasSeq;
622 alias Fields = Tuple!(int, "id", string, float);
623 static assert(is(Fields.Types == AliasSeq!(int, string, float)));
627 * The names of the `Tuple`'s components. Unnamed fields have empty names.
629 alias fieldNames = staticMap!(extractName, fieldSpecs);
632 static if (Specs.length == 0) @safe unittest
634 import std.meta : AliasSeq;
635 alias Fields = Tuple!(int, "id", string, float);
636 static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
640 * Use `t.expand` for a `Tuple` `t` to expand it into its
641 * components. The result of `expand` acts as if the `Tuple`'s components
642 * were listed as a list of values. (Ordinarily, a `Tuple` acts as a
646 mixin(injectNamedFields());
649 static if (Specs.length == 0) @safe unittest
651 auto t1 = tuple(1, " hello ", 'a');
652 assert(t1.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`);
654 void takeSeveralTypes(int n, string s, bool b)
656 assert(n == 4 && s == "test" && b == false);
659 auto t2 = tuple(4, "test", false);
660 //t.expand acting as a list of values
661 takeSeveralTypes(t2.expand);
664 static if (is(Specs))
666 // This is mostly to make t[n] work.
672 ref inout(Tuple!Types) _Tuple_super() inout @trusted
674 static foreach (i; 0 .. Types.length) // Rely on the field layout
676 static assert(typeof(return).init.tupleof[i].offsetof ==
679 return *cast(typeof(return)*) &(field[0]);
681 // This is mostly to make t[n] work.
682 alias _Tuple_super this;
685 // backwards compatibility
686 alias field = expand;
689 * Constructor taking one value for each field.
692 * values = A list of values that are either the same
693 * types as those given by the `Types` field
694 * of this `Tuple`, or can implicitly convert
695 * to those types. They must be in the same
696 * order as they appear in `Types`.
698 static if (Types.length > 0)
707 static if (Specs.length == 0) @safe unittest
709 alias ISD = Tuple!(int, string, double);
710 auto tup = ISD(1, "test", 3.2);
711 assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`);
715 * Constructor taking a compatible array.
718 * values = A compatible static array to build the `Tuple` from.
719 * Array slices are not supported.
721 this(U, size_t n)(U[n] values)
722 if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))
724 static foreach (i; 0 .. Types.length)
726 field[i] = values[i];
731 static if (Specs.length == 0) @safe unittest
734 Tuple!(int, int) t = ints;
738 * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible
739 * $(B iff) they are both of the same length, and, for each type `T` on the
740 * left-hand side, the corresponding type `U` on the right-hand side can
741 * implicitly convert to `T`.
744 * another = A compatible `Tuple` to build from. Its type must be
745 * compatible with the target `Tuple`'s type.
748 if (areBuildCompatibleTuples!(typeof(this), U))
750 field[] = another.field[];
754 static if (Specs.length == 0) @safe unittest
756 alias IntVec = Tuple!(int, int, int);
757 alias DubVec = Tuple!(double, double, double);
759 IntVec iv = tuple(1, 1, 1);
761 //Ok, int can implicitly convert to double
763 //Error: double cannot implicitly convert to int
768 * Comparison for equality. Two `Tuple`s are considered equal
769 * $(B iff) they fulfill the following criteria:
772 * $(LI Each `Tuple` is the same length.)
773 * $(LI For each type `T` on the left-hand side and each type
774 * `U` on the right-hand side, values of type `T` can be
775 * compared with values of type `U`.)
776 * $(LI For each value `v1` on the left-hand side and each value
777 * `v2` on the right-hand side, the expression `v1 == v2` is
781 * rhs = The `Tuple` to compare against. It must meeting the criteria
782 * for comparison between `Tuple`s.
785 * true if both `Tuple`s are equal, otherwise false.
787 bool opEquals(R)(R rhs)
788 if (areCompatibleTuples!(typeof(this), R, "=="))
790 return field[] == rhs.field[];
794 bool opEquals(R)(R rhs) const
795 if (areCompatibleTuples!(typeof(this), R, "=="))
797 return field[] == rhs.field[];
801 bool opEquals(R...)(auto ref R rhs)
802 if (R.length > 1 && areCompatibleTuples!(typeof(this), Tuple!R, "=="))
804 static foreach (i; 0 .. Types.length)
805 if (field[i] != rhs[i])
812 static if (Specs.length == 0) @safe unittest
814 Tuple!(int, string) t1 = tuple(1, "test");
815 Tuple!(double, string) t2 = tuple(1.0, "test");
816 //Ok, int can be compared with double and
817 //both have a value of 1
822 * Comparison for ordering.
825 * rhs = The `Tuple` to compare against. It must meet the criteria
826 * for comparison between `Tuple`s.
829 * For any values `v1` contained by the left-hand side tuple and any
830 * values `v2` contained by the right-hand side:
832 * 0 if `v1 == v2` for all members or the following value for the
833 * first position were the mentioned criteria is not satisfied:
836 * $(LI NaN, in case one of the operands is a NaN.)
837 * $(LI A negative number if the expression `v1 < v2` is true.)
838 * $(LI A positive number if the expression `v1 > v2` is true.))
841 if (areCompatibleTuples!(typeof(this), R, "<"))
843 static foreach (i; 0 .. Types.length)
845 if (field[i] != rhs.field[i])
847 import std.math.traits : isNaN;
848 static if (isFloatingPoint!(Types[i]))
853 static if (isFloatingPoint!(typeof(rhs.field[i])))
855 if (isNaN(rhs.field[i]))
858 static if (is(typeof(field[i].opCmp(rhs.field[i]))) &&
859 isFloatingPoint!(typeof(field[i].opCmp(rhs.field[i]))))
861 if (isNaN(field[i].opCmp(rhs.field[i])))
865 return field[i] < rhs.field[i] ? -1 : 1;
872 auto opCmp(R)(R rhs) const
873 if (areCompatibleTuples!(typeof(this), R, "<"))
875 static foreach (i; 0 .. Types.length)
877 if (field[i] != rhs.field[i])
879 import std.math.traits : isNaN;
880 static if (isFloatingPoint!(Types[i]))
885 static if (isFloatingPoint!(typeof(rhs.field[i])))
887 if (isNaN(rhs.field[i]))
890 static if (is(typeof(field[i].opCmp(rhs.field[i]))) &&
891 isFloatingPoint!(typeof(field[i].opCmp(rhs.field[i]))))
893 if (isNaN(field[i].opCmp(rhs.field[i])))
897 return field[i] < rhs.field[i] ? -1 : 1;
904 The first `v1` for which `v1 > v2` is true determines
905 the result. This could lead to unexpected behaviour.
907 static if (Specs.length == 0) @safe unittest
909 auto tup1 = tuple(1, 1, 1);
910 auto tup2 = tuple(1, 100, 100);
913 //Only the first result matters for comparison
920 Tuple concatenation is only allowed if all named fields are distinct (no named field of this tuple occurs in `t`
921 and no named field of `t` occurs in this tuple).
924 t = The `Tuple` to concatenate with
926 Returns: A concatenation of this tuple and `t`
928 auto opBinary(string op, T)(auto ref T t)
929 if (op == "~" && !(is(T : U[], U) && isTuple!U))
931 static if (isTuple!T)
933 static assert(distinctFieldNames!(_Fields, T._Fields),
934 "Cannot concatenate tuples with duplicate fields: " ~ fieldNames.stringof ~
935 " - " ~ T.fieldNames.stringof);
936 return Tuple!(_Fields, T._Fields)(expand, t.expand);
940 return Tuple!(_Fields, T)(expand, t);
945 auto opBinaryRight(string op, T)(auto ref T t)
946 if (op == "~" && !(is(T : U[], U) && isTuple!U))
948 static if (isTuple!T)
950 static assert(distinctFieldNames!(_Fields, T._Fields),
951 "Cannot concatenate tuples with duplicate fields: " ~ T.stringof ~
952 " - " ~ fieldNames.fieldNames.stringof);
953 return Tuple!(T._Fields, _Fields)(t.expand, expand);
957 return Tuple!(T, _Fields)(t, expand);
962 * Assignment from another `Tuple`.
965 * rhs = The source `Tuple` to assign from. Each element of the
966 * source `Tuple` must be implicitly assignable to each
967 * respective element of the target `Tuple`.
969 ref Tuple opAssign(R)(auto ref R rhs)
970 if (areCompatibleTuples!(typeof(this), R, "="))
972 import std.algorithm.mutation : swap;
974 static if (is(R : Tuple!Types) && !__traits(isRef, rhs) && isTuple!R)
978 // Cannot use swap at compile time
979 field[] = rhs.field[];
983 // Use swap-and-destroy to optimize rvalue assignment
984 swap!(Tuple!Types)(this, rhs);
989 // Do not swap; opAssign should be called on the fields.
990 field[] = rhs.field[];
996 * Renames the elements of a $(LREF Tuple).
998 * `rename` uses the passed `names` and returns a new
999 * $(LREF Tuple) using these names, with the content
1001 * If fewer names are passed than there are members
1002 * of the $(LREF Tuple) then those trailing members are unchanged.
1003 * An empty string will remove the name for that member.
1004 * It is an compile-time error to pass more names than
1005 * there are members of the $(LREF Tuple).
1007 ref rename(names...)() inout return
1008 if (names.length == 0 || allSatisfy!(isSomeString, typeof(names)))
1010 import std.algorithm.comparison : equal;
1011 // to circumvent https://issues.dlang.org/show_bug.cgi?id=16418
1012 static if (names.length == 0 || equal([names], [fieldNames]))
1016 enum nT = Types.length;
1017 enum nN = names.length;
1018 static assert(nN <= nT, "Cannot have more names than tuple members");
1019 alias allNames = AliasSeq!(names, fieldNames[nN .. $]);
1021 import std.meta : Alias, aliasSeqOf;
1023 template GetItem(size_t idx)
1025 import std.array : empty;
1026 static if (idx < nT)
1027 alias GetItem = Alias!(Types[idx]);
1028 else static if (allNames[idx - nT].empty)
1029 alias GetItem = AliasSeq!();
1031 alias GetItem = Alias!(allNames[idx - nT]);
1034 import std.range : roundRobin, iota;
1035 alias NewTupleT = Tuple!(staticMap!(GetItem, aliasSeqOf!(
1036 roundRobin(iota(nT), iota(nT, 2*nT)))));
1037 return *(() @trusted => cast(NewTupleT*)&this)();
1042 static if (Specs.length == 0) @safe unittest
1044 auto t0 = tuple(4, "hello");
1046 auto t0Named = t0.rename!("val", "tag");
1047 assert(t0Named.val == 4);
1048 assert(t0Named.tag == "hello");
1050 Tuple!(float, "dat", size_t[2], "pos") t1;
1052 auto t1Named = t1.rename!"height";
1053 t1Named.height = 3.4f;
1054 assert(t1Named.height == 3.4f);
1055 assert(t1Named.pos == [2, 1]);
1056 t1Named.rename!"altitude".altitude = 5;
1057 assert(t1Named.height == 5);
1059 Tuple!(int, "a", int, int, "c") t2;
1061 auto t2Named = t2.rename!("", "b");
1062 // "a" no longer has a name
1063 static assert(!__traits(hasMember, typeof(t2Named), "a"));
1064 assert(t2Named[0] == 3);
1065 assert(t2Named.b == 4);
1066 assert(t2Named.c == 5);
1068 // not allowed to specify more names than the tuple has members
1069 static assert(!__traits(compiles, t2.rename!("a","b","c","d")));
1071 // use it in a range pipeline
1072 import std.range : iota, zip;
1073 import std.algorithm.iteration : map, sum;
1074 auto res = zip(iota(1, 4), iota(10, 13))
1075 .map!(t => t.rename!("a", "b"))
1076 .map!(t => t.a * t.b)
1080 const tup = Tuple!(int, "a", int, "b")(2, 3);
1081 const renamed = tup.rename!("c", "d");
1082 assert(renamed.c + renamed.d == 5);
1086 * Overload of $(LREF _rename) that takes an associative array
1087 * `translate` as a template parameter, where the keys are
1088 * either the names or indices of the members to be changed
1089 * and the new names are the corresponding values.
1090 * Every key in `translate` must be the name of a member of the
1092 * The same rules for empty strings apply as for the variadic
1093 * template overload of $(LREF _rename).
1095 ref rename(alias translate)() inout
1096 if (is(typeof(translate) : V[K], V, K) && isSomeString!V &&
1097 (isSomeString!K || is(K : size_t)))
1099 import std.meta : aliasSeqOf;
1100 import std.range : ElementType;
1101 static if (isSomeString!(ElementType!(typeof(translate.keys))))
1104 import std.conv : to;
1105 import std.algorithm.iteration : filter;
1106 import std.algorithm.searching : canFind;
1107 enum notFound = translate.keys
1108 .filter!(k => fieldNames.canFind(k) == -1);
1109 static assert(notFound.empty, "Cannot find members "
1110 ~ notFound.to!string ~ " in type "
1111 ~ typeof(this).stringof);
1113 return this.rename!(aliasSeqOf!(
1115 import std.array : empty;
1116 auto names = [fieldNames];
1117 foreach (ref n; names)
1119 if (auto p = n in translate)
1127 import std.algorithm.iteration : filter;
1128 import std.conv : to;
1129 enum invalid = translate.keys.
1130 filter!(k => k < 0 || k >= this.length);
1131 static assert(invalid.empty, "Indices " ~ invalid.to!string
1132 ~ " are out of bounds for tuple with length "
1133 ~ this.length.to!string);
1135 return this.rename!(aliasSeqOf!(
1137 auto names = [fieldNames];
1138 foreach (k, v; translate)
1146 static if (Specs.length == 0) @safe unittest
1148 //replacing names by their current name
1150 Tuple!(float, "dat", size_t[2], "pos") t1;
1152 auto t1Named = t1.rename!(["dat": "height"]);
1153 t1Named.height = 3.4;
1154 assert(t1Named.pos == [2, 1]);
1155 t1Named.rename!(["height": "altitude"]).altitude = 5;
1156 assert(t1Named.height == 5);
1158 Tuple!(int, "a", int, "b") t2;
1160 auto t2Named = t2.rename!(["a": "b", "b": "c"]);
1161 assert(t2Named.b == 3);
1162 assert(t2Named.c == 4);
1164 const t3 = Tuple!(int, "a", int, "b")(3, 4);
1165 const t3Named = t3.rename!(["a": "b", "b": "c"]);
1166 assert(t3Named.b == 3);
1167 assert(t3Named.c == 4);
1171 static if (Specs.length == 0) @system unittest
1173 //replace names by their position
1175 Tuple!(float, "dat", size_t[2], "pos") t1;
1177 auto t1Named = t1.rename!([0: "height"]);
1178 t1Named.height = 3.4;
1179 assert(t1Named.pos == [2, 1]);
1180 t1Named.rename!([0: "altitude"]).altitude = 5;
1181 assert(t1Named.height == 5);
1183 Tuple!(int, "a", int, "b", int, "c") t2;
1184 t2 = tuple(3, 4, 5);
1185 auto t2Named = t2.rename!([0: "c", 2: "a"]);
1186 assert(t2Named.a == 5);
1187 assert(t2Named.b == 4);
1188 assert(t2Named.c == 3);
1191 static if (Specs.length == 0) @system unittest
1193 //check that empty translations work fine
1194 enum string[string] a0 = null;
1195 enum string[int] a1 = null;
1196 Tuple!(float, "a", float, "b") t0;
1198 auto t1 = t0.rename!a0;
1202 auto t2 = t0.rename!a1;
1205 auto t3 = t0.rename;
1211 * Takes a slice by-reference of this `Tuple`.
1214 * from = A `size_t` designating the starting position of the slice.
1215 * to = A `size_t` designating the ending position (exclusive) of the slice.
1218 * A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original.
1219 * It has the same types and values as the range `[from, to$(RPAREN)` in
1223 ref inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout @trusted
1224 if (from <= to && to <= Types.length)
1227 (typeof(this).alignof % typeof(return).alignof == 0) &&
1228 (expand[from].offsetof % typeof(return).alignof == 0),
1229 "Slicing by reference is impossible because of an alignment mistmatch" ~
1230 " (See https://issues.dlang.org/show_bug.cgi?id=15645).");
1232 return *cast(typeof(return)*) &(field[from]);
1236 static if (Specs.length == 0) @safe unittest
1238 Tuple!(int, string, float, double) a;
1241 auto s = a.slice!(1, 3);
1242 static assert(is(typeof(s) == Tuple!(string, float)));
1243 assert(s[0] == "abc" && s[1] == 4.5);
1245 // https://issues.dlang.org/show_bug.cgi?id=15645
1246 Tuple!(int, short, bool, double) b;
1247 static assert(!__traits(compiles, b.slice!(2, 4)));
1251 Creates a hash of this `Tuple`.
1254 A `size_t` representing the hash of this `Tuple`.
1256 size_t toHash() const nothrow @safe
1259 static foreach (i, T; Types)
1261 static if (__traits(compiles, h = .hashOf(field[i])))
1262 const k = .hashOf(field[i]);
1265 // Workaround for when .hashOf is not both @safe and nothrow.
1266 static if (is(T : shared U, U) && __traits(compiles, (U* a) nothrow @safe => .hashOf(*a))
1267 && !__traits(hasMember, T, "toHash"))
1268 // BUG: Improperly casts away `shared`!
1269 const k = .hashOf(*(() @trusted => cast(U*) &field[i])());
1271 // BUG: Improperly casts away `shared`!
1272 const k = typeid(T).getHash((() @trusted => cast(const void*) &field[i])());
1277 // As in boost::hash_combine
1278 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine
1279 h ^= k + 0x9e3779b9 + (h << 6) + (h >>> 2);
1285 * Converts to string.
1288 * The string representation of this `Tuple`.
1290 string toString()() const
1292 import std.array : appender;
1293 auto app = appender!string();
1294 this.toString((const(char)[] chunk) => app ~= chunk);
1298 import std.format.spec : FormatSpec;
1301 * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`.
1303 * $(TABLE2 Formats supported by Tuple,
1304 * $(THEAD Format, Description)
1305 * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.))
1306 * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`$(COMMA) so
1307 * it may contain as many formats as the `Tuple` has fields.))
1308 * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format$(COMMA) that is applied
1309 * on all fields of the `Tuple`. The inner format must be compatible to all
1313 * sink = A `char` accepting delegate
1314 * fmt = A $(REF FormatSpec, std,format)
1316 void toString(DG)(scope DG sink) const
1318 auto f = FormatSpec!char();
1323 void toString(DG, Char)(scope DG sink, scope const ref FormatSpec!Char fmt) const
1325 import std.format : format, FormatException;
1326 import std.format.write : formattedWrite;
1327 import std.range : only;
1332 foreach (i, Type; Types)
1338 // TODO: Change this once formattedWrite() works for shared objects.
1339 static if (is(Type == class) && is(Type == shared))
1341 sink(Type.stringof);
1345 formattedWrite(sink, fmt.nested, this.field[i]);
1351 formattedWrite(sink, fmt.nested, staticMap!(sharedToString, this.expand));
1354 else if (fmt.spec == 's')
1356 enum header = Unqual!(typeof(this)).stringof ~ "(",
1360 foreach (i, Type; Types)
1366 // TODO: Change this once format() works for shared objects.
1367 static if (is(Type == class) && is(Type == shared))
1369 sink(Type.stringof);
1373 sink(format!("%(%s%)")(only(field[i])));
1380 const spec = fmt.spec;
1381 throw new FormatException(
1382 "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~
1383 Unqual!(typeof(this)).stringof ~ "', not '%" ~ spec ~ "'.");
1388 static if (Specs.length == 0) @safe unittest
1390 import std.format : format;
1392 Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ];
1395 assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`);
1397 // One Format for each individual component
1398 assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`);
1399 assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`);
1401 // One Format for all components
1402 assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`);
1405 assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`);
1409 static if (Specs.length == 0) @safe unittest
1411 import std.exception : assertThrown;
1412 import std.format : format, FormatException;
1414 // Error: %( %) missing.
1415 assertThrown!FormatException(
1416 format("%d, %f", tuple(1, 2.0)) == `1, 2.0`
1419 // Error: %( %| %) missing.
1420 assertThrown!FormatException(
1421 format("%d", tuple(1, 2)) == `1, 2`
1424 // Error: %d inadequate for double
1425 assertThrown!FormatException(
1426 format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0`
1435 Tuple!(int, int) point;
1436 // assign coordinates
1445 `Tuple` members can be named. It is legal to mix named and unnamed
1446 members. The method above is still applicable to all fields.
1450 alias Entry = Tuple!(int, "index", string, "value");
1454 assert(e[1] == "Hello");
1459 A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed
1460 fields, i.e. each naming imparts a separate type for the `Tuple`. Two
1461 `Tuple`s differing in naming only are still distinct, even though they
1462 might have the same structure.
1466 Tuple!(int, "x", int, "y") point1;
1467 Tuple!(int, int) point2;
1468 assert(!is(typeof(point1) == typeof(point2)));
1471 /// Use tuples as ranges
1474 import std.algorithm.iteration : sum;
1475 import std.range : only;
1476 auto t = tuple(1, 2);
1477 assert(t.expand.only.sum == 3);
1480 // https://issues.dlang.org/show_bug.cgi?id=4582
1483 static assert(!__traits(compiles, Tuple!(string, "id", int, "id")));
1484 static assert(!__traits(compiles, Tuple!(string, "str", int, "i", string, "str", float)));
1487 /// Concatenate tuples
1490 import std.meta : AliasSeq;
1491 auto t = tuple(1, "2") ~ tuple(ushort(42), true);
1492 static assert(is(t.Types == AliasSeq!(int, string, ushort, bool)));
1493 assert(t[1] == "2");
1495 assert(t[3] == true);
1498 // https://issues.dlang.org/show_bug.cgi?id=14637
1502 auto t = tuple!"foo"(1.0) ~ tuple!"bar"("3");
1503 static assert(is(t.Types == AliasSeq!(double, string)));
1504 static assert(t.fieldNames == tuple("foo", "bar"));
1505 assert(t.foo == 1.0);
1506 assert(t.bar == "3");
1509 // https://issues.dlang.org/show_bug.cgi?id=18824
1513 alias Type = Tuple!(int, string);
1515 auto t = tuple(2, "s");
1516 // Test opBinaryRight
1520 static assert(is(typeof(arr) == Type[]));
1523 static assert(is(typeof(c) == immutable(Type)[]));
1529 auto t = tuple!"foo"(1.0) ~ "3";
1530 static assert(is(t.Types == AliasSeq!(double, string)));
1531 assert(t.foo == 1.0);
1538 auto t = "2" ~ tuple!"foo"(1.0);
1539 static assert(is(t.Types == AliasSeq!(string, double)));
1540 assert(t.foo == 1.0);
1547 auto t = "2" ~ tuple!"foo"(1.0) ~ tuple(42, 3.0f) ~ real(1) ~ "a";
1548 static assert(is(t.Types == AliasSeq!(string, double, int, float, real, string)));
1549 assert(t.foo == 1.0);
1550 assert(t[0] == "2");
1551 assert(t[1] == 1.0);
1553 assert(t[3] == 3.0f);
1554 assert(t[4] == 1.0);
1555 assert(t[5] == "a");
1558 // ensure that concatenation of tuples with non-distinct fields is forbidden
1561 static assert(!__traits(compiles,
1562 tuple!("a")(0) ~ tuple!("a")("1")));
1563 static assert(!__traits(compiles,
1564 tuple!("a", "b")(0, 1) ~ tuple!("b", "a")("3", 1)));
1565 static assert(!__traits(compiles,
1566 tuple!("a")(0) ~ tuple!("b", "a")("3", 1)));
1567 static assert(!__traits(compiles,
1568 tuple!("a1", "a")(1.0, 0) ~ tuple!("a2", "a")("3", 0)));
1571 // Ensure that Tuple comparison with non-const opEquals works
1578 bool opEquals(Bad b)
1584 auto t = Tuple!(int, Bad, string)(1, Bad(1), "asdf");
1586 //Error: mutable method Bad.opEquals is not callable using a const object
1587 assert(t == AliasSeq!(1, Bad(1), "asdf"));
1590 // Ensure Tuple.toHash works
1593 Tuple!(int, int) point;
1594 assert(point.toHash == typeof(point).init.toHash);
1595 assert(tuple(1, 2) != point);
1596 assert(tuple(1, 2) == tuple(1, 2));
1598 assert(tuple(1, 2) != point);
1600 assert(tuple(1, 2) == point);
1603 @safe @betterC unittest
1605 auto t = tuple(1, 2);
1606 assert(t == tuple(1, 2));
1607 auto t3 = tuple(1, 'd');
1610 // https://issues.dlang.org/show_bug.cgi?id=20850
1611 // Assignment to enum tuple
1614 enum T : Tuple!(int*) { a = T(null) }
1619 // https://issues.dlang.org/show_bug.cgi?id=13663
1622 auto t = tuple(real.nan);
1632 float opCmp(S s) { return float.nan; }
1633 bool opEquals(S s) { return false; }
1636 auto t = tuple(S());
1642 // https://issues.dlang.org/show_bug.cgi?id=8015
1648 @property string toStr()
1659 Creates a copy of a $(LREF Tuple) with its fields in _reverse order.
1662 t = The `Tuple` to copy.
1667 auto reverse(T)(T t)
1670 import std.meta : Reverse;
1671 // @@@BUG@@@ Cannot be an internal function due to forward reference issues.
1673 // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple
1674 // return tuple(Reverse!(t.expand));
1676 ReverseTupleType!T result;
1677 auto tup = t.expand;
1678 result.expand = Reverse!tup;
1685 auto tup = tuple(1, "2");
1686 assert(tup.reverse == tuple("2", 1));
1689 /* Get a Tuple type with the reverse specification of Tuple T. */
1690 private template ReverseTupleType(T)
1693 static if (is(T : Tuple!A, A...))
1694 alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A);
1697 /* Reverse the Specs of a Tuple. */
1698 private template ReverseTupleSpecs(T...)
1700 static if (T.length > 1)
1702 static if (is(typeof(T[$-1]) : string))
1704 alias ReverseTupleSpecs = AliasSeq!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2]));
1708 alias ReverseTupleSpecs = AliasSeq!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1]));
1713 alias ReverseTupleSpecs = T;
1717 // ensure that internal Tuple unittests are compiled
1727 Tuple!(int, "a", int, "b") nosh;
1728 static assert(nosh.length == 2);
1731 assert(nosh.a == 5);
1732 assert(nosh.b == 6);
1735 Tuple!(short, double) b;
1736 static assert(b.length == 2);
1738 auto a = Tuple!(int, real)(b);
1739 assert(a[0] == 0 && a[1] == 5);
1740 a = Tuple!(int, real)(1, 2);
1741 assert(a[0] == 1 && a[1] == 2);
1742 auto c = Tuple!(int, "a", double, "b")(a);
1743 assert(c[0] == 1 && c[1] == 2);
1746 Tuple!(int, real) nosh;
1749 assert(nosh[0] == 5 && nosh[1] == 0);
1750 assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string);
1751 Tuple!(int, int) yessh;
1756 Tuple!(int, shared A) nosh;
1758 assert(nosh[0] == 5 && nosh[1] is null);
1759 assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))");
1762 Tuple!(int, string) t;
1765 assert(t[0] == 10 && t[1] == "str");
1766 assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string);
1769 Tuple!(int, "a", double, "b") x;
1770 static assert(x.a.offsetof == x[0].offsetof);
1771 static assert(x.b.offsetof == x[1].offsetof);
1774 assert(x[0] == 5 && x[1] == 4.5);
1775 assert(x.a == 5 && x.b == 4.5);
1779 Tuple!(int, real) t;
1780 static assert(is(typeof(t[0]) == int));
1781 static assert(is(typeof(t[1]) == real));
1786 assert(*p0 == t[0]);
1787 assert(*p1 == t[1]);
1791 Tuple!(int, "x", real, "y", double, "z", string) t;
1796 auto a = t.slice!(0, 3);
1797 assert(a.length == 3);
1801 auto b = t.slice!(2, 4);
1802 assert(b.length == 2);
1804 assert(b[1] == t[3]);
1808 Tuple!(Tuple!(int, real), Tuple!(string, "s")) t;
1809 static assert(is(typeof(t[0]) == Tuple!(int, real)));
1810 static assert(is(typeof(t[1]) == Tuple!(string, "s")));
1811 static assert(is(typeof(t[0][0]) == int));
1812 static assert(is(typeof(t[0][1]) == real));
1813 static assert(is(typeof(t[1].s) == string));
1814 t[0] = tuple(10, 20.0L);
1816 assert(t[0][0] == 10);
1817 assert(t[0][1] == 20.0L);
1818 assert(t[1].s == "abc");
1825 this(this) { ++count; }
1826 ~this() { --count; }
1827 void opAssign(S rhs) { count = rhs.count; }
1830 Tuple!(S, S) ssCopy = ss;
1831 assert(ssCopy[0].count == 1);
1832 assert(ssCopy[1].count == 1);
1833 ssCopy[1] = ssCopy[0];
1834 assert(ssCopy[1].count == 2);
1836 // https://issues.dlang.org/show_bug.cgi?id=2800
1840 Tuple!(int, int) _front;
1841 @property ref Tuple!(int, int) front() return { return _front; }
1842 @property bool empty() { return _front[0] >= 10; }
1843 void popFront() { ++_front[0]; }
1847 static assert(is(typeof(a) == Tuple!(int, int)));
1848 assert(0 <= a[0] && a[0] < 10);
1852 // Construction with compatible elements
1854 auto t1 = Tuple!(int, double)(1, 1);
1856 // https://issues.dlang.org/show_bug.cgi?id=8702
1857 auto t8702a = tuple(tuple(1));
1858 auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1));
1860 // Construction with compatible tuple
1865 Tuple!(int, "a", double, "b") y = x;
1869 static assert(!__traits(compiles, Tuple!(int, int)(y)));
1871 // https://issues.dlang.org/show_bug.cgi?id=6275
1875 alias T = Tuple!(const(int));
1878 // https://issues.dlang.org/show_bug.cgi?id=9431
1880 alias T = Tuple!(int[1][]);
1883 // https://issues.dlang.org/show_bug.cgi?id=7666
1885 auto tup = tuple(1, "2");
1886 assert(tup.reverse == tuple("2", 1));
1889 Tuple!(int, "x", string, "y") tup = tuple(1, "2");
1890 auto rev = tup.reverse;
1891 assert(rev == tuple("2", 1));
1892 assert(rev.x == 1 && rev.y == "2");
1895 Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup;
1896 tup = tuple('a', 'b', 3, "4", 'c', cast(byte) 0x0D, 0.00);
1897 auto rev = tup.reverse;
1898 assert(rev == tuple(0.00, cast(byte) 0x0D, 'c', "4", 3, 'b', 'a'));
1899 assert(rev.x == 3 && rev.y == "4");
1906 struct Equ1 { bool opEquals(Equ1) { return true; } }
1907 auto tm1 = tuple(Equ1.init);
1908 const tc1 = tuple(Equ1.init);
1909 static assert( is(typeof(tm1 == tm1)));
1910 static assert(!is(typeof(tm1 == tc1)));
1911 static assert(!is(typeof(tc1 == tm1)));
1912 static assert(!is(typeof(tc1 == tc1)));
1914 struct Equ2 { bool opEquals(const Equ2) const { return true; } }
1915 auto tm2 = tuple(Equ2.init);
1916 const tc2 = tuple(Equ2.init);
1917 static assert( is(typeof(tm2 == tm2)));
1918 static assert( is(typeof(tm2 == tc2)));
1919 static assert( is(typeof(tc2 == tm2)));
1920 static assert( is(typeof(tc2 == tc2)));
1922 // https://issues.dlang.org/show_bug.cgi?id=8686
1923 struct Equ3 { bool opEquals(T)(T) { return true; } }
1924 auto tm3 = tuple(Equ3.init);
1925 const tc3 = tuple(Equ3.init);
1926 static assert( is(typeof(tm3 == tm3)));
1927 static assert( is(typeof(tm3 == tc3)));
1928 static assert(!is(typeof(tc3 == tm3)));
1929 static assert(!is(typeof(tc3 == tc3)));
1931 struct Equ4 { bool opEquals(T)(T) const { return true; } }
1932 auto tm4 = tuple(Equ4.init);
1933 const tc4 = tuple(Equ4.init);
1934 static assert( is(typeof(tm4 == tm4)));
1935 static assert( is(typeof(tm4 == tc4)));
1936 static assert( is(typeof(tc4 == tm4)));
1937 static assert( is(typeof(tc4 == tc4)));
1941 struct Cmp1 { int opCmp(Cmp1) { return 0; } }
1942 auto tm1 = tuple(Cmp1.init);
1943 const tc1 = tuple(Cmp1.init);
1944 static assert( is(typeof(tm1 < tm1)));
1945 static assert(!is(typeof(tm1 < tc1)));
1946 static assert(!is(typeof(tc1 < tm1)));
1947 static assert(!is(typeof(tc1 < tc1)));
1949 struct Cmp2 { int opCmp(const Cmp2) const { return 0; } }
1950 auto tm2 = tuple(Cmp2.init);
1951 const tc2 = tuple(Cmp2.init);
1952 static assert( is(typeof(tm2 < tm2)));
1953 static assert( is(typeof(tm2 < tc2)));
1954 static assert( is(typeof(tc2 < tm2)));
1955 static assert( is(typeof(tc2 < tc2)));
1957 struct Cmp3 { int opCmp(T)(T) { return 0; } }
1958 auto tm3 = tuple(Cmp3.init);
1959 const tc3 = tuple(Cmp3.init);
1960 static assert( is(typeof(tm3 < tm3)));
1961 static assert( is(typeof(tm3 < tc3)));
1962 static assert(!is(typeof(tc3 < tm3)));
1963 static assert(!is(typeof(tc3 < tc3)));
1965 struct Cmp4 { int opCmp(T)(T) const { return 0; } }
1966 auto tm4 = tuple(Cmp4.init);
1967 const tc4 = tuple(Cmp4.init);
1968 static assert( is(typeof(tm4 < tm4)));
1969 static assert( is(typeof(tm4 < tc4)));
1970 static assert( is(typeof(tc4 < tm4)));
1971 static assert( is(typeof(tc4 < tc4)));
1973 // https://issues.dlang.org/show_bug.cgi?id=14890
1974 static void test14890(inout int[] dummy)
1976 alias V = Tuple!(int, int);
1981 inout V wv; // OK <- NG
1982 inout const V wcv; // OK <- NG
1984 static foreach (v1; AliasSeq!(mv, cv, iv, wv, wcv))
1985 static foreach (v2; AliasSeq!(mv, cv, iv, wv, wcv))
1991 int[2] ints = [ 1, 2 ];
1992 Tuple!(int, int) t = ints;
1993 assert(t[0] == 1 && t[1] == 2);
1994 Tuple!(long, uint) t2 = ints;
1995 assert(t2[0] == 1 && t2[1] == 2);
2000 auto t1 = Tuple!(int, "x", string, "y")(1, "a");
2002 assert(t1.y == "a");
2003 void foo(Tuple!(int, string) t2) {}
2006 Tuple!(int, int)[] arr;
2007 arr ~= tuple(10, 20); // OK
2008 arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK
2010 static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) ==
2011 typeof(Tuple!(int, string ).tupleof)));
2015 // https://issues.dlang.org/show_bug.cgi?id=10686
2016 immutable Tuple!(int) t1;
2017 auto r1 = t1[0]; // OK
2018 immutable Tuple!(int, "x") t2;
2019 auto r2 = t2[0]; // error
2023 import std.exception : assertCTFEable;
2025 // https://issues.dlang.org/show_bug.cgi?id=10218
2029 t = tuple(2); // assignment
2035 Tuple!(immutable(Foo)[]) a;
2040 //Test non-assignable
2045 alias IS = immutable S;
2046 static assert(!isAssignable!IS);
2050 alias TIS = Tuple!IS;
2054 alias TISIS = Tuple!(IS, IS);
2055 TISIS d = tuple(s, s);
2057 TISIS e = TISIS(ss);
2060 // https://issues.dlang.org/show_bug.cgi?id=9819
2063 alias T = Tuple!(int, "x", double, "foo");
2064 static assert(T.fieldNames[0] == "x");
2065 static assert(T.fieldNames[1] == "foo");
2067 alias Fields = Tuple!(int, "id", string, float);
2068 static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
2071 // https://issues.dlang.org/show_bug.cgi?id=13837
2074 // New behaviour, named arguments.
2076 typeof(tuple!("x")(1)) == Tuple!(int, "x")));
2078 typeof(tuple!("x")(1.0)) == Tuple!(double, "x")));
2080 typeof(tuple!("x")("foo")) == Tuple!(string, "x")));
2082 typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y")));
2084 auto a = tuple!("a", "b", "c")("1", 2, 3.0f);
2085 static assert(is(typeof(a.a) == string));
2086 static assert(is(typeof(a.b) == int));
2087 static assert(is(typeof(a.c) == float));
2089 // Old behaviour, but with explicit type parameters.
2091 typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double)));
2093 typeof(tuple!(const int)(1)) == Tuple!(const int)));
2095 typeof(tuple()) == Tuple!()));
2097 // Nonsensical behaviour
2098 static assert(!__traits(compiles, tuple!(1)(2)));
2099 static assert(!__traits(compiles, tuple!("x")(1, 2)));
2100 static assert(!__traits(compiles, tuple!("x", "y")(1)));
2101 static assert(!__traits(compiles, tuple!("x")()));
2102 static assert(!__traits(compiles, tuple!("x", int)(2)));
2107 class C { override size_t toHash() const nothrow @safe { return 0; } }
2108 Tuple!(Rebindable!(const C)) a;
2113 @nogc @safe unittest
2115 alias T = Tuple!(string, "s");
2122 import std.format : format, FormatException;
2123 import std.exception : assertThrown;
2125 //enum tupStr = tuple(1, 1.0).toString; // toString is *impure*.
2126 //static assert(tupStr == `Tuple!(int, double)(1, 1)`);
2129 // https://issues.dlang.org/show_bug.cgi?id=17803, parte uno
2132 auto a = tuple(3, "foo");
2133 assert(__traits(compiles, { a = (a = a); }));
2138 Tuple!(int[]) a, b, c;
2139 a = tuple([0, 1, 2]);
2141 assert(a[0].length == b[0].length && b[0].length == c[0].length);
2142 assert(a[0].ptr == b[0].ptr && b[0].ptr == c[0].ptr);
2146 Constructs a $(LREF Tuple) object instantiated and initialized according to
2147 the given arguments.
2150 Names = An optional list of strings naming each successive field of the `Tuple`
2151 or a list of types that the elements are being casted to.
2152 For a list of names,
2153 each name matches up with the corresponding field given by `Args`.
2154 A name does not have to be provided for every field, but as
2155 the names must proceed in order, it is not possible to skip
2156 one field and name the next after it.
2157 For a list of types,
2158 there must be exactly as many types as parameters.
2160 template tuple(Names...)
2164 args = Values to initialize the `Tuple` with. The `Tuple`'s type will
2165 be inferred from the types of the values given.
2168 A new `Tuple` with its type inferred from the arguments given.
2170 auto tuple(Args...)(Args args)
2172 static if (Names.length == 0)
2174 // No specified names, just infer types from Args...
2175 return Tuple!Args(args);
2177 else static if (!is(typeof(Names[0]) : string))
2179 // Names[0] isn't a string, must be explicit types.
2180 return Tuple!Names(args);
2184 // Names[0] is a string, so must be specifying names.
2185 static assert(Names.length == Args.length,
2186 "Insufficient number of names given.");
2188 // Interleave(a, b).and(c, d) == (a, c, b, d)
2189 // This is to get the interleaving of types and names for Tuple
2190 // e.g. Tuple!(int, "x", string, "y")
2191 template Interleave(A...)
2193 template and(B...) if (B.length == 1)
2195 alias and = AliasSeq!(A[0], B[0]);
2198 template and(B...) if (B.length != 1)
2200 alias and = AliasSeq!(A[0], B[0],
2201 Interleave!(A[1..$]).and!(B[1..$]));
2204 return Tuple!(Interleave!(Args).and!(Names))(args);
2212 auto value = tuple(5, 6.7, "hello");
2213 assert(value[0] == 5);
2214 assert(value[1] == 6.7);
2215 assert(value[2] == "hello");
2217 // Field names can be provided.
2218 auto entry = tuple!("index", "value")(4, "Hello");
2219 assert(entry.index == 4);
2220 assert(entry.value == "Hello");
2224 Returns `true` if and only if `T` is an instance of `std.typecons.Tuple`.
2227 T = The type to check.
2230 true if `T` is a `Tuple` type, false otherwise.
2232 enum isTuple(T) = __traits(compiles,
2234 void f(Specs...)(Tuple!Specs tup) {}
2241 static assert(isTuple!(Tuple!()));
2242 static assert(isTuple!(Tuple!(int)));
2243 static assert(isTuple!(Tuple!(int, real, string)));
2244 static assert(isTuple!(Tuple!(int, "x", real, "y")));
2245 static assert(isTuple!(Tuple!(int, Tuple!(real), string)));
2250 static assert(isTuple!(const Tuple!(int)));
2251 static assert(isTuple!(immutable Tuple!(int)));
2253 static assert(!isTuple!(int));
2254 static assert(!isTuple!(const int));
2257 static assert(!isTuple!(S));
2260 // used by both Rebindable and UnqualRef
2261 private mixin template RebindableCommon(T, U, alias This)
2262 if (is(T == class) || is(T == interface) || isAssociativeArray!T)
2270 void opAssign(return scope T another) pure nothrow @nogc
2272 // If `T` defines `opCast` we must infer the safety
2273 static if (hasMember!(T, "opCast"))
2275 // This will allow the compiler to infer the safety of `T.opCast!U`
2276 // without generating any runtime cost
2277 if (false) { stripped = cast(U) another; }
2279 () @trusted { stripped = cast(U) another; }();
2282 void opAssign(typeof(this) another) @trusted pure nothrow @nogc
2284 stripped = another.stripped;
2287 static if (is(T == const U) && is(T == const shared U))
2289 // safely assign immutable to const / const shared
2290 void opAssign(This!(immutable U) another) @trusted pure nothrow @nogc
2292 stripped = another.stripped;
2296 this(T initializer) pure nothrow @nogc
2298 // Infer safety from opAssign
2299 opAssign(initializer);
2302 @property inout(T) get() @trusted pure nothrow @nogc return scope inout
2307 bool opEquals()(auto ref const(typeof(this)) rhs) const
2309 // Must forward explicitly because 'stripped' is part of a union.
2310 // The necessary 'toHash' is forwarded to the class via alias this.
2311 return stripped == rhs.stripped;
2314 bool opEquals(const(U) rhs) const
2316 return stripped == rhs;
2323 `Rebindable!(T)` is a simple, efficient wrapper that behaves just
2324 like an object of type `T`, except that you can reassign it to
2325 refer to another object. For completeness, `Rebindable!(T)` aliases
2326 itself away to `T` if `T` is a non-const object type.
2328 You may want to use `Rebindable` when you want to have mutable
2329 storage referring to `const` objects, for example an array of
2330 references that must be sorted in place. `Rebindable` does not
2331 break the soundness of D's type system and does not incur any of the
2332 risks usually associated with `cast`.
2335 T = An object, interface, array slice type, or associative array type.
2337 template Rebindable(T)
2338 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2340 static if (is(T == const U, U) || is(T == immutable U, U))
2342 static if (isDynamicArray!T)
2344 import std.range.primitives : ElementEncodingType;
2345 alias Rebindable = const(ElementEncodingType!T)[];
2351 mixin RebindableCommon!(T, U, Rebindable);
2357 alias Rebindable = T;
2361 ///Regular `const` object references cannot be reassigned.
2364 class Widget { int x; int y() @safe const { return x; } }
2365 const a = new Widget;
2368 // error! can't modify const a
2370 // error! can't modify const a
2375 However, `Rebindable!(Widget)` does allow reassignment,
2376 while otherwise behaving exactly like a $(D const Widget).
2380 class Widget { int x; int y() const @safe { return x; } }
2381 auto a = Rebindable!(const Widget)(new Widget);
2384 // error! can't modify const a
2390 // https://issues.dlang.org/show_bug.cgi?id=16054
2393 Rebindable!(immutable Object) r;
2394 static assert(__traits(compiles, r.get()));
2395 static assert(!__traits(compiles, &r.get()));
2402 override size_t toHash() const nothrow @trusted { return 42; }
2404 Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash();
2405 assert(a.toHash() == 42, "Rebindable!A should offer toHash()"
2406 ~ " by forwarding to A.toHash().");
2409 // https://issues.dlang.org/show_bug.cgi?id=18615
2410 // Rebindable!A should use A.opEqualsa
2416 override bool opEquals(Object rhsObj)
2418 if (auto rhs = cast(const(CustomOpEq)) rhsObj)
2419 return this.x == rhs.x;
2424 CustomOpEq a = new CustomOpEq();
2425 CustomOpEq b = new CustomOpEq();
2427 assert(a == b, "a.x == b.x should be true (0 == 0).");
2429 Rebindable!(const(CustomOpEq)) ra = a;
2430 Rebindable!(const(CustomOpEq)) rb = b;
2432 assert(ra == rb, "Rebindable should use CustomOpEq's opEquals, not 'is'.");
2433 assert(ra == b, "Rebindable!(someQualifier(A)) should be comparable"
2434 ~ " against const(A) via A.opEquals.");
2435 assert(a == rb, "Rebindable!(someQualifier(A)) should be comparable"
2436 ~ " against const(A) via A.opEquals.");
2440 assert(ra != b, "Rebindable!(someQualifier(A)) should be comparable"
2441 ~ " against const(A) via A.opEquals.");
2442 assert(a != rb, "Rebindable!(someQualifier(A)) should be comparable"
2443 ~ " against const(A) via A.opEquals.");
2445 Rebindable!(const(Object)) o1 = new Object();
2446 Rebindable!(const(Object)) o2 = new Object();
2448 assert(o1 == o1, "When the class doesn't provide its own opEquals,"
2449 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2450 assert(o1 != o2, "When the class doesn't provide its own opEquals,"
2451 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2452 assert(o1 != new Object(), "Rebindable!(const(Object)) should be"
2453 ~ " comparable against Object itself and use Object.opEquals.");
2456 // https://issues.dlang.org/show_bug.cgi?id=18755
2461 auto opCast(T)() @system immutable pure nothrow
2463 *(cast(uint*) 0xdeadbeef) = 0xcafebabe;
2468 static assert(!__traits(compiles, () @safe {
2469 auto r = Rebindable!(immutable Foo)(new Foo);
2471 static assert(__traits(compiles, () @system {
2472 auto r = Rebindable!(immutable Foo)(new Foo);
2477 Convenience function for creating a `Rebindable` using automatic type
2481 obj = A reference to an object, interface, associative array, or an array slice
2482 to initialize the `Rebindable` with.
2485 A newly constructed `Rebindable` initialized with the given reference.
2487 Rebindable!T rebindable(T)(T obj)
2488 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2501 this(int p) { payload = p; }
2505 auto c2 = c.rebindable;
2506 assert(c2.payload == 1);
2507 // passing Rebindable to rebindable
2511 assert(c2.payload == 2);
2514 assert(c3.payload == 2);
2518 This function simply returns the `Rebindable` object passed in. It's useful
2519 in generic programming cases when a given object may be either a regular
2520 `class` or a `Rebindable`.
2523 obj = An instance of Rebindable!T.
2526 `obj` without any modification.
2528 Rebindable!T rebindable(T)(Rebindable!T obj)
2533 // TODO: remove me once the rebindable overloads have been joined
2540 this(int p) { payload = p; }
2544 auto c2 = c.rebindable;
2545 assert(c2.payload == 1);
2546 // passing Rebindable to rebindable
2548 assert(c2.payload == 1);
2553 interface CI { int foo() const; }
2555 int foo() const { return 42; }
2556 @property int bar() const { return 23; }
2558 Rebindable!(C) obj0;
2559 static assert(is(typeof(obj0) == C));
2561 Rebindable!(const(C)) obj1;
2562 static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof);
2563 static assert(is(typeof(obj1.stripped) == C));
2565 assert(obj1.get !is null);
2566 obj1 = new const(C);
2567 assert(obj1.get !is null);
2569 Rebindable!(immutable(C)) obj2;
2570 static assert(is(typeof(obj2.get) == immutable(C)));
2571 static assert(is(typeof(obj2.stripped) == C));
2572 obj2 = new immutable(C);
2573 assert(obj1.get !is null);
2576 assert(obj2.foo() == 42);
2577 assert(obj2.bar == 23);
2579 interface I { final int foo() const { return 42; } }
2580 Rebindable!(I) obj3;
2581 static assert(is(typeof(obj3) == I));
2583 Rebindable!(const I) obj4;
2584 static assert(is(typeof(obj4.get) == const I));
2585 static assert(is(typeof(obj4.stripped) == I));
2586 static assert(is(typeof(obj4.foo()) == int));
2587 obj4 = new class I {};
2589 Rebindable!(immutable C) obj5i;
2590 Rebindable!(const C) obj5c;
2594 static assert(!__traits(compiles, obj5i = obj5c));
2596 // Test the convenience functions.
2597 auto obj5convenience = rebindable(obj5i);
2598 assert(obj5convenience is obj5i);
2600 auto obj6 = rebindable(new immutable(C));
2601 static assert(is(typeof(obj6) == Rebindable!(immutable C)));
2602 assert(obj6.foo() == 42);
2604 auto obj7 = rebindable(new C);
2605 CI interface1 = obj7;
2606 auto interfaceRebind1 = rebindable(interface1);
2607 assert(interfaceRebind1.foo() == 42);
2609 const interface2 = interface1;
2610 auto interfaceRebind2 = rebindable(interface2);
2611 assert(interfaceRebind2.foo() == 42);
2613 auto arr = [1,2,3,4,5];
2614 const arrConst = arr;
2615 assert(rebindable(arr) == arr);
2616 assert(rebindable(arrConst) == arr);
2618 // https://issues.dlang.org/show_bug.cgi?id=7654
2619 immutable(char[]) s7654;
2620 Rebindable!(typeof(s7654)) r7654 = s7654;
2622 static foreach (T; AliasSeq!(char, wchar, char, int))
2624 static assert(is(Rebindable!(immutable(T[])) == immutable(T)[]));
2625 static assert(is(Rebindable!(const(T[])) == const(T)[]));
2626 static assert(is(Rebindable!(T[]) == T[]));
2629 // https://issues.dlang.org/show_bug.cgi?id=12046
2630 static assert(!__traits(compiles, Rebindable!(int[1])));
2631 static assert(!__traits(compiles, Rebindable!(const int[1])));
2633 // Pull request 3341
2634 Rebindable!(immutable int[int]) pr3341 = [123:345];
2635 assert(pr3341[123] == 345);
2636 immutable int[int] pr3341_aa = [321:543];
2638 assert(pr3341[321] == 543);
2639 assert(rebindable(pr3341_aa)[321] == 543);
2643 Similar to `Rebindable!(T)` but strips all qualifiers from the reference as
2644 opposed to just constness / immutability. Primary intended use case is with
2645 shared (having thread-local reference to shared class data)
2648 T = A class or interface type.
2650 template UnqualRef(T)
2651 if (is(T == class) || is(T == interface))
2653 static if (is(T == immutable U, U)
2654 || is(T == const shared U, U)
2655 || is(T == const U, U)
2656 || is(T == shared U, U))
2660 mixin RebindableCommon!(T, U, UnqualRef);
2665 alias UnqualRef = T;
2674 static shared(Data) a;
2675 static UnqualRef!(shared Data) b;
2679 auto thread = new core.thread.Thread({
2680 a = new shared Data();
2681 b = new shared Data();
2694 alias T = UnqualRef!(const shared C);
2695 static assert(is(typeof(T.stripped) == C));
2701 Order the provided members to minimize size while preserving alignment.
2702 Alignment is not always optimal for 80-bit reals, nor for structs declared
2706 E = A list of the types to be aligned, representing fields
2707 of an aggregate such as a `struct` or `class`.
2709 names = The names of the fields that are to be aligned.
2712 A string to be mixed in to an aggregate, such as a `struct` or `class`.
2714 string alignForSize(E...)(const char[][] names...)
2716 // Sort all of the members by .alignof.
2717 // BUG: Alignment is not always optimal for align(1) structs
2718 // or 80-bit reals or 64-bit primitives on x86.
2719 // TRICK: Use the fact that .alignof is always a power of 2,
2720 // and maximum 16 on extant systems. Thus, we can perform
2721 // a very limited radix sort.
2722 // Contains the members with .alignof = 64,32,16,8,4,2,1
2724 assert(E.length == names.length,
2725 "alignForSize: There should be as many member names as the types");
2727 string[7] declaration = ["", "", "", "", "", "", ""];
2732 auto k = a >= 64? 0 : a >= 32? 1 : a >= 16? 2 : a >= 8? 3 : a >= 4? 4 : a >= 2? 5 : 6;
2733 declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n";
2737 foreach (decl; declaration)
2746 mixin(alignForSize!(byte[6], double)(["name", "height"]));
2752 enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w");
2753 struct Foo { int x; }
2754 enum y = alignForSize!(ubyte, Foo, double)("x", "y", "z");
2756 enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
2757 enum passNormalY = y == "double z;\nFoo y;\nubyte x;\n";
2759 enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
2760 enum passAbnormalY = y == "Foo y;\ndouble z;\nubyte x;\n";
2761 // ^ blame https://issues.dlang.org/show_bug.cgi?id=231
2763 static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof);
2764 static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof);
2767 // https://issues.dlang.org/show_bug.cgi?id=12914
2770 immutable string[] fieldNames = ["x", "y"];
2773 mixin(alignForSize!(byte, int)(fieldNames));
2778 Defines a value paired with a distinctive "null" state that denotes
2779 the absence of a value. If default constructed, a $(D
2780 Nullable!T) object starts in the null state. Assigning it renders it
2781 non-null. Calling `nullify` can nullify it again.
2783 Practically `Nullable!T` stores a `T` and a `bool`.
2786 $(LREF apply), an alternative way to use the payload.
2790 private union DontCallDestructorT
2792 import std.traits : hasIndirections;
2793 static if (hasIndirections!T)
2799 private DontCallDestructorT _value = DontCallDestructorT.init;
2801 private bool _isNull = true;
2804 * Constructor initializing `this` with `value`.
2807 * value = The value to initialize this `Nullable` with.
2809 this(inout T value) inout
2811 _value.payload = value;
2815 static if (hasElaborateDestructor!T)
2821 destroy(_value.payload);
2826 static if (__traits(hasPostblit, T))
2831 _value.payload.__xpostblit();
2834 else static if (__traits(hasCopyConstructor, T))
2836 this(ref return scope inout Nullable!T rhs) inout
2838 _isNull = rhs._isNull;
2840 _value.payload = rhs._value.payload;
2842 _value = DontCallDestructorT.init;
2847 * If they are both null, then they are equal. If one is null and the other
2848 * is not, then they are not equal. If they are both non-null, then they are
2849 * equal if their values are equal.
2851 bool opEquals(this This, Rhs)(auto ref Rhs rhs)
2852 if (!is(CommonType!(This, Rhs) == void))
2854 static if (is(This == Rhs))
2860 return _value.payload == rhs._value.payload;
2864 alias Common = CommonType!(This, Rhs);
2865 return cast(Common) this == cast(Common) rhs;
2870 bool opEquals(this This, Rhs)(auto ref Rhs rhs)
2871 if (is(CommonType!(This, Rhs) == void) && is(typeof(this.get == rhs)))
2873 return _isNull ? false : rhs == _value.payload;
2880 Nullable!int a = 42;
2881 Nullable!int b = 42;
2882 Nullable!int c = 27;
2884 assert(empty == empty);
2885 assert(empty == Nullable!int.init);
2893 assert(empty != 42);
2901 immutable Nullable!int a = 42;
2902 Nullable!int b = 42;
2903 immutable Nullable!int c = 29;
2904 Nullable!int d = 29;
2915 assert(a == const Nullable!int(42));
2916 assert(a != Nullable!int(29));
2919 // https://issues.dlang.org/show_bug.cgi?id=17482
2922 import std.variant : Variant;
2923 Nullable!Variant a = Variant(12);
2929 size_t toHash() const @safe nothrow
2931 static if (__traits(compiles, .hashOf(_value.payload)))
2932 return _isNull ? 0 : .hashOf(_value.payload);
2934 // Workaround for when .hashOf is not both @safe and nothrow.
2935 return _isNull ? 0 : typeid(T).getHash(&_value.payload);
2939 * Gives the string `"Nullable.null"` if `isNull` is `true`. Otherwise, the
2940 * result is equivalent to calling $(REF formattedWrite, std,format) on the
2944 * writer = A `char` accepting
2945 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
2946 * fmt = A $(REF FormatSpec, std,format) which is used to represent
2947 * the value if this Nullable is not null
2949 * A `string` if `writer` and `fmt` are not set; `void` otherwise.
2953 import std.array : appender;
2954 auto app = appender!string();
2955 auto spec = singleSpec("%s");
2956 toString(app, spec);
2961 string toString() const
2963 import std.array : appender;
2964 auto app = appender!string();
2965 auto spec = singleSpec("%s");
2966 toString(app, spec);
2971 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt)
2972 if (isOutputRange!(W, char))
2974 import std.range.primitives : put;
2976 put(writer, "Nullable.null");
2978 formatValue(writer, _value.payload, fmt);
2982 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) const
2983 if (isOutputRange!(W, char))
2985 import std.range.primitives : put;
2987 put(writer, "Nullable.null");
2989 formatValue(writer, _value.payload, fmt);
2993 * Check if `this` is in the null state.
2996 * true $(B iff) `this` is in the null state, otherwise false.
2998 @property bool isNull() const @safe pure nothrow
3013 // https://issues.dlang.org/show_bug.cgi?id=14940
3016 import std.array : appender;
3017 import std.format.write : formattedWrite;
3019 auto app = appender!string();
3021 formattedWrite(app, "%s", a);
3022 assert(app.data == "1");
3025 // https://issues.dlang.org/show_bug.cgi?id=19799
3028 import std.format : format;
3030 const Nullable!string a = const(Nullable!string)();
3036 * Forces `this` to the null state.
3040 static if (is(T == class) || is(T == interface))
3041 _value.payload = null;
3043 .destroy(_value.payload);
3050 Nullable!int ni = 0;
3058 * Assigns `value` to the internally-held state. If the assignment
3059 * succeeds, `this` becomes non-null.
3062 * value = A value of type `T` to assign to this `Nullable`.
3064 Nullable opAssign()(T value)
3066 import std.algorithm.mutation : moveEmplace, move;
3068 // the lifetime of the value in copy shall be managed by
3069 // this Nullable, so we must avoid calling its destructor.
3070 auto copy = DontCallDestructorT(value);
3074 // trusted since payload is known to be uninitialized.
3075 () @trusted { moveEmplace(copy.payload, _value.payload); }();
3079 move(copy.payload, _value.payload);
3086 * If this `Nullable` wraps a type that already has a null value
3087 * (such as a pointer), then assigning the null value to this
3088 * `Nullable` is no different than assigning any other value of
3089 * type `T`, and the resulting code will look very strange. It
3090 * is strongly recommended that this be avoided by instead using
3091 * the version of `Nullable` that takes an additional `nullValue`
3092 * template argument.
3097 Nullable!(int*) npi;
3102 assert(!npi.isNull);
3106 * Gets the value if not null. If `this` is in the null state, and the optional
3107 * parameter `fallback` was provided, it will be returned. Without `fallback`,
3108 * calling `get` with a null state is invalid.
3110 * When the fallback type is different from the Nullable type, `get(T)` returns
3114 * fallback = the value to return in case the `Nullable` is null.
3117 * The value held internally by this `Nullable`.
3119 @property ref inout(T) get() inout @safe pure nothrow
3121 enum message = "Called `get' on null Nullable!" ~ T.stringof ~ ".";
3122 assert(!isNull, message);
3123 return _value.payload;
3127 @property inout(T) get()(inout(T) fallback) inout
3129 return isNull ? fallback : _value.payload;
3133 @property auto get(U)(inout(U) fallback) inout
3135 return isNull ? fallback : _value.payload;
3138 /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions.
3139 alias empty = isNull;
3142 alias popFront = nullify;
3145 alias popBack = nullify;
3148 @property ref inout(T) front() inout @safe pure nothrow
3157 @property inout(typeof(this)) save() inout
3163 inout(typeof(this)) opIndex(size_t[2] dim) inout
3164 in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
3166 return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
3169 size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
3175 @property size_t length() const @safe pure nothrow
3181 alias opDollar(size_t dim : 0) = length;
3184 ref inout(T) opIndex(size_t index) inout @safe pure nothrow
3191 * Converts `Nullable` to a range. Works even when the contained type is `immutable`.
3193 auto opSlice(this This)()
3195 static struct NullableRange
3199 // starts out true if value is null
3200 private bool empty_;
3202 @property bool empty() const @safe pure nothrow
3207 void popFront() @safe pure nothrow
3212 alias popBack = popFront;
3214 @property ref inout(typeof(value.get())) front() inout @safe pure nothrow
3221 @property inout(typeof(this)) save() inout
3226 size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
3231 @property size_t length() const @safe pure nothrow
3236 alias opDollar(size_t dim : 0) = length;
3238 ref inout(typeof(value.get())) opIndex(size_t index) inout @safe pure nothrow
3244 inout(typeof(this)) opIndex(size_t[2] dim) inout
3245 in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
3247 return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
3250 auto opIndex() inout
3255 return NullableRange(this, isNull);
3260 auto nullable(T)(T t)
3262 return Nullable!T(t);
3268 struct CustomerRecord
3275 Nullable!CustomerRecord getByName(string name)
3277 //A bunch of hairy stuff
3279 return Nullable!CustomerRecord.init;
3282 auto queryResult = getByName("Doe, John");
3283 if (!queryResult.isNull)
3285 //Process Mr. Doe's customer record
3286 auto address = queryResult.get.address;
3287 auto customerNum = queryResult.get.customerNum;
3289 //Do some things with this customer's info
3293 //Add the customer to the database
3300 import std.exception : assertThrown;
3302 auto a = 42.nullable;
3304 assert(a.get == 42);
3308 assertThrown!Throwable(a.get);
3313 import std.algorithm.iteration : each, joiner;
3314 Nullable!int a = 42;
3316 // Add each value to an array
3318 a.each!((n) => arr ~= n);
3319 assert(arr == [42]);
3320 b.each!((n) => arr ~= n);
3321 assert(arr == [42]);
3322 // Take first value from an array of Nullables
3323 Nullable!int[] c = new Nullable!int[](10);
3324 c[7] = Nullable!int(42);
3325 assert(c.joiner.front == 42);
3329 auto k = Nullable!int(74);
3336 static int f(scope const Nullable!int x) {
3337 return x.isNull ? 42 : x.get;
3348 import std.exception : assertThrown;
3350 static struct S { int x; }
3356 assert(s.get != S(0));
3358 assert(s.get.x == 9190);
3360 assertThrown!Throwable(s.get.x = 9441);
3364 // Ensure Nullable can be used in pure/nothrow/@safe environment.
3365 function() @safe pure nothrow
3378 // Ensure Nullable can be used when the value is not pure/nothrow/@safe
3382 this(this) @system {}
3389 assert(s.get.x == 5);
3394 // https://issues.dlang.org/show_bug.cgi?id=9404
3397 alias N = Nullable!int;
3402 b = a; // `N b = a;` works fine
3409 //Check nullable immutable is constructable
3411 auto a1 = Nullable!(immutable int)();
3412 auto a2 = Nullable!(immutable int)(1);
3415 //Check immutable nullable is constructable
3417 auto a1 = immutable (Nullable!int)();
3418 auto a2 = immutable (Nullable!int)(1);
3424 alias NInt = Nullable!int;
3428 //from other Nullable null
3433 //from other Nullable non-null
3438 //Construct from similar nullable
3439 auto a3 = immutable(NInt)();
3446 //from other Nullable null
3452 //from other Nullable non-null
3458 //Construct from similar nullable
3459 auto a3 = immutable(NInt)();
3467 //Check nullable is nicelly embedable in a struct
3472 static struct S2 //inspired from 9404
3479 void opAssign(ref S2 other)
3484 static foreach (S; AliasSeq!(S1, S2))
3493 // https://issues.dlang.org/show_bug.cgi?id=10268
3497 JSONValue value = null;
3498 auto na = Nullable!JSONValue(value);
3500 struct S1 { int val; }
3501 struct S2 { int* val; }
3502 struct S3 { immutable int* val; }
3506 immutable si = immutable S1(1);
3507 auto x1 = Nullable!S1(sm);
3508 auto x2 = immutable Nullable!S1(sm);
3509 auto x3 = Nullable!S1(si);
3510 auto x4 = immutable Nullable!S1(si);
3511 assert(x1.get.val == 1);
3512 assert(x2.get.val == 1);
3513 assert(x3.get.val == 1);
3514 assert(x4.get.val == 1);
3522 immutable si = immutable S2(&ni);
3523 auto x1 = Nullable!S2(sm);
3524 static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); }));
3525 static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); }));
3526 auto x4 = immutable Nullable!S2(si);
3527 assert(*x1.get.val == 10);
3528 assert(*x4.get.val == 10);
3533 immutable si = immutable S3(&ni);
3534 auto x1 = Nullable!S3(sm);
3535 auto x2 = immutable Nullable!S3(sm);
3536 auto x3 = Nullable!S3(si);
3537 auto x4 = immutable Nullable!S3(si);
3538 assert(*x1.get.val == 10);
3539 assert(*x2.get.val == 10);
3540 assert(*x3.get.val == 10);
3541 assert(*x4.get.val == 10);
3545 // https://issues.dlang.org/show_bug.cgi?id=10357
3548 import std.datetime;
3549 Nullable!SysTime time = SysTime(0);
3552 // https://issues.dlang.org/show_bug.cgi?id=10915
3555 import std.conv : to;
3558 Appender!string buffer;
3561 assert(ni.to!string() == "Nullable.null");
3562 assert((cast(const) ni).to!string() == "Nullable.null");
3564 struct Test { string s; }
3565 alias NullableTest = Nullable!Test;
3567 NullableTest nt = Test("test");
3568 // test output range version
3569 assert(nt.to!string() == `Test("test")`);
3570 // test appender version
3571 assert(nt.toString() == `Test("test")`);
3572 // test const version
3573 assert((cast(const) nt).toString() == `const(Test)("test")`);
3575 NullableTest ntn = Test("null");
3576 assert(ntn.to!string() == `Test("null")`);
3587 override string toString()
3589 return d.to!string();
3592 Nullable!TestToString ntts = new TestToString(2.5);
3593 assert(ntts.to!string() == "2.5");
3596 // https://issues.dlang.org/show_bug.cgi?id=14477
3599 static struct DisabledDefaultConstructor
3604 Nullable!DisabledDefaultConstructor var;
3605 var = DisabledDefaultConstructor(5);
3609 // https://issues.dlang.org/show_bug.cgi?id=17440
3612 static interface I { }
3619 canary = 0x5050DEAD;
3624 auto nc = nullable(c);
3626 assert(c.canary == 0xA71FE);
3629 auto ni = nullable(i);
3631 assert(c.canary == 0xA71FE);
3634 // https://issues.dlang.org/show_bug.cgi?id=19037
3637 import std.datetime : SysTime;
3643 nothrow invariant { assert(b == true); }
3647 static bool destroyed;
3650 this(bool b) { this.b = b; }
3651 ~this() @safe { destroyed = true; }
3653 // mustn't call opAssign on Test.init in Nullable!Test, because the invariant
3654 // will be called before opAssign on the Test.init that is in Nullable
3655 // and Test.init violates its invariant.
3656 void opAssign(Test rhs) @safe { assert(false); }
3665 Test.destroyed = false;
3669 assert(Test.destroyed);
3671 Test.destroyed = false;
3673 // don't run destructor on T.init in Nullable on scope exit!
3674 assert(!Test.destroyed);
3676 // check that the contained type's destructor is called on assignment
3681 // can't be static, since we need a specific value's pointer
3686 if (this.destroyedRef)
3688 *this.destroyedRef = true;
3699 // reset from rvalue destruction in Nullable's opAssign
3702 // overwrite Nullable
3705 // the original S should be destroyed.
3706 assert(destroyed == true);
3708 // check that the contained type's destructor is still called when required
3711 bool destructorCalled = false;
3716 ~this() { *this.destroyed = true; }
3722 assert(!destructorCalled);
3724 Nullable!S ns = Nullable!S(S(&destructorCalled));
3726 destructorCalled = false; // reset after S was destroyed in the NS constructor
3728 assert(destructorCalled);
3731 // check that toHash on Nullable is forwarded to the contained type
3736 size_t toHash() const @safe pure nothrow { return 5; }
3739 Nullable!S s1 = S();
3740 Nullable!S s2 = Nullable!S();
3742 assert(typeid(Nullable!S).getHash(&s1) == 5);
3743 assert(typeid(Nullable!S).getHash(&s2) == 0);
3746 // https://issues.dlang.org/show_bug.cgi?id=21704
3749 import std.array : staticArray;
3755 ~this() { destroyed = true; }
3759 Nullable!(Probe[1]) test = [Probe()].staticArray;
3765 // https://issues.dlang.org/show_bug.cgi?id=21705
3771 bool opEquals(S rhs) { return n == rhs.n; }
3774 Nullable!S test1 = S(1), test2 = S(1);
3778 assert(test1 == test2);
3781 // https://issues.dlang.org/show_bug.cgi?id=22101
3788 ~this() { impure++; }
3795 // https://issues.dlang.org/show_bug.cgi?id=22100
3798 Nullable!int a, b, c;
3800 a = b = c = nullable(5);
3803 // https://issues.dlang.org/show_bug.cgi?id=18374
3804 @safe pure nothrow unittest
3806 import std.algorithm.comparison : equal;
3807 import std.range : only, takeNone;
3808 import std.range.primitives : hasAssignableElements, hasLength,
3809 hasLvalueElements, hasSlicing, hasSwappableElements,
3810 isRandomAccessRange;
3811 Nullable!int a = 42;
3813 assert(a.front == 42);
3814 assert(a.back == 42);
3816 assert(a.equal(only(42)));
3817 assert(a[0 .. $].equal(only(42)));
3819 assert(a.equal(only(43)));
3821 assert(a.equal(only(42)));
3824 assert(b.equal(takeNone(b)));
3825 Nullable!int c = a.save();
3831 assert(isRandomAccessRange!(Nullable!int));
3832 assert(hasLength!(Nullable!int));
3833 assert(hasSlicing!(Nullable!int));
3834 assert(hasAssignableElements!(Nullable!int));
3835 assert(hasSwappableElements!(Nullable!int));
3836 assert(hasLvalueElements!(Nullable!int));
3839 // https://issues.dlang.org/show_bug.cgi?id=23640
3840 @safe pure nothrow unittest
3842 import std.algorithm.comparison : equal;
3843 import std.range : only;
3844 import std.range.primitives : hasLength, hasSlicing,
3845 isRandomAccessRange;
3846 static immutable struct S { int[] array; }
3847 auto value = S([42]);
3848 alias ImmutableNullable = immutable Nullable!S;
3849 auto a = ImmutableNullable(value)[];
3850 alias Range = typeof(a);
3851 assert(isRandomAccessRange!Range);
3852 assert(hasLength!Range);
3853 assert(hasSlicing!Range);
3855 assert(a.front == value);
3856 assert(a.back == value);
3857 assert(a[0] == value);
3858 assert(a.equal(only(value)));
3859 assert(a[0 .. $].equal(only(value)));
3868 Just like `Nullable!T`, except that the null state is defined as a
3869 particular value. For example, $(D Nullable!(uint, uint.max)) is an
3870 `uint` that sets aside the value `uint.max` to denote a null
3871 state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D
3872 Nullable!T) because it does not need to store an extra `bool`.
3875 T = The wrapped type for which Nullable provides a null value.
3877 nullValue = The null value which denotes the null state of this
3878 `Nullable`. Must be of type `T`.
3880 struct Nullable(T, T nullValue)
3882 private T _value = nullValue;
3885 Constructor initializing `this` with `value`.
3888 value = The value to initialize this `Nullable` with.
3897 import std.format.spec : FormatSpec;
3898 import std.format.write : formatValue;
3899 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
3900 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt)
3904 sink.formatValue("Nullable.null", fmt);
3908 sink.formatValue(_value, fmt);
3912 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const
3916 sink.formatValue("Nullable.null", fmt);
3920 sink.formatValue(_value, fmt);
3927 import std.conv : to;
3929 const Nullable!(ulong, 0) x = 1;
3930 assert(x.to!string == "1");
3934 Check if `this` is in the null state.
3937 true $(B iff) `this` is in the null state, otherwise false.
3939 @property bool isNull() const
3941 //Need to use 'is' if T is a nullable type and
3942 //nullValue is null, or it's a compiler error
3943 static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null)
3945 return _value is nullValue;
3947 //Need to use 'is' if T is a float type
3948 //because NaN != NaN
3949 else static if (__traits(isFloating, T) || __traits(compiles, { static assert(!(nullValue == nullValue)); }))
3951 return _value is nullValue;
3955 return _value == nullValue;
3962 Nullable!(int, -1) ni;
3963 //Initialized to "null" state
3972 assert(typeof(this).init.isNull, typeof(this).stringof ~
3973 ".isNull does not work correctly because " ~ T.stringof ~
3974 " has an == operator that is non-reflexive and could not be" ~
3975 " determined before runtime to be non-reflexive!");
3978 // https://issues.dlang.org/show_bug.cgi?id=11135
3979 // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed
3980 version (none) @system unittest
3982 static foreach (T; AliasSeq!(float, double, real))
3984 Nullable!(T, T.init) nf;
3985 //Initialized to "null" state
3987 assert(nf is typeof(nf).init);
3998 Forces `this` to the null state.
4008 Nullable!(int, -1) ni = 0;
4016 Assigns `value` to the internally-held state. If the assignment
4017 succeeds, `this` becomes non-null. No null checks are made. Note
4018 that the assignment may leave `this` in the null state.
4021 value = A value of type `T` to assign to this `Nullable`.
4022 If it is `nullvalue`, then the internal state of
4023 this `Nullable` will be set to null.
4025 void opAssign()(T value)
4027 import std.algorithm.mutation : swap;
4029 swap(value, _value);
4033 If this `Nullable` wraps a type that already has a null value
4034 (such as a pointer), and that null value is not given for
4035 `nullValue`, then assigning the null value to this `Nullable`
4036 is no different than assigning any other value of type `T`,
4037 and the resulting code will look very strange. It is strongly
4038 recommended that this be avoided by using `T`'s "built in"
4039 null value for `nullValue`.
4044 enum nullVal = cast(int*) 0xCAFEBABE;
4045 Nullable!(int*, nullVal) npi;
4050 assert(!npi.isNull);
4054 Gets the value. `this` must not be in the null state.
4055 This function is also called for the implicit conversion to `T`.
4057 Preconditions: `isNull` must be `false`.
4059 The value held internally by this `Nullable`.
4061 @property ref inout(T) get() inout
4063 //@@@6169@@@: We avoid any call that might evaluate nullValue's %s,
4064 //Because it might messup get's purity and safety inference.
4065 enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue).";
4066 assert(!isNull, message);
4073 import std.exception : assertThrown, assertNotThrown;
4075 Nullable!(int, -1) ni;
4076 //`get` is implicitly called. Will throw
4077 //an error in non-release mode
4078 assertThrown!Throwable(ni == 0);
4081 assertNotThrown!Throwable(ni == 0);
4085 Implicitly converts to `T`.
4086 `this` must not be in the null state.
4092 auto nullable(alias nullValue, T)(T t)
4093 if (is (typeof(nullValue) == T))
4095 return Nullable!(T, nullValue)(t);
4101 Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle)
4103 //Find the needle, returning -1 if not found
4105 return Nullable!(size_t, size_t.max).init;
4108 void sendLunchInvite(string name)
4112 //It's safer than C...
4113 auto coworkers = ["Jane", "Jim", "Marry", "Fred"];
4114 auto pos = indexOf(coworkers, "Bob");
4117 //Send Bob an invitation to lunch
4118 sendLunchInvite(coworkers[pos]);
4122 //Bob not found; report the error
4125 //And there's no overhead
4126 static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof);
4132 import std.exception : assertThrown;
4134 Nullable!(int, int.min) a;
4136 assertThrown!Throwable(a.get);
4140 static assert(a.sizeof == int.sizeof);
4146 auto a = nullable!(int.min)(8);
4152 @nogc nothrow pure @safe unittest
4154 // https://issues.dlang.org/show_bug.cgi?id=19226
4155 // fully handle non-self-equal nullValue
4156 static struct Fraction
4161 return denominator == 0;
4163 bool opEquals(const Fraction rhs) const
4165 return !isNaN && denominator == rhs.denominator;
4168 alias N = Nullable!(Fraction, Fraction.init);
4169 assert(N.init.isNull);
4174 static int f(scope const Nullable!(int, int.min) x) {
4175 return x.isNull ? 42 : x.get;
4177 Nullable!(int, int.min) a;
4186 // Ensure Nullable can be used in pure/nothrow/@safe environment.
4187 function() @safe pure nothrow
4189 Nullable!(int, int.min) n;
4200 // Ensure Nullable can be used when the value is not pure/nothrow/@system
4204 bool opEquals(const S s) const @system { return s.x == x; }
4207 Nullable!(S, S(711)) s;
4217 //Check nullable is nicelly embedable in a struct
4220 Nullable!(int, 0) ni;
4222 static struct S2 //inspired from 9404
4224 Nullable!(int, 0) ni;
4229 void opAssign(S2 other)
4234 static foreach (S; AliasSeq!(S1, S2))
4244 import std.conv : to;
4246 // https://issues.dlang.org/show_bug.cgi?id=10915
4247 Nullable!(int, 1) ni = 1;
4248 assert(ni.to!string() == "Nullable.null");
4250 struct Test { string s; }
4251 alias NullableTest = Nullable!(Test, Test("null"));
4253 NullableTest nt = Test("test");
4254 assert(nt.to!string() == `Test("test")`);
4256 NullableTest ntn = Test("null");
4257 assert(ntn.to!string() == "Nullable.null");
4268 override string toString()
4270 return d.to!string();
4273 alias NullableTestToString = Nullable!(TestToString, null);
4275 NullableTestToString ntts = new TestToString(2.5);
4276 assert(ntts.to!string() == "2.5");
4281 Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull.
4283 When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`,
4284 pass it to the function you provide and wrap the result in another `Nullable` (if necessary).
4285 If the `Nullable` is null, `apply` will return null itself.
4289 fun = a function operating on the content of the nullable
4292 `fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`.
4295 $(HTTPS en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad)
4297 template apply(alias fun)
4299 import std.functional : unaryFun;
4301 auto apply(T)(auto ref T t)
4302 if (isInstanceOf!(Nullable, T))
4304 alias FunType = typeof(unaryFun!fun(T.init.get));
4306 enum MustWrapReturn = !isInstanceOf!(Nullable, FunType);
4308 static if (MustWrapReturn)
4310 alias ReturnType = Nullable!FunType;
4314 alias ReturnType = FunType;
4319 static if (MustWrapReturn)
4321 return unaryFun!fun(t.get).nullable;
4325 return unaryFun!fun(t.get);
4330 return ReturnType.init;
4336 nothrow pure @nogc @safe unittest
4338 alias toFloat = i => cast(float) i;
4340 Nullable!int sample;
4342 // apply(null) results in a null `Nullable` of the function's return type.
4343 Nullable!float f = sample.apply!toFloat;
4344 assert(sample.isNull && f.isNull);
4348 // apply(non-null) calls the function and wraps the result in a `Nullable`.
4349 f = sample.apply!toFloat;
4350 assert(!sample.isNull && !f.isNull);
4351 assert(f.get == 3.0f);
4355 nothrow pure @nogc @safe unittest
4357 alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init;
4359 Nullable!int sample;
4361 // when the function already returns a `Nullable`, that `Nullable` is not wrapped.
4362 auto result = sample.apply!greaterThree;
4363 assert(sample.isNull && result.isNull);
4365 // The function may decide to return a null `Nullable`.
4367 result = sample.apply!greaterThree;
4368 assert(!sample.isNull && result.isNull);
4370 // Or it may return a value already wrapped in a `Nullable`.
4372 result = sample.apply!greaterThree;
4373 assert(!sample.isNull && !result.isNull);
4374 assert(result.get == 4);
4377 // test that Nullable.get(default) can merge types
4378 @safe @nogc nothrow pure
4381 Nullable!ubyte sample = Nullable!ubyte();
4383 // Test that get(U) returns the common type of the Nullable type and the parameter type.
4384 assert(sample.get(1000) == 1000);
4387 // Workaround for https://issues.dlang.org/show_bug.cgi?id=20670
4388 @safe @nogc nothrow pure
4391 immutable struct S { }
4393 S[] array = Nullable!(S[])().get(S[].init);
4396 // regression test for https://issues.dlang.org/show_bug.cgi?id=21199
4397 @safe @nogc nothrow pure
4401 assert(S(5).nullable.apply!"a.i" == 5);
4404 // regression test for https://issues.dlang.org/show_bug.cgi?id=22176
4405 @safe @nogc nothrow pure
4413 // Nullable shouldn't cause S to generate an
4414 // opAssign that would check the invariant.
4422 Just like `Nullable!T`, except that the object refers to a value
4423 sitting elsewhere in memory. This makes assignments overwrite the
4424 initially assigned value. Internally `NullableRef!T` only stores a
4425 pointer to `T` (i.e., $(D Nullable!T.sizeof == (T*).sizeof)).
4427 struct NullableRef(T)
4432 Constructor binding `this` to `value`.
4435 value = The value to bind to.
4437 this(T* value) @safe pure nothrow
4444 import std.format.spec : FormatSpec;
4445 import std.format.write : formatValue;
4446 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
4447 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt)
4451 sink.formatValue("Nullable.null", fmt);
4455 sink.formatValue(*_value, fmt);
4459 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const
4463 sink.formatValue("Nullable.null", fmt);
4467 sink.formatValue(*_value, fmt);
4474 import std.conv : to;
4476 const NullableRef!(ulong) x = new ulong(1);
4477 assert(x.to!string == "1");
4481 Binds the internal state to `value`.
4484 value = A pointer to a value of type `T` to bind this `NullableRef` to.
4486 void bind(T* value) @safe pure nothrow
4494 NullableRef!int nr = new int(42);
4497 int* n = new int(1);
4503 Returns `true` if and only if `this` is in the null state.
4506 true if `this` is in the null state, otherwise false.
4508 @property bool isNull() const @safe pure nothrow
4510 return _value is null;
4519 int* n = new int(42);
4521 assert(!nr.isNull && nr == 42);
4525 Forces `this` to the null state.
4527 void nullify() @safe pure nothrow
4535 NullableRef!int nr = new int(42);
4543 Assigns `value` to the internally-held state.
4546 value = A value of type `T` to assign to this `NullableRef`.
4547 If the internal state of this `NullableRef` has not
4548 been initialized, an error will be thrown in
4551 void opAssign()(T value)
4552 if (isAssignable!T) //@@@9416@@@
4554 enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ ".";
4555 assert(!isNull, message);
4562 import std.exception : assertThrown, assertNotThrown;
4566 assertThrown!Throwable(nr = 42);
4568 nr.bind(new int(0));
4570 assertNotThrown!Throwable(nr = 42);
4575 Gets the value. `this` must not be in the null state.
4576 This function is also called for the implicit conversion to `T`.
4578 @property ref inout(T) get() inout @safe pure nothrow
4580 enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ ".";
4581 assert(!isNull, message);
4588 import std.exception : assertThrown, assertNotThrown;
4591 //`get` is implicitly called. Will throw
4592 //an error in non-release mode
4593 assertThrown!Throwable(nr == 0);
4595 nr.bind(new int(0));
4596 assertNotThrown!Throwable(nr == 0);
4600 Implicitly converts to `T`.
4601 `this` must not be in the null state.
4607 auto nullableRef(T)(T* t)
4609 return NullableRef!T(t);
4615 import std.exception : assertThrown;
4618 auto a = nullableRef(&x);
4629 assertThrown!Throwable(a.get);
4630 assertThrown!Throwable(a = 71);
4638 static int f(scope const NullableRef!int x) {
4639 return x.isNull ? 42 : x.get;
4642 auto a = nullableRef(&x);
4649 // Ensure NullableRef can be used in pure/nothrow/@safe environment.
4650 function() @safe pure nothrow
4652 auto storage = new int;
4661 assert(*storage == 2294);
4668 // Ensure NullableRef can be used when the value is not pure/nothrow/@safe
4672 this(this) @system {}
4673 bool opEquals(const S s) const @system { return s.x == x; }
4676 auto storage = S(5);
4688 //Check nullable is nicelly embedable in a struct
4693 static struct S2 //inspired from 9404
4700 void opAssign(S2 other)
4705 static foreach (S; AliasSeq!(S1, S2))
4714 // https://issues.dlang.org/show_bug.cgi?id=10915
4717 import std.conv : to;
4719 NullableRef!int nri;
4720 assert(nri.to!string() == "Nullable.null");
4726 NullableRef!Test nt = new Test("test");
4727 assert(nt.to!string() == `Test("test")`);
4738 override string toString()
4740 return d.to!string();
4743 TestToString tts = new TestToString(2.5);
4744 NullableRef!TestToString ntts = &tts;
4745 assert(ntts.to!string() == "2.5");
4750 `BlackHole!Base` is a subclass of `Base` which automatically implements
4751 all abstract member functions in `Base` as do-nothing functions. Each
4752 auto-implemented function just returns the default value of the return type
4753 without doing anything.
4756 $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole)
4757 Perl module by Sean M. Burke.
4760 Base = A non-final class for `BlackHole` to inherit from.
4763 $(LREF AutoImplement), $(LREF generateEmptyFunction)
4765 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction);
4770 import std.math.traits : isNaN;
4772 static abstract class C
4775 this(int v) { m_value = v; }
4776 int value() @property { return m_value; }
4778 abstract real realValue() @property;
4779 abstract void doSomething();
4782 auto c = new BlackHole!C(42);
4783 assert(c.value == 42);
4785 // Returns real.init which is NaN
4786 assert(c.realValue.isNaN);
4787 // Abstract functions are implemented as do-nothing
4793 import std.math.traits : isNaN;
4797 interface I_1 { real test(); }
4798 auto o = new BlackHole!I_1;
4799 assert(o.test().isNaN()); // NaN
4806 this(int v) { m_value = v; }
4807 int value() @property { return m_value; }
4809 abstract real realValue() @property;
4810 abstract void doSomething();
4813 auto c = new BlackHole!C(42);
4814 assert(c.value == 42);
4816 assert(c.realValue.isNaN); // NaN
4820 // https://issues.dlang.org/show_bug.cgi?id=12058
4823 inout(Object) foo() inout;
4828 nothrow pure @nogc @safe unittest
4832 I foo() nothrow pure @nogc @safe return scope;
4835 scope cb = new BlackHole!I();
4841 `WhiteHole!Base` is a subclass of `Base` which automatically implements
4842 all abstract member functions as functions that always fail. These functions
4843 simply throw an `Error` and never return. `Whitehole` is useful for
4844 trapping the use of class member functions that haven't been implemented.
4847 $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole)
4848 Perl module by Michael G Schwern.
4851 Base = A non-final class for `WhiteHole` to inherit from.
4854 $(LREF AutoImplement), $(LREF generateAssertTrap)
4856 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction);
4861 import std.exception : assertThrown;
4865 abstract void notYetImplemented();
4868 auto c = new WhiteHole!C;
4869 assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error
4872 // https://issues.dlang.org/show_bug.cgi?id=20232
4873 nothrow pure @safe unittest
4877 I foo() nothrow pure @safe return scope;
4880 if (0) // Just checking attribute interference
4882 scope cw = new WhiteHole!I();
4888 class NotImplementedError : Error
4890 this(string method) nothrow pure @safe
4892 super(method ~ " is not implemented");
4898 import std.exception : assertThrown;
4906 auto o = new WhiteHole!I_1;
4907 assertThrown!NotImplementedError(o.foo());
4908 assertThrown!NotImplementedError(o.bar());
4914 abstract void notYetImplemented();
4917 auto c = new WhiteHole!C;
4920 c.notYetImplemented();
4929 `AutoImplement` automatically implements (by default) all abstract member
4930 functions in the class or interface `Base` in specified way.
4932 The second version of `AutoImplement` automatically implements
4933 `Interface`, while deriving from `BaseClass`.
4936 how = template which specifies _how functions will be implemented/overridden.
4938 Two arguments are passed to `how`: the type `Base` and an alias
4939 to an implemented function. Then `how` must return an implemented
4940 function body as a string.
4942 The generated function body can use these keywords:
4944 $(LI `a0`, `a1`, …: arguments passed to the function;)
4945 $(LI `args`: a tuple of the arguments;)
4946 $(LI `self`: an alias to the function itself;)
4947 $(LI `parent`: an alias to the overridden function (if any).)
4950 You may want to use templated property functions (instead of Implicit
4951 Template Properties) to generate complex functions:
4952 --------------------
4953 // Prints log messages for each call to overridden functions.
4954 string generateLogger(C, alias fun)() @property
4957 enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
4960 stmt ~= q{ struct Importer { import std.stdio; } };
4961 stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
4962 static if (!__traits(isAbstractFunction, fun))
4964 static if (is(ReturnType!fun == void))
4965 stmt ~= q{ parent(args); };
4968 auto r = parent(args);
4969 Importer.writeln("--> ", r);
4975 --------------------
4977 what = template which determines _what functions should be
4978 implemented/overridden.
4980 An argument is passed to `what`: an alias to a non-final member
4981 function in `Base`. Then `what` must return a boolean value.
4982 Return `true` to indicate that the passed function should be
4983 implemented/overridden.
4985 --------------------
4986 // Sees if fun returns something.
4987 enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
4988 --------------------
4993 Generated code is inserted in the scope of `std.typecons` module. Thus,
4994 any useful functions outside `std.typecons` cannot be used in the generated
4995 code. To workaround this problem, you may `import` necessary things in a
4996 local struct, as done in the `generateLogger()` template in the above
5003 $(LI Variadic arguments to constructors are not forwarded to super.)
5004 $(LI Deep interface inheritance causes compile error with messages like
5005 "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar
5006 does not override any function". [$(BUGZILLA 2525)] )
5007 $(LI The `parent` keyword is actually a delegate to the super class'
5008 corresponding member function. [$(BUGZILLA 2540)] )
5009 $(LI Using alias template parameter in `how` and/or `what` may cause
5010 strange compile error. Use template tuple parameter instead to workaround
5011 this problem. [$(BUGZILLA 4217)] )
5014 class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base
5015 if (!is(how == class))
5017 private alias autoImplement_helper_ =
5018 AutoImplement_Helper!("autoImplement_helper_", "Base", Base, typeof(this), how, what);
5019 mixin(autoImplement_helper_.code);
5023 class AutoImplement(
5024 Interface, BaseClass, alias how,
5025 alias what = isAbstractFunction) : BaseClass, Interface
5026 if (is(Interface == interface) && is(BaseClass == class))
5028 private alias autoImplement_helper_ = AutoImplement_Helper!(
5029 "autoImplement_helper_", "Interface", Interface, typeof(this), how, what);
5030 mixin(autoImplement_helper_.code);
5036 interface PackageSupplier
5042 static abstract class AbstractFallbackPackageSupplier : PackageSupplier
5044 protected PackageSupplier default_, fallback;
5046 this(PackageSupplier default_, PackageSupplier fallback)
5048 this.default_ = default_;
5049 this.fallback = fallback;
5056 template fallback(T, alias func)
5058 import std.format : format;
5059 // for all implemented methods:
5060 // - try default first
5061 // - only on a failure run & return fallback
5065 return default_.%1$s(args);
5069 return fallback.%1$s(args);
5071 }.format(__traits(identifier, func));
5074 // combines two classes and use the second one as fallback
5075 alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback);
5077 class FailingPackageSupplier : PackageSupplier
5079 int foo(){ throw new Exception("failure"); }
5080 int bar(){ return 2;}
5083 class BackupPackageSupplier : PackageSupplier
5085 int foo(){ return -1; }
5086 int bar(){ return -1;}
5089 auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier());
5091 assert(registry.foo() == -1);
5092 assert(registry.bar() == 2);
5096 * Code-generating stuffs are encupsulated in this helper template so that
5097 * namespace pollution, which can cause name confliction with Base's public
5098 * members, should be minimized.
5100 private template AutoImplement_Helper(string myName, string baseName,
5101 Base, Self, alias generateMethodBody, alias cherrypickMethod)
5104 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5106 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5108 // Returns function overload sets in the class C, filtered with pred.
5109 template enumerateOverloads(C, alias pred)
5111 template Impl(names...)
5113 import std.meta : Filter;
5114 static if (names.length > 0)
5116 alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0]));
5117 alias next = Impl!(names[1 .. $]);
5119 static if (methods.length > 0)
5120 alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next);
5125 alias Impl = AliasSeq!();
5128 alias enumerateOverloads = Impl!(__traits(allMembers, C));
5131 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5133 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5135 // Add a non-final check to the cherrypickMethod.
5136 enum bool canonicalPicker(fun.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) =
5137 !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun);
5140 * A tuple of overload sets, each item of which consists of functions to be
5141 * implemented by the generated code.
5143 alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker);
5146 * Super class of this AutoImplement instance
5148 alias Super = BaseTypeTuple!(Self)[0];
5149 static assert(is(Super == class));
5150 static assert(is(Base == interface) || is(Super == Base));
5153 * A tuple of the super class' constructors. Used for forwarding
5154 * constructor calls.
5156 static if (__traits(hasMember, Super, "__ctor"))
5157 alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Super, "__ctor"));
5159 alias ctorOverloadSet = OverloadSet!("__ctor"); // empty
5162 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5164 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5167 * The generated code will be mixed into AutoImplement, which will be
5168 * instantiated in this module's scope. Thus, any user-defined types are
5169 * out of scope and cannot be used directly (i.e. by their names).
5171 * We will use FuncInfo instances for accessing return types and parameter
5172 * types of the implemented functions. The instances will be populated to
5173 * the AutoImplement's scope in a certain way; see the populate() below.
5176 // Returns the preferred identifier for the FuncInfo instance for the i-th
5177 // overloaded function with the name.
5178 template INTERNAL_FUNCINFO_ID(string name, size_t i)
5180 import std.format : format;
5182 enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i);
5186 * Insert FuncInfo instances about all the target functions here. This
5187 * enables the generated code to access type information via, for example,
5188 * "autoImplement_helper_.F_foo_1".
5190 template populate(overloads...)
5192 static if (overloads.length > 0)
5194 mixin populate!(overloads[0].name, overloads[0].contents);
5195 mixin populate!(overloads[1 .. $]);
5198 template populate(string name, methods...)
5200 static if (methods.length > 0)
5202 mixin populate!(name, methods[0 .. $ - 1]);
5204 alias target = methods[$ - 1];
5205 enum ith = methods.length - 1;
5206 mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;");
5210 public mixin populate!(targetOverloadSets);
5211 public mixin populate!( ctorOverloadSet );
5214 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5215 // Code-generating policies
5216 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5218 /* Common policy configurations for generating constructors and methods. */
5219 template CommonGeneratingPolicy()
5221 // base class identifier which generated code should use
5222 enum string BASE_CLASS_ID = baseName;
5224 // FuncInfo instance identifier which generated code should use
5225 template FUNCINFO_ID(string name, size_t i)
5227 enum string FUNCINFO_ID =
5228 myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i);
5232 /* Policy configurations for generating constructors. */
5233 template ConstructorGeneratingPolicy()
5235 mixin CommonGeneratingPolicy;
5237 /* Generates constructor body. Just forward to the base class' one. */
5238 string generateFunctionBody(ctor.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
5240 enum varstyle = variadicFunctionStyle!(typeof(&ctor[0]));
5242 static if (varstyle & (Variadic.c | Variadic.d))
5244 // the argptr-forwarding problem
5245 //pragma(msg, "Warning: AutoImplement!(", Base, ") ",
5246 // "ignored variadic arguments to the constructor ",
5247 // FunctionTypeOf!(typeof(&ctor[0])) );
5249 return "super(args);";
5253 /* Policy configurations for genearting target methods. */
5254 template MethodGeneratingPolicy()
5256 mixin CommonGeneratingPolicy;
5258 /* Geneartes method body. */
5259 string generateFunctionBody(func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
5261 return generateMethodBody!(Base, func); // given
5266 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5268 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5270 alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!());
5271 alias MethodGenerator = MemberFunctionGenerator!(MethodGeneratingPolicy!());
5273 public enum string code =
5274 ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~
5275 MethodGenerator.generateCode!(targetOverloadSets);
5277 debug (SHOW_GENERATED_CODE)
5279 pragma(msg, "-------------------- < ", Base, " >");
5281 pragma(msg, "--------------------");
5285 //debug = SHOW_GENERATED_CODE;
5289 // no function to implement
5292 auto o = new BlackHole!I_1;
5296 interface I_3 { void test(int, in int, out int, ref int, lazy int); }
5297 auto o = new BlackHole!I_3;
5299 // use of user-defined type
5302 interface I_4 { S test(); }
5303 auto o = new BlackHole!I_4;
5313 auto o = new BlackHole!I_5;
5315 // constructor forwarding
5319 this(int n) { assert(n == 42); }
5320 this(string s) { assert(s == "Deeee"); }
5323 auto o1 = new BlackHole!C_6(42);
5324 auto o2 = new BlackHole!C_6("Deeee");
5325 auto o3 = new BlackHole!C_6(1, 2, 3, 4);
5332 int test_pure() pure;
5333 int test_nothrow() nothrow;
5334 int test_property() @property;
5335 int test_safe() @safe;
5336 int test_trusted() @trusted;
5337 int test_system() @system;
5338 int test_pure_nothrow() pure nothrow;
5340 auto o = new BlackHole!I_7;
5346 void test_const() const;
5347 void test_immutable() immutable;
5348 void test_shared() shared;
5349 void test_shared_const() shared const;
5351 auto o = new BlackHole!I_8;
5357 private string foo_;
5363 protected string boilerplate() @property
5365 return "Boilerplate stuff.";
5368 public string foo() @property
5376 string testMethod(size_t);
5379 static string generateTestMethod(C, alias fun)() @property
5381 return "return this.boilerplate[0 .. a0];";
5384 auto o = new AutoImplement!(I_10, C_9, generateTestMethod)("Testing");
5385 assert(o.testMethod(11) == "Boilerplate");
5386 assert(o.foo == "Testing");
5388 /+ // deep inheritance
5390 // https://issues.dlang.org/show_bug.cgi?id=2525
5391 // https://issues.dlang.org/show_bug.cgi?id=3525
5392 // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic()
5393 interface I { void foo(); }
5396 static abstract class C_9 : K {}
5397 auto o = new BlackHole!C_9;
5399 // test `parent` alias
5403 void simple(int) @safe;
5404 int anotherSimple(string);
5405 int overloaded(int);
5407 void overloaded(string) @safe;
5413 import std.traits : Parameters, ReturnType;
5414 import std.meta : Alias;
5416 protected ReturnType!fn _impl(alias fn)(Parameters!fn)
5417 if (is(Alias!(__traits(parent, fn)) == interface))
5419 static if (!is(typeof(return) == void))
5420 return typeof(return).init;
5424 template tpl(I, alias fn)
5425 if (is(I == interface) && __traits(isSame, __traits(parent, fn), I))
5427 enum string tpl = q{
5428 enum bool haveReturn = !is(typeof(return) == void);
5430 static if (is(typeof(return) == void))
5433 return _impl!parent(args);
5437 auto o = new AutoImplement!(I_11, C_11, tpl);
5441 // https://issues.dlang.org/show_bug.cgi?id=17177
5442 // AutoImplement fails on function overload sets with
5443 // "cannot infer type from overloaded function symbol"
5446 static class Issue17177
5451 Issue17177 overloaded(string n)
5465 static string how(C, alias fun)()
5467 static if (!is(ReturnType!fun == void))
5470 return parent(args);
5481 import std.meta : templateNot;
5482 alias Implementation = AutoImplement!(Issue17177, how, templateNot!isFinalFunction);
5485 version (StdUnittest)
5487 // https://issues.dlang.org/show_bug.cgi?id=10647
5488 // Add prefix "issue10647_" as a workaround for
5489 // https://issues.dlang.org/show_bug.cgi?id=1238
5490 private string issue10647_generateDoNothing(C, alias fun)() @property
5494 static if (is(ReturnType!fun == void))
5498 string returnType = ReturnType!fun.stringof;
5499 stmt ~= "return "~returnType~".init;";
5504 private template issue10647_isAlwaysTrue(alias fun)
5506 enum issue10647_isAlwaysTrue = true;
5509 // Do nothing template
5510 private template issue10647_DoNothing(Base)
5512 alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue);
5515 // A class to be overridden
5516 private class issue10647_Foo{
5523 auto foo = new issue10647_DoNothing!issue10647_Foo();
5528 Used by MemberFunctionGenerator.
5530 package template OverloadSet(string nam, T...)
5532 enum string name = nam;
5537 Used by MemberFunctionGenerator.
5539 package template FuncInfo(alias func)
5540 if (is(typeof(&func)))
5542 alias RT = ReturnType!(typeof(&func));
5543 alias PT = Parameters!(typeof(&func));
5545 package template FuncInfo(Func)
5547 alias RT = ReturnType!Func;
5548 alias PT = Parameters!Func;
5552 General-purpose member function generator.
5553 --------------------
5554 template GeneratingPolicy()
5556 // [optional] the name of the class where functions are derived
5557 enum string BASE_CLASS_ID;
5559 // [optional] define this if you have only function types
5560 enum bool WITHOUT_SYMBOL;
5562 // [optional] Returns preferred identifier for i-th parameter.
5563 template PARAMETER_VARIABLE_ID(size_t i);
5565 // Returns the identifier of the FuncInfo instance for the i-th overload
5566 // of the specified name. The identifier must be accessible in the scope
5567 // where generated code is mixed.
5568 template FUNCINFO_ID(string name, size_t i);
5570 // Returns implemented function body as a string. When WITHOUT_SYMBOL is
5571 // defined, the latter is used.
5572 template generateFunctionBody(alias func);
5573 template generateFunctionBody(string name, FuncType);
5575 --------------------
5577 package template MemberFunctionGenerator(alias Policy)
5580 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5582 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5584 alias format = std.format.format;
5586 enum CONSTRUCTOR_NAME = "__ctor";
5588 // true if functions are derived from a base class
5589 enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID");
5591 // true if functions are specified as types, not symbols
5592 enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL");
5594 // preferred identifier for i-th parameter variable
5595 static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID"))
5597 alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID;
5601 enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i);
5602 // default: a0, a1, ...
5605 // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach.
5606 template CountUp(size_t n)
5609 alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1);
5611 alias CountUp = AliasSeq!();
5615 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5617 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5620 * Runs through all the target overload sets and generates D code which
5621 * implements all the functions in the overload sets.
5623 public string generateCode(overloads...)() @property
5627 // run through all the overload sets
5628 foreach (i_; CountUp!(0 + overloads.length)) // workaround
5630 enum i = 0 + i_; // workaround
5631 alias oset = overloads[i];
5633 code ~= generateCodeForOverloadSet!(oset);
5635 static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME)
5637 // The generated function declarations may hide existing ones
5638 // in the base class (cf. HiddenFuncError), so we put an alias
5639 // declaration here to reveal possible hidden functions.
5640 code ~= format("alias %s = %s.%s;\n",
5642 // super: https://issues.dlang.org/show_bug.cgi?id=2540
5643 Policy.BASE_CLASS_ID,
5650 // handle each overload set
5651 string generateCodeForOverloadSet(alias oset)() @property
5655 foreach (i_; CountUp!(0 + oset.contents.length)) // workaround
5657 enum i = 0 + i_; // workaround
5658 code ~= generateFunction!(
5659 Policy.FUNCINFO_ID!(oset.name, i), oset.name,
5660 oset.contents[i]) ~ "\n";
5666 * Returns D code which implements the function func. This function
5667 * actually generates only the declarator part; the function body part is
5668 * generated by the functionGenerator() policy.
5670 public string generateFunction(
5671 string myFuncInfo, string name, func... )() @property
5673 import std.format : format;
5675 enum isCtor = (name == CONSTRUCTOR_NAME);
5677 string code; // the result
5679 auto paramsRes = generateParameters!(myFuncInfo, func)();
5680 code ~= paramsRes.imports;
5682 /*** Function Declarator ***/
5684 alias Func = FunctionTypeOf!(func);
5685 alias FA = FunctionAttribute;
5686 enum atts = functionAttributes!(func);
5687 enum realName = isCtor ? "this" : name;
5689 // FIXME?? Make it so that these aren't CTFE funcs any more, since
5690 // Format is deprecated, and format works at compile time?
5691 /* Made them CTFE funcs just for the sake of Format!(...) */
5693 // return type with optional "ref"
5694 static string make_returnType()
5700 if (atts & FA.ref_) rtype ~= "ref ";
5701 rtype ~= myFuncInfo ~ ".RT";
5705 enum returnType = make_returnType();
5707 // function attributes attached after declaration
5708 static string make_postAtts()
5711 if (atts & FA.pure_ ) poatts ~= " pure";
5712 if (atts & FA.nothrow_) poatts ~= " nothrow";
5713 if (atts & FA.property) poatts ~= " @property";
5714 if (atts & FA.safe ) poatts ~= " @safe";
5715 if (atts & FA.trusted ) poatts ~= " @trusted";
5716 if (atts & FA.scope_ ) poatts ~= " scope";
5717 if (atts & FA.return_ ) poatts ~= " return";
5720 enum postAtts = make_postAtts();
5722 // function storage class
5723 static string make_storageClass()
5726 if (is(Func == shared)) postc ~= " shared";
5727 if (is(Func == const)) postc ~= " const";
5728 if (is(Func == inout)) postc ~= " inout";
5729 if (is(Func == immutable)) postc ~= " immutable";
5732 enum storageClass = make_storageClass();
5735 if (__traits(isVirtualMethod, func))
5736 code ~= "override ";
5737 code ~= format("extern(%s) %s %s(%s) %s %s\n",
5738 functionLinkage!(func),
5742 postAtts, storageClass );
5745 /*** Function Body ***/
5748 enum nparams = Parameters!(func).length;
5750 /* Declare keywords: args, self and parent. */
5753 preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n";
5756 preamble ~= "alias self = " ~ name ~ ";\n";
5757 static if (WITH_BASE_CLASS)
5758 preamble ~= `alias parent = __traits(getMember, ` ~ Policy.BASE_CLASS_ID ~ `, "` ~ name ~ `");`;
5762 static if (WITHOUT_SYMBOL)
5763 enum fbody = Policy.generateFunctionBody!(name, func);
5765 enum fbody = Policy.generateFunctionBody!(func);
5776 * Returns D code which declares function parameters,
5777 * and optionally any imports (e.g. core.vararg)
5778 * "ref int a0, real a1, ..."
5780 static struct GenParams { string imports, params; }
5781 GenParams generateParameters(string myFuncInfo, func...)()
5783 alias STC = ParameterStorageClass;
5784 alias stcs = ParameterStorageClassTuple!(func);
5785 enum nparams = stcs.length;
5787 string imports = ""; // any imports required
5788 string params = ""; // parameters
5790 foreach (i, stc; stcs)
5792 if (i > 0) params ~= ", ";
5794 // Parameter storage classes.
5795 if (stc & STC.scope_) params ~= "scope ";
5796 if (stc & STC.in_) params ~= "in ";
5797 if (stc & STC.out_ ) params ~= "out ";
5798 if (stc & STC.ref_ ) params ~= "ref ";
5799 if (stc & STC.lazy_ ) params ~= "lazy ";
5801 // Take parameter type from the FuncInfo.
5802 params ~= format("%s.PT[%s]", myFuncInfo, i);
5804 // Declare a parameter variable.
5805 params ~= " " ~ PARAMETER_VARIABLE_ID!(i);
5808 // Add some ellipsis part if needed.
5809 auto style = variadicFunctionStyle!(func);
5810 final switch (style)
5815 case Variadic.c, Variadic.d:
5816 imports ~= "import core.vararg;\n";
5817 // (...) or (a, b, ...)
5818 params ~= (nparams == 0) ? "..." : ", ...";
5821 case Variadic.typesafe:
5826 return typeof(return)(imports, params);
5829 // Returns D code which enumerates n parameter variables using comma as the
5830 // separator. "a0, a1, a2, a3"
5831 string enumerateParameters(size_t n)() @property
5835 foreach (i_; CountUp!(n))
5837 enum i = 0 + i_; // workaround
5838 if (i > 0) params ~= ", ";
5839 params ~= PARAMETER_VARIABLE_ID!(i);
5847 Predefined how-policies for `AutoImplement`. These templates are also used by
5848 `BlackHole` and `WhiteHole`, respectively.
5850 template generateEmptyFunction(C, func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)
5852 static if (is(ReturnType!(func) == void))
5853 enum string generateEmptyFunction = q{
5855 else static if (functionAttributes!(func) & FunctionAttribute.ref_)
5856 enum string generateEmptyFunction = q{
5857 static typeof(return) dummy;
5861 enum string generateEmptyFunction = q{
5862 return typeof(return).init;
5869 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction);
5877 auto i = new BlackHole!I();
5878 // generateEmptyFunction returns the default value of the return type without doing anything
5880 assert(i.bar is null);
5884 template generateAssertTrap(C, func...)
5886 enum string generateAssertTrap =
5887 `throw new NotImplementedError("` ~ C.stringof ~ "."
5888 ~ __traits(identifier, func) ~ `");`;
5894 import std.exception : assertThrown;
5896 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap);
5904 auto i = new WhiteHole!I();
5905 // generateAssertTrap throws an exception for every unimplemented function of the interface
5906 assertThrown!NotImplementedError(i.foo);
5907 assertThrown!NotImplementedError(i.bar);
5912 pragma(mangle, "_d_toObject")
5913 extern(C) pure nothrow Object typecons_d_toObject(void* p);
5917 * Avoids opCast operator overloading.
5919 private template dynamicCast(T)
5920 if (is(T == class) || is(T == interface))
5923 T dynamicCast(S)(inout S source)
5924 if (is(S == class) || is(S == interface))
5926 static if (is(Unqual!S : Unqual!T))
5928 import std.traits : QualifierOf;
5929 alias Qual = QualifierOf!S; // SharedOf or MutableOf
5930 alias TmpT = Qual!(Unqual!T);
5931 inout(TmpT) tmp = source; // bypass opCast by implicit conversion
5932 return *cast(T*)(&tmp); // + variable pointer cast + dereference
5936 return cast(T) typecons_d_toObject(*cast(void**)(&source));
5943 class C { @disable void opCast(T)(); }
5945 static assert(!__traits(compiles, cast(Object) c));
5946 auto o = dynamicCast!Object(c);
5949 interface I { @disable void opCast(T)(); Object instance(); }
5950 interface J { @disable void opCast(T)(); Object instance(); }
5951 class D : I, J { Object instance() { return this; } }
5953 static assert(!__traits(compiles, cast(J) i));
5954 J j = dynamicCast!J(i);
5955 assert(i.instance() is j.instance());
5959 Supports structural based typesafe conversion.
5961 If `Source` has structural conformance with the `interface` `Targets`,
5962 wrap creates an internal wrapper class which inherits `Targets` and
5963 wraps the `src` object, then returns it.
5965 `unwrap` can be used to extract objects which have been wrapped by `wrap`.
5967 template wrap(Targets...)
5968 if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
5970 import std.meta : staticMap;
5973 auto wrap(Source)(inout Source src) @trusted pure nothrow
5974 if (Targets.length == 1 && is(Source : Targets[0]))
5976 alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]);
5977 return dynamicCast!(inout T)(src);
5979 // structural upcast
5980 template wrap(Source)
5981 if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets))
5983 auto wrap(inout Source src)
5985 static assert(hasRequireMethods!(),
5986 "Source "~Source.stringof~
5987 " does not have structural conformance to "~
5990 alias T = Select!(is(Source == shared), shared Impl, Impl);
5991 return new inout T(src);
5994 template FuncInfo(string s, F)
6000 // https://issues.dlang.org/show_bug.cgi?id=12064: Remove NVI members
6001 template OnlyVirtual(members...)
6003 enum notFinal(alias T) = !__traits(isFinalFunction, T);
6004 import std.meta : Filter;
6005 alias OnlyVirtual = Filter!(notFinal, members);
6008 // Concat all Targets function members into one tuple
6009 template Concat(size_t i = 0)
6011 static if (i >= Targets.length)
6012 alias Concat = AliasSeq!();
6015 alias Concat = AliasSeq!(OnlyVirtual!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1)));
6019 // Remove duplicated functions based on the identifier name and function type covariance
6020 template Uniq(members...)
6022 static if (members.length == 0)
6023 alias Uniq = AliasSeq!();
6026 alias func = members[0];
6027 enum name = __traits(identifier, func);
6028 alias type = FunctionTypeOf!func;
6029 template check(size_t i, mem...)
6031 static if (i >= mem.length)
6032 enum ptrdiff_t check = -1;
6035 enum ptrdiff_t check =
6036 __traits(identifier, func) == __traits(identifier, mem[i]) &&
6037 !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void)
6038 ? i : check!(i + 1, mem);
6041 enum ptrdiff_t x = 1 + check!(0, members[1 .. $]);
6044 alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x]));
6045 alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]);
6047 static if (remain.length >= 1 && remain[0].name == name &&
6048 !is(DerivedFunctionType!(typex, remain[0].type) == void))
6050 alias F = DerivedFunctionType!(typex, remain[0].type);
6051 alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]);
6054 alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain);
6058 alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $]));
6062 alias TargetMembers = Uniq!(Concat!()); // list of FuncInfo
6063 alias SourceMembers = GetOverloadedMethods!Source; // list of function symbols
6065 // Check whether all of SourceMembers satisfy covariance target in TargetMembers
6066 template hasRequireMethods(size_t i = 0)
6068 static if (i >= TargetMembers.length)
6069 enum hasRequireMethods = true;
6072 enum hasRequireMethods =
6073 findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 &&
6074 hasRequireMethods!(i + 1);
6078 // Internal wrapper class
6079 final class Impl : Structural, Targets
6082 Source _wrap_source;
6084 this( inout Source s) inout @safe pure nothrow { _wrap_source = s; }
6085 this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; }
6087 // BUG: making private should work with NVI.
6088 protected final inout(Object) _wrap_getSource() inout @trusted
6090 return dynamicCast!(inout Object)(_wrap_source);
6093 import std.conv : to;
6094 import core.lifetime : forward;
6095 template generateFun(size_t i)
6097 enum name = TargetMembers[i].name;
6098 enum fa = functionAttributes!(TargetMembers[i].type);
6099 static @property stc()
6102 if (fa & FunctionAttribute.property) r ~= "@property ";
6103 if (fa & FunctionAttribute.ref_) r ~= "ref ";
6104 if (fa & FunctionAttribute.pure_) r ~= "pure ";
6105 if (fa & FunctionAttribute.nothrow_) r ~= "nothrow ";
6106 if (fa & FunctionAttribute.trusted) r ~= "@trusted ";
6107 if (fa & FunctionAttribute.safe) r ~= "@safe ";
6110 static @property mod()
6112 alias type = AliasSeq!(TargetMembers[i].type)[0];
6114 static if (is(type == immutable)) r ~= " immutable";
6117 static if (is(type == shared)) r ~= " shared";
6118 static if (is(type == const)) r ~= " const";
6119 else static if (is(type == inout)) r ~= " inout";
6124 enum n = to!string(i);
6125 static if (fa & FunctionAttribute.property)
6127 static if (Parameters!(TargetMembers[i].type).length == 0)
6128 enum fbody = "_wrap_source."~name;
6130 enum fbody = "_wrap_source."~name~" = forward!args";
6134 enum fbody = "_wrap_source."~name~"(forward!args)";
6137 "override "~stc~"ReturnType!(TargetMembers["~n~"].type) "
6138 ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~
6139 "{ return "~fbody~"; }";
6143 static foreach (i; 0 .. TargetMembers.length)
6144 mixin(generateFun!i);
6149 template wrap(Targets...)
6150 if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets))
6152 import std.meta : staticMap;
6154 alias wrap = .wrap!(staticMap!(Unqual, Targets));
6158 template unwrap(Target)
6159 if (isMutable!Target)
6162 auto unwrap(Source)(inout Source src) @trusted pure nothrow
6163 if (is(Target : Source))
6165 alias T = Select!(is(Source == shared), shared Target, Target);
6166 return dynamicCast!(inout T)(src);
6168 // structural downcast
6169 auto unwrap(Source)(inout Source src) @trusted pure nothrow
6170 if (!is(Target : Source))
6172 alias T = Select!(is(Source == shared), shared Target, Target);
6173 Object o = dynamicCast!(Object)(src); // remove qualifier
6176 if (auto a = dynamicCast!(Structural)(o))
6178 if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource()))
6181 else if (auto d = dynamicCast!(inout T)(o))
6191 template unwrap(Target)
6192 if (!isMutable!Target)
6194 alias unwrap = .unwrap!(Unqual!Target);
6203 @property int height();
6207 @property int height();
6211 int quack() { return 1; }
6212 @property int height() { return 10; }
6216 int quack() { return 2; }
6217 @property int height() { return 20; }
6220 Duck d1 = new Duck();
6221 Human h1 = new Human();
6223 interface Refleshable
6228 // does not have structural conformance
6229 static assert(!__traits(compiles, d1.wrap!Refleshable));
6230 static assert(!__traits(compiles, h1.wrap!Refleshable));
6233 Quack qd = d1.wrap!Quack;
6235 assert(qd.quack() == 1); // calls Duck.quack
6237 Duck d2 = qd.unwrap!Duck;
6240 // structural upcast
6241 Quack qh = h1.wrap!Quack;
6242 assert(qh.quack() == 2); // calls Human.quack
6243 // structural downcast
6244 Human h2 = qh.unwrap!Human;
6247 // structural upcast (two steps)
6248 Quack qx = h1.wrap!Quack; // Human -> Quack
6249 Flyer fx = qx.wrap!Flyer; // Quack -> Flyer
6250 assert(fx.height == 20); // calls Human.height
6251 // structural downcast (two steps)
6252 Quack qy = fx.unwrap!Quack; // Flyer -> Quack
6253 Human hy = qy.unwrap!Human; // Quack -> Human
6255 // structural downcast (one step)
6256 Human hz = fx.unwrap!Human; // Flyer -> Human
6263 import std.traits : FunctionAttribute, functionAttributes;
6264 interface A { int run(); }
6265 interface B { int stop(); @property int status(); }
6268 int run() { return 1; }
6269 int stop() { return 2; }
6270 @property int status() { return 3; }
6274 auto ab = x.wrap!(A, B);
6277 assert(a.run() == 1);
6278 assert(b.stop() == 2);
6279 assert(b.status == 3);
6280 static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
6283 // Internal class to support dynamic cross-casting
6284 private interface Structural
6286 inout(Object) _wrap_getSource() inout @safe pure nothrow;
6293 int draw() { return 1; }
6294 int draw(int v) { return v; }
6296 int draw() const { return 2; }
6297 int draw() shared { return 3; }
6298 int draw() shared const { return 4; }
6299 int draw() immutable { return 5; }
6306 int draw() shared const;
6307 int draw() immutable;
6315 auto sa = new shared A();
6316 auto ia = new immutable A();
6318 Drawable md = ma.wrap!Drawable;
6319 const Drawable cd = ma.wrap!Drawable;
6320 shared Drawable sd = sa.wrap!Drawable;
6321 shared const Drawable scd = sa.wrap!Drawable;
6322 immutable Drawable id = ia.wrap!Drawable;
6323 assert( md.draw() == 1);
6324 assert( cd.draw() == 2);
6325 assert( sd.draw() == 3);
6326 assert(scd.draw() == 4);
6327 assert( id.draw() == 5);
6330 Drawable2 d = ma.wrap!Drawable2;
6331 static assert(!__traits(compiles, d.draw()));
6332 assert(d.draw(10) == 10);
6336 // https://issues.dlang.org/show_bug.cgi?id=10377
6339 import std.range, std.algorithm;
6341 interface MyInputRange(T)
6343 @property T front();
6345 @property bool empty();
6348 //auto o = iota(0,10,1).inputRangeObject();
6349 //pragma(msg, __traits(allMembers, typeof(o)));
6350 auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)();
6351 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6354 // https://issues.dlang.org/show_bug.cgi?id=10536
6363 int foo() { return 1; }
6364 @disable void opCast(T, this X)(); // !
6367 Interface i = new Pluggable().wrap!Interface;
6368 assert(i.foo() == 1);
6372 // Enhancement 10538
6380 int opDispatch(string name, A...)(A args) { return 100; }
6383 Interface i = wrap!Interface(new Pluggable());
6384 assert(i.foo() == 100);
6385 assert(i.bar(10) == 100);
6388 // https://issues.dlang.org/show_bug.cgi?id=12064
6394 final int nvi1(){return foo();}
6400 final int nvi2(){return bar();}
6405 int foo() { return 42;}
6406 int bar() { return 12064;}
6409 auto baz = new Baz();
6410 auto foobar = baz.wrap!(I, J)();
6411 assert(foobar.nvi1 == 42);
6412 assert(foobar.nvi2 == 12064);
6415 // Make a tuple of non-static function symbols
6416 package template GetOverloadedMethods(T)
6418 import std.meta : Filter;
6420 alias allMembers = __traits(allMembers, T);
6421 template follows(size_t i = 0)
6423 static if (i >= allMembers.length)
6425 alias follows = AliasSeq!();
6427 else static if (!__traits(compiles, mixin("T."~allMembers[i])))
6429 alias follows = follows!(i + 1);
6433 enum name = allMembers[i];
6435 template isMethod(alias f)
6437 static if (is(typeof(&f) F == F*) && is(F == function))
6438 enum isMethod = !__traits(isStaticFunction, f);
6440 enum isMethod = false;
6442 alias follows = AliasSeq!(
6443 Filter!(isMethod, __traits(getOverloads, T, name)),
6447 alias GetOverloadedMethods = follows!();
6449 // find a function from Fs that has same identifier and covariant type with f
6450 private template findCovariantFunction(alias finfo, Source, Fs...)
6452 template check(size_t i = 0)
6454 static if (i >= Fs.length)
6455 enum ptrdiff_t check = -1;
6458 enum ptrdiff_t check =
6459 (finfo.name == __traits(identifier, Fs[i])) &&
6460 isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type)
6461 ? i : check!(i + 1);
6465 static if (x == -1 && is(typeof(Source.opDispatch)))
6467 alias Params = Parameters!(finfo.type);
6468 enum ptrdiff_t findCovariantFunction =
6469 is(typeof(( Source).init.opDispatch!(finfo.name)(Params.init))) ||
6470 is(typeof(( const Source).init.opDispatch!(finfo.name)(Params.init))) ||
6471 is(typeof(( immutable Source).init.opDispatch!(finfo.name)(Params.init))) ||
6472 is(typeof(( shared Source).init.opDispatch!(finfo.name)(Params.init))) ||
6473 is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init)))
6474 ? ptrdiff_t.max : -1;
6477 enum ptrdiff_t findCovariantFunction = x;
6480 private enum TypeModifier
6482 mutable = 0, // type is mutable
6483 const_ = 1, // type is const
6484 immutable_ = 2, // type is immutable
6485 shared_ = 4, // type is shared
6486 inout_ = 8, // type is wild
6488 private template TypeMod(T)
6490 static if (is(T == immutable))
6492 enum mod1 = TypeModifier.immutable_;
6497 enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0;
6498 static if (is(T == const))
6499 enum mod2 = TypeModifier.const_;
6500 else static if (is(T == inout))
6501 enum mod2 = TypeModifier.inout_;
6503 enum mod2 = TypeModifier.mutable;
6505 enum TypeMod = cast(TypeModifier)(mod1 | mod2);
6510 template UnittestFuncInfo(alias f)
6512 enum name = __traits(identifier, f);
6513 alias type = FunctionTypeOf!f;
6518 int draw() { return 1; }
6519 @property int value() { return 2; }
6520 final int run() { return 3; }
6522 alias methods = GetOverloadedMethods!A;
6525 alias @property int F2();
6527 alias nothrow @trusted uint F4();
6528 alias int F5(Object);
6529 alias bool F6(Object);
6530 static assert(methods.length == 3 + 4);
6531 static assert(__traits(identifier, methods[0]) == "draw" && is(typeof(&methods[0]) == F1*));
6532 static assert(__traits(identifier, methods[1]) == "value" && is(typeof(&methods[1]) == F2*));
6533 static assert(__traits(identifier, methods[2]) == "run" && is(typeof(&methods[2]) == F1*));
6536 @property int value();
6539 static assert(findCovariantFunction!(UnittestFuncInfo!draw, A, methods) == 0);
6540 static assert(findCovariantFunction!(UnittestFuncInfo!value, A, methods) == 1);
6541 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1);
6542 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, A, methods) == -1);
6544 // considering opDispatch
6547 void opDispatch(string name, A...)(A) {}
6549 alias methodsB = GetOverloadedMethods!B;
6550 static assert(findCovariantFunction!(UnittestFuncInfo!draw, B, methodsB) == ptrdiff_t.max);
6551 static assert(findCovariantFunction!(UnittestFuncInfo!value, B, methodsB) == ptrdiff_t.max);
6552 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max);
6553 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, B, methodsB) == ptrdiff_t.max);
6556 package template DerivedFunctionType(T...)
6558 static if (!T.length)
6560 alias DerivedFunctionType = void;
6562 else static if (T.length == 1)
6564 static if (is(T[0] == function))
6566 alias DerivedFunctionType = T[0];
6570 alias DerivedFunctionType = void;
6573 else static if (is(T[0] P0 == function) && is(T[1] P1 == function))
6575 alias FA = FunctionAttribute;
6577 alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0;
6578 alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1;
6579 enum FA0 = functionAttributes!F0;
6580 enum FA1 = functionAttributes!F1;
6582 template CheckParams(size_t i = 0)
6584 static if (i >= P0.length)
6585 enum CheckParams = true;
6588 enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) &&
6589 CheckParams!(i + 1);
6592 static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) &&
6593 P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 &&
6594 variadicFunctionStyle!F0 == variadicFunctionStyle!F1 &&
6595 functionLinkage!F0 == functionLinkage!F1 &&
6596 ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0)
6598 alias R = Select!(is(R0 : R1), R0, R1);
6599 alias FX = FunctionTypeOf!(R function(P0));
6600 // @system is default
6601 alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system);
6602 alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]);
6605 alias DerivedFunctionType = void;
6608 alias DerivedFunctionType = void;
6612 // attribute covariance
6614 static assert(is(DerivedFunctionType!(F1, F1) == F1));
6615 alias int F2() pure nothrow;
6616 static assert(is(DerivedFunctionType!(F1, F2) == F2));
6617 alias int F3() @safe;
6618 alias int F23() @safe pure nothrow;
6619 static assert(is(DerivedFunctionType!(F2, F3) == F23));
6621 // return type covariance
6623 static assert(is(DerivedFunctionType!(F1, F4) == void));
6628 static assert(is(DerivedFunctionType!(F5, F6) == F6));
6629 alias typeof(null) F7();
6632 static assert(is(DerivedFunctionType!(F5, F7) == F7));
6633 static assert(is(DerivedFunctionType!(F7, F8) == void));
6634 static assert(is(DerivedFunctionType!(F7, F9) == F7));
6636 // variadic type equality
6638 alias int F11(int...);
6639 alias int F12(int, ...);
6640 static assert(is(DerivedFunctionType!(F10, F11) == void));
6641 static assert(is(DerivedFunctionType!(F10, F12) == void));
6642 static assert(is(DerivedFunctionType!(F11, F12) == void));
6645 alias extern(C) int F13(int);
6646 alias extern(D) int F14(int);
6647 alias extern(Windows) int F15(int);
6648 static assert(is(DerivedFunctionType!(F13, F14) == void));
6649 static assert(is(DerivedFunctionType!(F13, F15) == void));
6650 static assert(is(DerivedFunctionType!(F14, F15) == void));
6652 // ref & @property equality
6654 alias ref int F17(int);
6655 alias @property int F18(int);
6656 static assert(is(DerivedFunctionType!(F16, F17) == void));
6657 static assert(is(DerivedFunctionType!(F16, F18) == void));
6658 static assert(is(DerivedFunctionType!(F17, F18) == void));
6661 package template Bind(alias Template, args1...)
6663 alias Bind(args2...) = Template!(args1, args2);
6668 Options regarding auto-initialization of a `SafeRefCounted` object (see
6669 the definition of `SafeRefCounted` below).
6671 enum RefCountedAutoInitialize
6673 /// Do not auto-initialize the object
6675 /// Auto-initialize the object
6682 import core.exception : AssertError;
6683 import std.exception : assertThrown;
6690 SafeRefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto;
6691 SafeRefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto;
6693 assert(rcAuto.refCountedPayload.a == 42);
6695 assertThrown!AssertError(rcNoAuto.refCountedPayload);
6696 rcNoAuto.refCountedStore.ensureInitialized;
6697 assert(rcNoAuto.refCountedPayload.a == 42);
6700 // Same the above but for old RefCounted and not documented
6703 import core.exception : AssertError;
6704 import std.exception : assertThrown;
6711 RefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto;
6712 RefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto;
6714 assert(rcAuto.refCountedPayload.a == 42);
6716 assertThrown!AssertError(rcNoAuto.refCountedPayload);
6717 rcNoAuto.refCountedStore.ensureInitialized;
6718 assert(rcNoAuto.refCountedPayload.a == 42);
6722 Defines a reference-counted object containing a `T` value as
6725 An instance of `SafeRefCounted` is a reference to a structure,
6726 which is referred to as the $(I store), or $(I storage implementation
6727 struct) in this documentation. The store contains a reference count
6728 and the `T` payload. `SafeRefCounted` uses `malloc` to allocate
6729 the store. As instances of `SafeRefCounted` are copied or go out of
6730 scope, they will automatically increment or decrement the reference
6731 count. When the reference count goes down to zero, `SafeRefCounted`
6732 will call `destroy` against the payload and call `free` to
6733 deallocate the store. If the `T` payload contains any references
6734 to GC-allocated memory, then `SafeRefCounted` will add it to the GC memory
6735 that is scanned for pointers, and remove it from GC scanning before
6736 `free` is called on the store.
6738 One important consequence of `destroy` is that it will call the
6739 destructor of the `T` payload. GC-managed references are not
6740 guaranteed to be valid during a destructor call, but other members of
6741 `T`, such as file handles or pointers to `malloc` memory, will
6742 still be valid during the destructor call. This allows the `T` to
6743 deallocate or clean up any non-GC resources immediately after the
6744 reference count has reached zero.
6746 Without -preview=dip1000, `SafeRefCounted` is unsafe and should be
6747 used with care. No references to the payload should be escaped outside
6748 the `SafeRefCounted` object.
6750 With -preview=dip1000, `SafeRefCounted` is safe if it's payload is accessed only
6751 with the $(LREF borrow) function. Scope semantics can also prevent accidental
6752 escaping of `refCountedPayload`, but it's still up to the user to not destroy
6753 the last counted reference while the payload is in use. Due to that,
6754 `refCountedPayload` remains accessible only in `@system` code.
6756 The `autoInit` option makes the object ensure the store is
6757 automatically initialized. Leaving $(D autoInit ==
6758 RefCountedAutoInitialize.yes) (the default option) is convenient but
6759 has the cost of a test whenever the payload is accessed. If $(D
6760 autoInit == RefCountedAutoInitialize.no), user code must call either
6761 `refCountedStore.isInitialized` or `refCountedStore.ensureInitialized`
6762 before attempting to access the payload. Not doing so results in null
6763 pointer dereference.
6765 If `T.this()` is annotated with `@disable` then `autoInit` must be
6766 `RefCountedAutoInitialize.no` in order to compile.
6771 struct SafeRefCounted(T, RefCountedAutoInitialize autoInit =
6772 RefCountedAutoInitialize.yes)
6773 if (!is(T == class) && !(is(T == interface)))
6777 private enum enableGCScan = false;
6781 private enum enableGCScan = hasIndirections!T;
6784 extern(C) private pure nothrow @nogc static
6786 pragma(mangle, "free") void pureFree( void *ptr );
6787 static if (enableGCScan)
6788 import core.memory : GC;
6791 pragma(inline, true) private void checkInit()()
6792 if (autoInit == RefCountedAutoInitialize.yes)
6794 _refCounted.ensureInitialized();
6797 pragma(inline, true) private void checkInit()() inout
6798 if (autoInit == RefCountedAutoInitialize.no)
6800 assert(_refCounted.isInitialized,
6801 "Attempted to use an uninitialized payload.");
6804 /// `SafeRefCounted` storage implementation.
6805 struct RefCountedStore
6813 private Impl* _store;
6815 private void initialize(A...)(auto ref A args)
6817 import core.lifetime : emplace, forward;
6820 version (D_Exceptions) scope(failure) () @trusted { deallocateStore(); }();
6821 emplace(&_store._payload, forward!args);
6825 private void move(ref T source) nothrow pure
6827 import std.algorithm.mutation : moveEmplace;
6830 () @trusted { moveEmplace(source, _store._payload); }();
6834 // 'nothrow': can only generate an Error
6835 private void allocateStore() nothrow pure
6837 static if (enableGCScan)
6839 import std.internal.memory : enforceCalloc;
6840 auto ptr = enforceCalloc(1, Impl.sizeof);
6841 _store = () @trusted { return cast(Impl*) ptr; }();
6842 () @trusted { GC.addRange(&_store._payload, T.sizeof); }();
6846 import std.internal.memory : enforceMalloc;
6847 auto ptr = enforceMalloc(Impl.sizeof);
6848 _store = () @trusted { return cast(Impl*) ptr; }();
6852 private void deallocateStore() nothrow pure
6854 static if (enableGCScan)
6856 GC.removeRange(&this._store._payload);
6863 Returns `true` if and only if the underlying store has been
6864 allocated and initialized.
6866 @property nothrow @safe pure @nogc
6867 bool isInitialized() const
6869 return _store !is null;
6873 Returns underlying reference count if it is allocated and initialized
6874 (a positive integer), and `0` otherwise.
6876 @property nothrow @safe pure @nogc
6877 size_t refCount() const
6879 return isInitialized ? _store._count : 0;
6883 Makes sure the payload was properly initialized. Such a
6884 call is typically inserted before using the payload.
6886 This function is unavailable if `T.this()` is annotated with
6890 void ensureInitialized()()
6892 // By checking for `@disable this()` and failing early we can
6893 // produce a clearer error message.
6894 static assert(__traits(compiles, { static T t; }),
6895 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~
6896 "` because `" ~ fullyQualifiedName!T ~
6897 ".this()` is annotated with `@disable`.");
6898 if (!isInitialized) initialize();
6902 RefCountedStore _refCounted;
6904 /// Returns storage implementation struct.
6905 @property nothrow @safe
6906 ref inout(RefCountedStore) refCountedStore() inout
6912 Constructor that initializes the payload.
6914 Postcondition: `refCountedStore.isInitialized`
6916 this(A...)(auto ref A args) if (A.length > 0)
6919 assert(refCountedStore.isInitialized);
6923 import core.lifetime : forward;
6924 _refCounted.initialize(forward!args);
6928 this(return scope T val)
6930 _refCounted.move(val);
6934 Constructor that tracks the reference count appropriately. If $(D
6935 !refCountedStore.isInitialized), does nothing.
6937 this(this) @safe pure nothrow @nogc
6939 if (!_refCounted.isInitialized) return;
6940 ++_refCounted._store._count;
6944 Destructor that tracks the reference count appropriately. If $(D
6945 !refCountedStore.isInitialized), does nothing. When the reference count goes
6946 down to zero, calls `destroy` agaist the payload and calls `free`
6947 to deallocate the corresponding resource.
6951 import std.traits : dip1000Enabled;
6953 // This prevents the same reference from decrementing the count twice.
6954 scope(exit) _refCounted = _refCounted.init;
6956 if (!_refCounted.isInitialized) return;
6957 assert(_refCounted._store._count > 0);
6958 if (--_refCounted._store._count) return;
6959 // Done, destroy and deallocate
6960 .destroy(_refCounted._store._payload);
6962 static if (dip1000Enabled)
6964 () @trusted { _refCounted.deallocateStore(); }();
6966 else _refCounted.deallocateStore();
6970 Assignment operators.
6972 Note: You may not assign a new payload to an uninitialized SafeRefCounted, if
6973 auto initialization is off. Assigning another counted reference is still okay.
6975 void opAssign(typeof(this) rhs)
6977 import std.algorithm.mutation : swap;
6979 swap(_refCounted._store, rhs._refCounted._store);
6983 void opAssign(T rhs)
6985 import std.algorithm.mutation : move;
6988 move(rhs, _refCounted._store._payload);
6991 //version to have a single properly ddoc'ed function (w/ correct sig)
6995 Returns a reference to the payload. If (autoInit ==
6996 RefCountedAutoInitialize.yes), calls $(D
6997 refCountedStore.ensureInitialized). Otherwise, just issues $(D
6998 assert(refCountedStore.isInitialized)). Used with $(D alias
6999 refCountedPayload this;), so callers can just use the `SafeRefCounted`
7002 $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
7003 So if $(D autoInit == RefCountedAutoInitialize.no)
7004 or called for a constant or immutable object, then
7005 `refCountedPayload` will also be qualified as nothrow
7006 (but will still assert if not initialized).
7009 ref T refCountedPayload() return;
7012 @property nothrow @system pure @nogc
7013 ref inout(T) refCountedPayload() inout return;
7017 static if (autoInit == RefCountedAutoInitialize.yes)
7019 //Can't use inout here because of potential mutation
7021 ref T refCountedPayload() return
7024 return _refCounted._store._payload;
7029 @property nothrow @system pure @nogc
7030 ref inout(T) refCountedPayload() inout return
7033 return _refCounted._store._payload;
7039 Returns a reference to the payload. If (autoInit ==
7040 RefCountedAutoInitialize.yes), calls $(D
7041 refCountedStore.ensureInitialized). Otherwise, just issues $(D
7042 assert(refCountedStore.isInitialized)).
7044 alias refCountedPayload this;
7046 static if (is(T == struct) && !is(typeof((ref T t) => t.toString())))
7048 string toString(this This)()
7050 import std.conv : to;
7052 static if (autoInit)
7053 return to!string(refCountedPayload);
7056 if (!_refCounted.isInitialized)
7057 return This.stringof ~ "(RefCountedStore(null))";
7059 return to!string(_refCounted._store._payload);
7066 @betterC pure @system nothrow @nogc unittest
7068 // A pair of an `int` and a `size_t` - the latter being the
7069 // reference count - will be dynamically allocated
7070 auto rc1 = SafeRefCounted!int(5);
7072 // No more allocation, add just one extra reference count
7074 // Reference semantics
7077 // the pair will be freed when rc1 and rc2 go out of scope
7080 // This test can't be betterC because the test extractor won't see the private
7081 // `initialize` method accessed here
7082 pure @safe nothrow @nogc unittest
7084 auto rc1 = SafeRefCounted!(int, RefCountedAutoInitialize.no)(5);
7085 rc1._refCounted.initialize();
7088 pure @system unittest
7090 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7092 MyRefCounted!int* p;
7094 auto rc1 = MyRefCounted!int(5);
7097 assert(rc1._refCounted._store._count == 1);
7099 assert(rc1._refCounted._store._count == 2);
7100 // Reference semantics
7104 assert(rc2._refCounted._store._count == 2);
7106 assert(rc1._refCounted._store._count == 2);
7108 assert(p._refCounted._store == null);
7110 // [Safe]RefCounted as a member
7116 x._refCounted.initialize(y);
7120 auto another = this;
7126 assert(a.x._refCounted._store._count == 2,
7127 "https://issues.dlang.org/show_bug.cgi?id=4356 still unfixed");
7131 @betterC pure @safe nothrow @nogc unittest
7133 import std.algorithm.mutation : swap;
7135 SafeRefCounted!int p1, p2;
7139 // Same as above but for old RefCounted and not @safe
7140 @betterC pure @system nothrow @nogc unittest
7142 import std.algorithm.mutation : swap;
7144 RefCounted!int p1, p2;
7148 // https://issues.dlang.org/show_bug.cgi?id=6606
7149 @betterC @safe pure nothrow @nogc unittest
7160 alias SRC = SafeRefCounted!S;
7163 // Same as above but for old RefCounted and not @safe
7164 @betterC @system pure nothrow @nogc unittest
7175 alias SRC = RefCounted!S;
7178 // https://issues.dlang.org/show_bug.cgi?id=6436
7179 @betterC @system pure unittest
7181 import std.meta : AliasSeq;
7184 this(int rval) { assert(rval == 1); }
7185 this(ref int lval) { assert(lval == 3); ++lval; }
7188 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7190 auto s1 = MyRefCounted!S(1);
7192 auto s2 = MyRefCounted!S(lval);
7197 // gc_addRange coverage
7198 @betterC @safe pure unittest
7200 struct S { int* p; }
7202 auto s = SafeRefCounted!S(null);
7205 // Same as above but for old RefCounted and not @safe
7206 @betterC @system pure unittest
7208 struct S { int* p; }
7210 auto s = RefCounted!S(null);
7213 @betterC @system pure nothrow @nogc unittest
7215 import std.meta : AliasSeq;
7216 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7219 a = 5; //This should not assert
7223 b = a; //This should not assert either
7226 MyRefCounted!(int*) c;
7230 // https://issues.dlang.org/show_bug.cgi?id=21638
7231 @betterC @system pure nothrow @nogc unittest
7233 import std.meta : AliasSeq;
7234 static struct NoDefaultCtor
7237 this(int x) @nogc nothrow pure { this.x = x; }
7241 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7243 auto rc = MyRefCounted!(NoDefaultCtor, RefCountedAutoInitialize.no)(5);
7248 // https://issues.dlang.org/show_bug.cgi?id=20502
7251 alias Types = AliasSeq!(SafeRefCounted, RefCounted);
7252 alias funcs = AliasSeq!(safeRefCounted, refCounted);
7253 static foreach (aliasI; 0 .. 2)
7255 alias MyRefCounted = Types[aliasI];
7256 alias myRefCounted = funcs[aliasI];
7257 import std.conv : to;
7259 // Check that string conversion is transparent for refcounted
7260 // structs that do not have either toString or alias this.
7261 static struct A { Object a; }
7262 auto a = A(new Object());
7263 auto r = myRefCounted(a);
7264 assert(to!string(r) == to!string(a));
7265 assert(to!string(cast(const) r) == to!string(cast(const) a));
7266 // Check that string conversion is still transparent for refcounted
7267 // structs that have alias this.
7268 static struct B { int b; alias b this; }
7269 static struct C { B b; alias b this; }
7270 assert(to!string(myRefCounted(C(B(123)))) == to!string(C(B(123))));
7271 // https://issues.dlang.org/show_bug.cgi?id=22093
7272 // Check that uninitialized refcounted structs that previously could be
7273 // converted to strings still can be.
7274 alias R = typeof(r);
7276 cast(void) (((const ref R a) => to!string(a))(r2));
7277 cast(void) to!string(MyRefCounted!(A, RefCountedAutoInitialize.no).init);
7281 // We tried to make `refCountedPayload` `@safe` in
7282 // https://github.com/dlang/phobos/pull/8368 . It proved impossible, but it may
7283 // be possible in the future. This test checks for false `@safe` issues we
7292 int[] getArr1 (scope Container local)
7294 // allowed because the argument is inferred as return scope.
7298 int[] getArr2 (scope Container local)
7300 SafeRefCounted!Container rc = local;
7301 // Escapes a reference to expired reference counted struct
7303 return rc.refCountedPayload().data;
7306 int destroyFirstAndUseLater()
7308 auto rc = SafeRefCounted!int(123);
7309 int* ptr = &rc.refCountedPayload();
7314 // This is here mainly to test that safety gets inferred correctly for the
7316 static assert(isSafe!getArr1);
7317 // https://github.com/dlang/phobos/pull/8101#issuecomment-843017282
7318 // This got apparently fixed automatically by compiler updates.
7319 static assert(!isSafe!getArr2);
7320 // As of writing, this is the issue that is still preventing payload access
7321 // from being `@safe`
7322 static assert(!isSafe!destroyFirstAndUseLater);
7326 Borrows the payload of $(LREF SafeRefCounted) for use in `fun`. Inferred as `@safe`
7327 if `fun` is `@safe` and does not escape a reference to the payload.
7328 The reference count will be incremented for the duration of the operation,
7329 so destroying the last reference will not leave dangling references in
7333 fun = A callable accepting the payload either by value or by reference.
7334 refCount = The counted reference to the payload.
7336 The return value of `fun`, if any. `ref` in the return value will be
7339 For yet unknown reason, code that uses this function with UFCS syntax
7340 will not be inferred as `@safe`. It will still compile if the code is
7341 explicitly marked `@safe` and nothing in `fun` prevents that.
7343 template borrow(alias fun)
7345 import std.functional : unaryFun;
7347 auto ref borrow(RC)(RC refCount) if
7349 isInstanceOf!(SafeRefCounted, RC)
7350 && is(typeof(unaryFun!fun(refCount.refCountedPayload)))
7353 refCount.checkInit();
7355 // If `fun` escapes a reference to the payload, it will be inferred
7356 // as unsafe due to the scope storage class here.
7357 scope plPtr = &refCount._refCounted._store._payload;
7358 return unaryFun!fun(*plPtr);
7360 // We destroy our copy of the reference here, automatically destroying
7361 // the payload if `fun` destroyed the last reference outside.
7365 /// This example can be marked `@safe` with `-preview=dip1000`.
7366 @safe pure nothrow unittest
7368 auto rcInt = safeRefCounted(5);
7369 assert(rcInt.borrow!(theInt => theInt) == 5);
7370 auto sameInt = rcInt;
7371 assert(sameInt.borrow!"a" == 5);
7373 // using `ref` in the function
7374 auto arr = [0, 1, 2, 3, 4, 5, 6];
7375 sameInt.borrow!(ref (x) => arr[x]) = 10;
7376 assert(arr == [0, 1, 2, 3, 4, 10, 6]);
7378 // modifying the payload via an alias
7379 sameInt.borrow!"a*=2";
7380 assert(rcInt.borrow!"a" == 10);
7383 // Some memory safety penetration testing.
7387 int torpedoesFired = 0;
7388 struct Destroyer { ~this() @safe { torpedoesFired++; } }
7390 alias RcInt = typeof(safeRefCounted(0));
7391 auto standardUsage(RcInt arg)
7393 return borrow!((ref x) => x)(arg);
7395 ref harmlessRefReturn(RcInt arg)
7397 return borrow!(ref (ref x) => *globalPtr = x)(arg);
7399 ref problematicRefReturn(RcInt arg)
7401 return borrow!(ref (ref x) => x)(arg);
7403 auto sideChannelEscape(RcInt arg)
7405 return borrow!((ref x)
7411 auto destroyDuringApply()
7413 auto rc = safeRefCounted(Destroyer());
7414 return borrow!((ref x)
7416 // Destroys the last reference to the payload, decrementing it's
7419 // Destroy again! rc should be set to it's init value so that this
7420 // won't decrement the reference count of the original payload.
7422 // The internal reference count increment done for duration of
7423 // `apply` should make sure that the payload destructor is not yet
7424 // run, and this value thus not incremented.
7425 return torpedoesFired;
7429 // First, let's verify the dangerous functions really do what they are
7431 auto testRc = safeRefCounted(42);
7432 assert(sideChannelEscape(testRc) == 42);
7433 assert(&problematicRefReturn(testRc) == globalPtr);
7435 // Now, are the @safe attributes inferred correctly?
7436 assert(isSafe!standardUsage);
7437 assert(isSafe!harmlessRefReturn);
7438 assert(!isSafe!problematicRefReturn);
7439 assert(!isSafe!sideChannelEscape);
7440 assert(isSafe!destroyDuringApply);
7442 // Finally, we test protection against early destruction during `apply`.
7443 auto torpedoesUpToReturn = destroyDuringApply();
7444 assert(torpedoesFired == torpedoesUpToReturn + 1);
7448 * Initializes a `SafeRefCounted` with `val`. The template parameter
7449 * `T` of `SafeRefCounted` is inferred from `val`.
7450 * This function can be used to move non-copyable values to the heap.
7451 * It also disables the `autoInit` option of `SafeRefCounted`.
7454 * val = The value to be reference counted
7456 * An initialized `SafeRefCounted` containing `val`.
7458 * $(LREF refCounted)
7459 * $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared)
7461 SafeRefCounted!(T, RefCountedAutoInitialize.no) safeRefCounted(T)(T val)
7464 res._refCounted.move(val);
7473 static size_t nDestroyed;
7475 @disable this(this); // not copyable
7476 ~this() { name = null; ++nDestroyed; }
7479 auto file = File("name");
7480 assert(file.name == "name");
7481 // file cannot be copied and has unique ownership
7482 static assert(!__traits(compiles, {auto file2 = file;}));
7484 assert(File.nDestroyed == 0);
7486 // make the file ref counted to share ownership
7488 // We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted.
7489 // This allows us to see (after the scope) what happens after all handles have been destroyed.
7491 // We move the content of `file` to a separate (and heap-allocated) `File` object,
7492 // managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles").
7494 // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`);
7495 // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`).
7496 // It appears that writing `name = null;` in the destructor is redundant,
7497 // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator),
7498 // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor.
7499 import std.algorithm.mutation : move;
7500 auto rcFile = safeRefCounted(move(file));
7501 assert(rcFile.name == "name");
7502 assert(File.nDestroyed == 1);
7503 assert(file.name == null);
7505 // We create another `SafeRefCounted!File` handle to the same separate `File` object.
7506 // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified).
7507 auto rcFile2 = rcFile;
7508 assert(rcFile.refCountedStore.refCount == 2);
7509 assert(File.nDestroyed == 1);
7511 // The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed
7512 // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`)
7513 // (=> `File.nDestroyed` is incremented again, from 1 to 2):
7514 assert(File.nDestroyed == 2);
7518 Creates a proxy for the value `a` that will forward all operations
7519 while disabling implicit conversions. The aliased item `a` must be
7520 an $(B lvalue). This is useful for creating a new type from the
7521 "base" type (though this is $(B not) a subtype-supertype
7522 relationship; the new type is not related to the old type in any way,
7525 The new type supports all operations that the underlying type does,
7526 including all operators such as `+`, `--`, `<`, `[]`, etc.
7529 a = The value to act as a proxy for all operations. It must
7532 mixin template Proxy(alias a)
7534 private alias ValueType = typeof({ return a; }());
7536 /* Determine if 'T.a' can referenced via a const(T).
7537 * Use T* as the parameter because 'scope' inference needs a fully
7538 * analyzed T, which doesn't work when accessibleFrom() is used in a
7539 * 'static if' in the definition of Proxy or T.
7541 private enum bool accessibleFrom(T) =
7542 is(typeof((T* self){ cast(void) mixin("(*self)."~__traits(identifier, a)); }));
7544 static if (is(typeof(this) == class))
7546 override bool opEquals(Object o)
7548 if (auto b = cast(typeof(this))o)
7550 return a == mixin("b."~__traits(identifier, a));
7555 bool opEquals(T)(T b)
7556 if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
7558 static if (is(typeof(a.opEquals(b))))
7559 return a.opEquals(b);
7560 else static if (is(typeof(b.opEquals(a))))
7561 return b.opEquals(a);
7566 override int opCmp(Object o)
7568 if (auto b = cast(typeof(this))o)
7570 return a < mixin("b."~__traits(identifier, a)) ? -1
7571 : a > mixin("b."~__traits(identifier, a)) ? +1 : 0;
7573 static if (is(ValueType == class))
7576 throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString);
7579 int opCmp(T)(auto ref const T b)
7580 if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
7582 static if (is(typeof(a.opCmp(b))))
7584 else static if (is(typeof(b.opCmp(a))))
7587 return a < b ? -1 : a > b ? +1 : 0;
7590 static if (accessibleFrom!(const typeof(this)))
7592 override size_t toHash() const nothrow @safe
7594 static if (__traits(compiles, .hashOf(a)))
7597 // Workaround for when .hashOf is not both @safe and nothrow.
7599 static if (is(typeof(&a) == ValueType*))
7602 auto v = a; // if a is (property) function
7603 // BUG: Improperly casts away `shared`!
7604 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)());
7611 auto ref opEquals(this X, B)(auto ref B b)
7613 static if (is(immutable B == immutable typeof(this)))
7615 return a == mixin("b."~__traits(identifier, a));
7621 auto ref opCmp(this X, B)(auto ref B b)
7623 static if (is(typeof(a.opCmp(b))))
7625 else static if (is(typeof(b.opCmp(a))))
7627 else static if (isFloatingPoint!ValueType || isFloatingPoint!B)
7628 return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan;
7630 return a < b ? -1 : (a > b);
7633 static if (accessibleFrom!(const typeof(this)))
7635 size_t toHash() const nothrow @safe
7637 static if (__traits(compiles, .hashOf(a)))
7640 // Workaround for when .hashOf is not both @safe and nothrow.
7642 static if (is(typeof(&a) == ValueType*))
7645 auto v = a; // if a is (property) function
7646 // BUG: Improperly casts away `shared`!
7647 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)());
7653 auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); }
7655 auto ref opCast(T, this X)() { return cast(T) a; }
7657 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; }
7658 auto ref opSlice(this X )() { return a[]; }
7659 auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b .. e]; }
7661 auto ref opUnary (string op, this X )() { return mixin(op~"a"); }
7662 auto ref opIndexUnary(string op, this X, D...)(auto ref D i) { return mixin(op~"a[i]"); }
7663 auto ref opSliceUnary(string op, this X )() { return mixin(op~"a[]"); }
7664 auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b .. e]"); }
7666 auto ref opBinary(string op, this X, B)(auto ref B b)
7667 if (op == "in" && is(typeof(a in b)) || op != "in")
7669 return mixin("a "~op~" b");
7671 auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); }
7673 static if (!is(typeof(this) == class))
7676 static if (isAssignable!ValueType)
7678 auto ref opAssign(this X)(auto ref typeof(this) v)
7680 a = mixin("v."~__traits(identifier, a));
7686 @disable void opAssign(this X)(auto ref typeof(this) v);
7690 auto ref opAssign (this X, V )(auto ref V v) if (!is(V == typeof(this))) { return a = v; }
7691 auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i) { return a[i] = v; }
7692 auto ref opSliceAssign(this X, V )(auto ref V v) { return a[] = v; }
7693 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; }
7695 auto ref opOpAssign (string op, this X, V )(auto ref V v)
7697 return mixin("a = a "~op~" v");
7699 auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i)
7701 return mixin("a[i] " ~op~"= v");
7703 auto ref opSliceOpAssign(string op, this X, V )(auto ref V v)
7705 return mixin("a[] " ~op~"= v");
7707 auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e)
7709 return mixin("a[b .. e] "~op~"= v");
7712 template opDispatch(string name)
7714 static if (is(typeof(__traits(getMember, a, name)) == function))
7716 // non template function
7717 auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); }
7719 else static if (is(typeof({ enum x = mixin("a."~name); })))
7721 // built-in type field, manifest constant, and static non-mutable field
7722 enum opDispatch = mixin("a."~name);
7724 else static if (__traits(isTemplate, mixin("a."~name)))
7727 template opDispatch(T...)
7729 enum targs = T.length ? "!T" : "";
7730 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
7735 // field or property function
7736 @property auto ref opDispatch(this X)() { return mixin("a."~name); }
7737 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
7742 import std.traits : isArray;
7744 static if (isArray!ValueType)
7746 auto opDollar() const { return a.length; }
7748 else static if (is(typeof(a.opDollar!0)))
7750 auto ref opDollar(size_t pos)() { return a.opDollar!pos(); }
7752 else static if (is(typeof(a.opDollar) == function))
7754 auto ref opDollar() { return a.opDollar(); }
7756 else static if (is(typeof(a.opDollar)))
7758 alias opDollar = a.opDollar;
7770 this(int n){ value = n; }
7775 // Enable operations that original type has.
7778 assert(n * 2 == 22);
7780 void func(int n) { }
7782 // Disable implicit conversions to original type.
7787 ///The proxied value must be an $(B lvalue).
7792 //Won't work; the literal '1'
7793 //is an rvalue, not an lvalue
7796 //Okay, n is an lvalue
7800 this(int n) { this.n = n; }
7808 struct NewObjectType
7811 //Ok, obj is an lvalue
7814 this (Object o) { obj = o; }
7817 NewObjectType not = new Object();
7818 assert(__traits(compiles, not.toHash()));
7822 There is one exception to the fact that the new type is not related to the
7823 old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member)
7824 functions are usable with the new type; they will be forwarded on to the
7829 import std.math.traits : isInfinity;
7832 assert(!f.isInfinity);
7839 this(float f) { _ = f; }
7843 assert(!nf.isInfinity);
7852 this(int n) inout { value = n; }
7855 static immutable arr = [1,2,3];
7858 static foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt))
7861 static assert(!__traits(compiles, { int x = m; }));
7862 static assert(!__traits(compiles, { void func(int n){} func(m); }));
7868 assert(cast(double) m == 10.0);
7869 assert(m + 10 == 20);
7871 assert(m * 20 == 200);
7873 assert(10 + m == 20);
7874 assert(15 - m == 5);
7875 assert(20 * m == 200);
7876 assert(50 / m == 5);
7877 static if (is(T == MyInt)) // mutable
7880 assert(m++ == 11); assert(m == 12);
7882 assert(m-- == 11); assert(m == 10);
7884 m = 20; assert(m == 20);
7886 static assert(T.max == int.max);
7887 static assert(T.min == int.min);
7888 static assert(T.init == int.init);
7889 static assert(T.str == "str");
7890 static assert(T.arr == [1,2,3]);
7895 static struct MyArray
7897 private int[] value;
7899 this(int[] arr) { value = arr; }
7900 this(immutable int[] arr) immutable { value = arr; }
7903 static foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray))
7905 static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; })))
7906 T a = [1,2,3,4].idup; // workaround until qualified ctor is properly supported
7909 assert(a == [1,2,3,4]);
7910 assert(a != [5,6,7,8]);
7912 version (LittleEndian)
7913 assert(cast(ulong[]) a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]);
7915 assert(cast(ulong[]) a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]);
7916 assert(a ~ [10,11] == [1,2,3,4,10,11]);
7918 assert(a[] == [1,2,3,4]);
7919 assert(a[2 .. 4] == [3,4]);
7920 static if (is(T == MyArray)) // mutable
7923 a = [5,6,7,8]; assert(a == [5,6,7,8]);
7924 a[0] = 0; assert(a == [0,6,7,8]);
7925 a[] = 1; assert(a == [1,1,1,1]);
7926 a[0 .. 3] = 2; assert(a == [2,2,2,1]);
7927 a[0] += 2; assert(a == [4,2,2,1]);
7928 a[] *= 2; assert(a == [8,4,4,2]);
7929 a[0 .. 2] /= 2; assert(a == [4,2,4,2]);
7939 @property int val1() const { return field; }
7940 @property void val1(int n) { field = n; }
7942 @property ref int val2() { return field; }
7944 int func(int x, int y) const { return x; }
7945 void func1(ref int a) { a = 9; }
7947 T ifti1(T)(T t) { return t; }
7948 void ifti2(Args...)(Args args) { }
7949 void ifti3(T, Args...)(Args args) { }
7951 T opCast(T)(){ return T.init; }
7953 T tempfunc(T)() { return T.init; }
7959 this(Foo f) { foo = f; }
7962 auto h = new Hoge(new Foo());
7965 static assert(!__traits(compiles, { Foo f = h; }));
7968 h.field = 1; // lhs of assign
7969 n = h.field; // rhs of assign
7970 assert(h.field == 1); // lhs of BinExp
7971 assert(1 == h.field); // rhs of BinExp
7974 // getter/setter property function
7977 assert(h.val1 == 4);
7978 assert(4 == h.val1);
7981 // ref getter property function
7984 assert(h.val2 == 8);
7985 assert(8 == h.val2);
7989 assert(h.func(2,4) == 2);
7994 assert(h.ifti1(4) == 4);
7998 // https://issues.dlang.org/show_bug.cgi?id=5896 test
7999 assert(h.opCast!int() == 0);
8000 assert(cast(int) h == 0);
8001 const ih = new const Hoge(new Foo());
8002 static assert(!__traits(compiles, ih.opCast!int()));
8003 static assert(!__traits(compiles, cast(int) ih));
8005 // template member function
8006 assert(h.tempfunc!int() == 0);
8009 @system unittest // about Proxy inside a class
8014 mixin Proxy!payload;
8015 this(int i){ payload = i; }
8016 string opCall(string msg){ return msg; }
8017 int pow(int i){ return payload ^^ i; }
8023 mixin Proxy!payload;
8024 this(int i){ payload = new MyClass(i); }
8030 mixin Proxy!payload;
8031 this(int i){ payload = i; }
8035 Object a = new MyClass(5);
8036 Object b = new MyClass(5);
8037 Object c = new MyClass2(5);
8038 Object d = new MyClass3(5);
8040 assert((cast(MyClass) a) == 5);
8041 assert(5 == (cast(MyClass) b));
8042 assert(5 == cast(MyClass2) c);
8046 // oops! above line is unexpected, isn't it?
8047 // the reason is below.
8048 // MyClass2.opEquals knows MyClass but,
8049 // MyClass.opEquals doesn't know MyClass2.
8050 // so, c.opEquals(a) is true, but a.opEquals(c) is false.
8051 // furthermore, opEquals(T) couldn't be invoked.
8052 assert((cast(MyClass2) c) != (cast(MyClass) a));
8055 Object e = new MyClass2(7);
8056 assert(a < cast(MyClass2) e); // OK. and
8057 assert(e > a); // OK, but...
8058 // assert(a < e); // RUNTIME ERROR!
8059 // assert((cast(MyClass) a) < e); // RUNTIME ERROR!
8060 assert(3 < cast(MyClass) a);
8061 assert((cast(MyClass2) e) < 11);
8064 assert((cast(MyClass2) e)("hello") == "hello");
8067 assert((cast(MyClass)(cast(MyClass2) c)) == a);
8068 assert((cast(int)(cast(MyClass2) c)) == 5);
8074 mixin Proxy!payload;
8075 this(string s){ payload = s; }
8080 mixin Proxy!payload;
8081 this(string s){ payload = new MyClass4(s); }
8083 auto f = new MyClass4("hello");
8084 assert(f[1] == 'e');
8085 auto g = new MyClass5("hello");
8086 assert(f[1] == 'e');
8089 assert(f[2 .. 4] == "ll");
8092 assert(-(cast(MyClass2) c) == -5);
8095 assert((cast(MyClass) a) + (cast(MyClass2) c) == 10);
8096 assert(5 + cast(MyClass) a == 10);
8099 (cast(MyClass2) c) = 11;
8100 assert((cast(MyClass2) c) == 11);
8101 (cast(MyClass2) c) = new MyClass(13);
8102 assert((cast(MyClass2) c) == 13);
8105 assert((cast(MyClass2) c) += 4);
8106 assert((cast(MyClass2) c) == 17);
8109 assert((cast(MyClass2) c).pow(2) == 289);
8112 assert(f[2..$-1] == "ll");
8118 assert(hash[b] == 19);
8119 assert(hash[c] == 21);
8128 mixin Proxy!payload;
8136 @disable void opAssign(typeof(this));
8142 mixin Proxy!payload;
8145 static assert(!__traits(compiles, f = f));
8151 mixin Proxy!payload;
8153 // override default Proxy behavior
8154 void opAssign(typeof(this) rhs){}
8160 // https://issues.dlang.org/show_bug.cgi?id=8613
8167 this(string s) { val = s; }
8171 names[Name("a")] = true;
8172 bool* b = Name("a") in names;
8175 // workaround for https://issues.dlang.org/show_bug.cgi?id=19669
8176 private enum isDIP1000 = __traits(compiles, () @safe {
8181 // excludes struct S; it's 'mixin Proxy!foo' doesn't compile with -dip1000
8182 static if (isDIP1000) {} else
8185 // https://issues.dlang.org/show_bug.cgi?id=14213
8186 // using function for the payload
8189 int foo() { return 12; }
8193 assert(s + 1 == 13);
8194 assert(s * 2 == 24);
8201 int foo() { return 12; }
8207 // Check all floating point comparisons for both Proxy and Typedef,
8208 // also against int and a Typedef!int, to be as regression-proof
8209 // as possible. https://issues.dlang.org/show_bug.cgi?id=15561
8212 static struct MyFloatImpl
8217 static void allFail(T0, T1)(T0 a, T1 b)
8225 static foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double,
8226 float, real, Typedef!int, int))
8228 static foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float))
8233 static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1))
8256 $(B Typedef) allows the creation of a unique type which is
8257 based on an existing type. Unlike the `alias` feature,
8258 $(B Typedef) ensures the two types are not considered as equals.
8262 init = Optional initial value for the new type.
8263 cookie = Optional, used to create multiple unique types which are
8264 based on the same origin type `T`
8266 Note: If a library routine cannot handle the Typedef type,
8267 you can use the `TypedefType` template to extract the
8268 type which the Typedef wraps.
8270 struct Typedef(T, T init = T.init, string cookie=null)
8272 private T Typedef_payload = init;
8274 // https://issues.dlang.org/show_bug.cgi?id=18415
8275 // prevent default construction if original type does too.
8276 static if ((is(T == struct) || is(T == union)) && !is(typeof({T t;})))
8283 Typedef_payload = init;
8288 this(tdef.Typedef_payload);
8291 // We need to add special overload for cast(Typedef!X) exp,
8292 // thus we can't simply inherit Proxy!Typedef_payload
8293 T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)()
8295 return T2(cast(T) Typedef_payload);
8298 auto ref opCast(T2, this X)()
8300 return cast(T2) Typedef_payload;
8303 mixin Proxy!Typedef_payload;
8305 pure nothrow @nogc @safe @property
8307 alias TD = typeof(this);
8308 static if (isIntegral!T)
8310 static TD min() {return TD(T.min);}
8311 static TD max() {return TD(T.max);}
8313 else static if (isFloatingPoint!T)
8315 static TD infinity() {return TD(T.infinity);}
8316 static TD nan() {return TD(T.nan);}
8317 static TD dig() {return TD(T.dig);}
8318 static TD epsilon() {return TD(T.epsilon);}
8319 static TD mant_dig() {return TD(T.mant_dig);}
8320 static TD max_10_exp() {return TD(T.max_10_exp);}
8321 static TD max_exp() {return TD(T.max_exp);}
8322 static TD min_10_exp() {return TD(T.min_10_exp);}
8323 static TD min_exp() {return TD(T.min_exp);}
8324 static TD max() {return TD(T.max);}
8325 static TD min_normal() {return TD(T.min_normal);}
8326 TD re() {return TD(Typedef_payload.re);}
8327 TD im() {return TD(Typedef_payload.im);}
8332 * Convert wrapped value to a human readable string
8334 string toString(this T)()
8336 import std.array : appender;
8337 auto app = appender!string();
8338 auto spec = singleSpec("%s");
8339 toString(app, spec);
8344 void toString(this T, W)(ref W writer, scope const ref FormatSpec!char fmt)
8345 if (isOutputRange!(W, char))
8347 formatValue(writer, Typedef_payload, fmt);
8353 import std.conv : to;
8356 auto td = Typedef!int(i);
8357 assert(i.to!string == td.to!string);
8364 alias MyInt = Typedef!int;
8370 /// custom initialization values
8373 alias MyIntInit = Typedef!(int, 42);
8374 static assert(is(TypedefType!MyIntInit == int));
8375 static assert(MyIntInit() == 42);
8378 /// Typedef creates a new type
8381 alias MyInt = Typedef!int;
8382 static void takeInt(int) {}
8383 static void takeMyInt(MyInt) {}
8387 static assert(!__traits(compiles, takeMyInt(i)));
8390 static assert(!__traits(compiles, takeInt(myInt)));
8391 takeMyInt(myInt); // ok
8394 /// Use the optional `cookie` argument to create different types of the same base type
8397 alias TypeInt1 = Typedef!int;
8398 alias TypeInt2 = Typedef!int;
8400 // The two Typedefs are the same type.
8401 static assert(is(TypeInt1 == TypeInt2));
8403 alias MoneyEuros = Typedef!(float, float.init, "euros");
8404 alias MoneyDollars = Typedef!(float, float.init, "dollars");
8406 // The two Typedefs are _not_ the same type.
8407 static assert(!is(MoneyEuros == MoneyDollars));
8410 // https://issues.dlang.org/show_bug.cgi?id=12461
8413 alias Int = Typedef!int;
8421 Get the underlying type which a `Typedef` wraps.
8422 If `T` is not a `Typedef` it will alias itself to `T`.
8424 template TypedefType(T)
8426 static if (is(T : Typedef!Arg, Arg))
8427 alias TypedefType = Arg;
8429 alias TypedefType = T;
8435 import std.conv : to;
8437 alias MyInt = Typedef!int;
8438 static assert(is(TypedefType!MyInt == int));
8440 /// Instantiating with a non-Typedef will return that type
8441 static assert(is(TypedefType!int == int));
8445 // extract the needed type
8446 MyInt myInt = MyInt( num.to!(TypedefType!MyInt) );
8449 // cast to the underlying type to get the value that's being wrapped
8450 int x = cast(TypedefType!MyInt) myInt;
8452 alias MyIntInit = Typedef!(int, 42);
8453 static assert(is(TypedefType!MyIntInit == int));
8454 static assert(MyIntInit() == 42);
8460 static assert(!__traits(compiles, { int y = x; }));
8461 static assert(!__traits(compiles, { long z = x; }));
8466 static assert(Typedef!int.init == int.init);
8468 Typedef!(float, 1.0) z; // specifies the init
8471 static assert(typeof(z).init == 1.0);
8473 alias Dollar = Typedef!(int, 0, "dollar");
8474 alias Yen = Typedef!(int, 0, "yen");
8475 static assert(!is(Dollar == Yen));
8477 Typedef!(int[3]) sa;
8478 static assert(sa.length == 3);
8479 static assert(typeof(sa).length == 3);
8481 Typedef!(int[3]) dollar1;
8482 assert(dollar1[0..$] is dollar1[0 .. 3]);
8484 Typedef!(int[]) dollar2;
8486 assert(dollar2[0..$] is dollar2[0 .. 3]);
8488 static struct Dollar1
8490 static struct DollarToken {}
8491 enum opDollar = DollarToken.init;
8492 auto opSlice(size_t, DollarToken) { return 1; }
8493 auto opSlice(size_t, size_t) { return 2; }
8496 Typedef!Dollar1 drange1;
8497 assert(drange1[0..$] == 1);
8498 assert(drange1[0 .. 1] == 2);
8500 static struct Dollar2
8502 size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; }
8503 size_t opIndex(size_t i, size_t j) { return i + j; }
8506 Typedef!Dollar2 drange2;
8507 assert(drange2[$, $] == 101);
8509 static struct Dollar3
8511 size_t opDollar() { return 123; }
8512 size_t opIndex(size_t i) { return i; }
8515 Typedef!Dollar3 drange3;
8516 assert(drange3[$] == 123);
8519 // https://issues.dlang.org/show_bug.cgi?id=18415
8520 @safe @nogc pure nothrow unittest
8522 struct NoDefCtorS{@disable this();}
8523 union NoDefCtorU{@disable this();}
8524 static assert(!is(typeof({Typedef!NoDefCtorS s;})));
8525 static assert(!is(typeof({Typedef!NoDefCtorU u;})));
8528 // https://issues.dlang.org/show_bug.cgi?id=11703
8529 @safe @nogc pure nothrow unittest
8531 alias I = Typedef!int;
8532 static assert(is(typeof(I.min) == I));
8533 static assert(is(typeof(I.max) == I));
8535 alias F = Typedef!double;
8536 static assert(is(typeof(F.infinity) == F));
8537 static assert(is(typeof(F.epsilon) == F));
8540 assert(!is(typeof(F.re).stringof == double));
8541 assert(!is(typeof(F.im).stringof == double));
8546 // https://issues.dlang.org/show_bug.cgi?id=8655
8547 import std.typecons;
8548 import std.bitmanip;
8549 static import core.stdc.config;
8551 alias c_ulong = Typedef!(core.stdc.config.c_ulong);
8556 c_ulong, "NameOffset", 31,
8557 c_ulong, "NameIsString", 1
8562 // https://issues.dlang.org/show_bug.cgi?id=12596
8565 import std.typecons;
8566 alias TD = Typedef!int;
8572 @safe unittest // about toHash
8574 import std.typecons;
8576 alias TD = Typedef!int;
8579 assert(td[TD(1)] == 1);
8583 alias TD = Typedef!(int[]);
8585 td[TD([1,2,3,4])] = 2;
8586 assert(td[TD([1,2,3,4])] == 2);
8590 alias TD = Typedef!(int[][]);
8592 td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3;
8593 assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3);
8597 struct MyStruct{ int x; }
8598 alias TD = Typedef!MyStruct;
8600 td[TD(MyStruct(10))] = 4;
8601 assert(TD(MyStruct(20)) !in td);
8602 assert(td[TD(MyStruct(10))] == 4);
8606 static struct MyStruct2
8609 size_t toHash() const nothrow @safe { return x; }
8610 bool opEquals(ref const MyStruct2 r) const { return r.x == x; }
8613 alias TD = Typedef!MyStruct2;
8615 td[TD(MyStruct2(50))] = 5;
8616 assert(td[TD(MyStruct2(50))] == 5);
8621 alias TD = Typedef!MyClass;
8623 auto c = new MyClass;
8625 assert(TD(new MyClass) !in td);
8626 assert(td[TD(c)] == 6);
8632 alias String = Typedef!(char[]);
8633 alias CString = Typedef!(const(char)[]);
8634 CString cs = "fubar";
8635 String s = cast(String) cs;
8637 char[] s2 = cast(char[]) cs;
8638 const(char)[] cs2 = cast(const(char)[])s;
8642 @system unittest // toString
8644 import std.meta : AliasSeq;
8645 import std.conv : to;
8650 static foreach (T; AliasSeq!(int, bool, float, double, real,
8653 int*, int[], int[2], int[int]))
8658 Typedef!(const T) ctd;
8659 Typedef!(immutable T) itd;
8661 assert(t.to!string() == td.to!string());
8663 static if (!(is(T == TestS) || is(T == TestC)))
8665 assert(t.to!string() == ctd.to!string());
8666 assert(t.to!string() == itd.to!string());
8671 @safe @nogc unittest // typedef'ed type with custom operators
8676 int opCmp(MyInt other)
8678 if (value < other.value)
8680 return !(value == other.value);
8684 auto m1 = Typedef!MyInt(MyInt(1));
8685 auto m2 = Typedef!MyInt(MyInt(2));
8690 Allocates a `class` object right inside the current scope,
8691 therefore avoiding the overhead of `new`. This facility is unsafe;
8692 it is the responsibility of the user to not escape a reference to the
8693 object outside the scope.
8695 The class destructor will be called when the result of `scoped()` is
8698 Scoped class instances can be embedded in a parent `class` or `struct`,
8699 just like a child struct instance. Scoped member variables must have
8700 type `typeof(scoped!Class(args))`, and be initialized with a call to
8701 scoped. See below for an example.
8704 It's illegal to move a class instance even if you are sure there
8705 are no pointers to it. As such, it is illegal to move a scoped object.
8710 // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for
8711 // small objects). We will just use the maximum of filed alignments.
8712 enum alignment = __traits(classInstanceAlignment, T);
8713 alias aligned = _alignUp!alignment;
8715 static struct Scoped
8717 // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory.
8718 private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void;
8720 @property inout(T) Scoped_payload() inout
8722 void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr);
8723 // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly.
8724 immutable size_t d = alignedStore - Scoped_store.ptr;
8725 size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof];
8728 import core.stdc.string : memmove;
8729 memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T));
8732 return cast(inout(T)) alignedStore;
8734 alias Scoped_payload this;
8737 @disable this(this);
8741 // `destroy` will also write .init but we have no functions in druntime
8742 // for deterministic finalization and memory releasing for now.
8743 .destroy(Scoped_payload);
8747 /** Returns the _scoped object.
8748 Params: args = Arguments to pass to `T`'s constructor.
8750 @system auto scoped(Args...)(auto ref Args args)
8752 import core.lifetime : emplace, forward;
8754 Scoped result = void;
8755 void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr);
8756 immutable size_t d = alignedStore - result.Scoped_store.ptr;
8757 *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d;
8758 emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], forward!args);
8774 // Standard usage, constructing A on the stack
8775 auto a1 = scoped!A();
8778 // Result of `scoped` call implicitly converts to a class reference
8780 assert(aRef.x == 42);
8782 // Scoped destruction
8784 auto a2 = scoped!A(1);
8787 // a2 is destroyed here, calling A's destructor
8789 // aRef is now an invalid reference
8791 // Here the temporary scoped A is immediately destroyed.
8792 // This means the reference is then invalid.
8795 // Wrong, should use `auto`
8796 A invalid = scoped!A();
8802 import std.algorithm.mutation : move;
8803 auto invalid = a1.move; // illegal, scoped objects can't be moved
8805 static assert(!is(typeof({
8806 auto e1 = a1; // illegal, scoped objects can't be copied
8807 assert([a1][0].x == 42); // ditto
8809 static assert(!is(typeof({
8810 alias ScopedObject = typeof(a1);
8811 auto e2 = ScopedObject(); // illegal, must be built via scoped!A
8812 auto e3 = ScopedObject(1); // ditto
8816 alias makeScopedA = scoped!A;
8817 auto a3 = makeScopedA();
8818 auto a4 = makeScopedA(1);
8820 // Use as member variable
8823 typeof(scoped!A()) a; // note the trailing parentheses
8835 assert(aRef.x == 5);
8836 destroy(b1); // calls A's destructor for b1.a
8837 // aRef is now an invalid reference
8841 assert(b2.a.x == 6);
8842 destroy(*b2); // calls A's destructor for b2.a
8845 private size_t _alignUp(size_t alignment)(size_t n)
8846 if (alignment > 0 && !((alignment - 1) & alignment))
8848 enum badEnd = alignment - 1; // 0b11, 0b111, ...
8849 return (n + badEnd) & ~badEnd;
8852 // https://issues.dlang.org/show_bug.cgi?id=6580 testcase
8855 enum alignment = (void*).alignof;
8858 static class C1 { byte b; }
8859 static class C2 { byte[2] b; }
8860 static class C3 { byte[3] b; }
8861 static class C7 { byte[7] b; }
8862 static assert(scoped!C0().sizeof % alignment == 0);
8863 static assert(scoped!C1().sizeof % alignment == 0);
8864 static assert(scoped!C2().sizeof % alignment == 0);
8865 static assert(scoped!C3().sizeof % alignment == 0);
8866 static assert(scoped!C7().sizeof % alignment == 0);
8868 enum longAlignment = long.alignof;
8871 long long_; byte byte_ = 4;
8873 this(long _long, ref int i) { long_ = _long; ++i; }
8875 static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; }
8876 static assert(scoped!C1long().sizeof % longAlignment == 0);
8877 static assert(scoped!C2long().sizeof % longAlignment == 0);
8879 void alignmentTest()
8882 auto c1long = scoped!C1long(3, var);
8884 auto c2long = scoped!C2long();
8885 assert(cast(uint)&c1long.long_ % longAlignment == 0);
8886 assert(cast(uint)&c2long.long_ % longAlignment == 0);
8887 assert(c1long.long_ == 3 && c1long.byte_ == 4);
8888 assert(c2long.byte_ == [5, 6] && c2long.long_ == 7);
8893 version (DigitalMars)
8895 void test(size_t size)
8897 import core.stdc.stdlib : alloca;
8898 cast(void) alloca(size);
8901 foreach (i; 0 .. 10)
8906 void test(size_t size)()
8911 static foreach (i; 0 .. 11)
8916 // Original https://issues.dlang.org/show_bug.cgi?id=6580 testcase
8919 class C { int i; byte b; }
8921 auto sa = [scoped!C(), scoped!C()];
8922 assert(cast(uint)&sa[0].i % int.alignof == 0);
8923 assert(cast(uint)&sa[1].i % int.alignof == 0); // fails
8928 class A { int x = 1; }
8929 auto a1 = scoped!A();
8931 auto a2 = scoped!A();
8939 class A { int x = 1; this() { x = 2; } }
8940 auto a1 = scoped!A();
8942 auto a2 = scoped!A();
8950 class A { int x = 1; this(int y) { x = y; } ~this() {} }
8951 auto a1 = scoped!A(5);
8953 auto a2 = scoped!A(42);
8961 class A { static bool dead; ~this() { dead = true; } }
8962 class B : A { static bool dead; ~this() { dead = true; } }
8964 auto b = scoped!B();
8966 assert(B.dead, "asdasd");
8967 assert(A.dead, "asdasd");
8970 // https://issues.dlang.org/show_bug.cgi?id=8039 testcase
8974 static struct S { ~this(){ ++dels; } }
8976 static class A { S s; }
8977 dels = 0; { scoped!A(); }
8980 static class B { S[2] s; }
8981 dels = 0; { scoped!B(); }
8984 static struct S2 { S[3] s; }
8985 static class C { S2[2] s; }
8986 dels = 0; { scoped!C(); }
8989 static class D: A { S2[2] s; }
8990 dels = 0; { scoped!D(); }
8991 assert(dels == 1+6);
8996 // https://issues.dlang.org/show_bug.cgi?id=4500
8999 this() { a = this; }
9000 this(int i) { a = this; }
9002 bool check() { return this is a; }
9005 auto a1 = scoped!A();
9008 auto a2 = scoped!A(1);
9021 this() { ++sdtor; assert(sdtor == 1); }
9022 ~this() { assert(sdtor == 1); --sdtor; }
9027 static class ABob : A, Bob
9029 this() { ++sdtor; assert(sdtor == 2); }
9030 ~this() { assert(sdtor == 2); --sdtor; }
9034 scope(exit) assert(A.sdtor == 0);
9035 auto abob = scoped!ABob();
9040 static class A { this(int) {} }
9041 static assert(!__traits(compiles, scoped!A()));
9046 static class A { @property inout(int) foo() inout { return 1; } }
9048 auto a1 = scoped!A();
9049 assert(a1.foo == 1);
9050 static assert(is(typeof(a1.foo) == int));
9052 auto a2 = scoped!(const(A))();
9053 assert(a2.foo == 1);
9054 static assert(is(typeof(a2.foo) == const(int)));
9056 auto a3 = scoped!(immutable(A))();
9057 assert(a3.foo == 1);
9058 static assert(is(typeof(a3.foo) == immutable(int)));
9060 const c1 = scoped!A();
9061 assert(c1.foo == 1);
9062 static assert(is(typeof(c1.foo) == const(int)));
9064 const c2 = scoped!(const(A))();
9065 assert(c2.foo == 1);
9066 static assert(is(typeof(c2.foo) == const(int)));
9068 const c3 = scoped!(immutable(A))();
9069 assert(c3.foo == 1);
9070 static assert(is(typeof(c3.foo) == immutable(int)));
9077 this(int rval) { assert(rval == 1); }
9078 this(ref int lval) { assert(lval == 3); ++lval; }
9081 auto c1 = scoped!C(1);
9083 auto c2 = scoped!C(lval);
9095 alias makeScopedC = scoped!C;
9097 auto a = makeScopedC();
9098 auto b = makeScopedC(1);
9099 auto c = makeScopedC(1, 1);
9101 static assert(is(typeof(a) == typeof(b)));
9102 static assert(is(typeof(b) == typeof(c)));
9106 Defines a simple, self-documenting yes/no flag. This makes it easy for
9107 APIs to define functions accepting flags without resorting to $(D
9108 bool), which is opaque in calls, and without needing to define an
9109 enumerated type separately. Using `Flag!"Name"` instead of $(D
9110 bool) makes the flag's meaning visible in calls. Each yes/no flag has
9111 its own type, which makes confusions and mix-ups impossible.
9115 Code calling `getLine` (usually far away from its definition) can't be
9116 understood without looking at the documentation, even by users familiar with
9119 string getLine(bool keepTerminator)
9122 if (keepTerminator) ...
9126 auto line = getLine(false);
9129 Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong
9130 code compiles and runs with erroneous results.
9132 After replacing the boolean parameter with an instantiation of `Flag`, code
9133 calling `getLine` can be easily read and understood even by people not
9134 fluent with the API:
9137 string getLine(Flag!"keepTerminator" keepTerminator)
9140 if (keepTerminator) ...
9144 auto line = getLine(Yes.keepTerminator);
9147 The structs `Yes` and `No` are provided as shorthand for
9148 `Flag!"Name".yes` and `Flag!"Name".no` and are preferred for brevity and
9149 readability. These convenience structs mean it is usually unnecessary and
9150 counterproductive to create an alias of a `Flag` as a way of avoiding typing
9151 out the full type while specifying the affirmative or negative options.
9153 Passing categorical data by means of unstructured `bool`
9154 parameters is classified under "simple-data coupling" by Steve
9155 McConnell in the $(LUCKY Code Complete) book, along with three other
9156 kinds of coupling. The author argues citing several studies that
9157 coupling has a negative effect on code quality. `Flag` offers a
9158 simple structuring method for passing yes/no flags to APIs.
9160 template Flag(string name) {
9165 When creating a value of type `Flag!"Name"`, use $(D
9166 Flag!"Name".no) for the negative option. When using a value
9167 of type `Flag!"Name"`, compare it against $(D
9168 Flag!"Name".no) or just `false` or `0`. */
9171 /** When creating a value of type `Flag!"Name"`, use $(D
9172 Flag!"Name".yes) for the affirmative option. When using a
9173 value of type `Flag!"Name"`, compare it against $(D
9185 assert(flag == Flag!"abc".no);
9186 assert(flag == No.abc);
9188 if (flag) assert(0);
9194 auto flag = Yes.abc;
9197 assert(flag == Yes.abc);
9198 if (!flag) assert(0);
9199 if (flag) {} else assert(0);
9203 Convenience names that allow using e.g. `Yes.encryption` instead of
9204 `Flag!"encryption".yes` and `No.encryption` instead of $(D
9205 Flag!"encryption".no).
9209 template opDispatch(string name)
9211 enum opDispatch = Flag!name.yes;
9214 //template yes(string name) { enum Flag!name yes = Flag!name.yes; }
9219 template opDispatch(string name)
9221 enum opDispatch = Flag!name.no;
9230 assert(flag == Flag!"abc".no);
9231 assert(flag == No.abc);
9233 if (flag) assert(0);
9239 auto flag = Yes.abc;
9242 assert(flag == Yes.abc);
9243 if (!flag) assert(0);
9244 if (flag) {} else assert(0);
9248 Detect whether an enum is of integral type and has only "flag" values
9249 (i.e. values with a bit count of exactly 1).
9250 Additionally, a zero value is allowed for compatibility with enums including
9253 template isBitFlagEnum(E)
9255 static if (is(E Base == enum) && isIntegral!Base)
9257 enum isBitFlagEnum = (E.min >= 0) &&
9259 static foreach (immutable flag; EnumMembers!E)
9263 if (value != 0) return false;
9270 enum isBitFlagEnum = false;
9275 @safe pure nothrow unittest
9286 static assert(isBitFlagEnum!A);
9289 /// Test an enum with default (consecutive) values
9290 @safe pure nothrow unittest
9300 static assert(!isBitFlagEnum!B);
9303 /// Test an enum with non-integral values
9304 @safe pure nothrow unittest
9312 static assert(!isBitFlagEnum!C);
9316 A typesafe structure for storing combinations of enum values.
9318 This template defines a simple struct to represent bitwise OR combinations of
9319 enum values. It can be used if all the enum values are integral constants with
9320 a bit count of at most 1, or if the `unsafe` parameter is explicitly set to
9322 This is much safer than using the enum itself to store
9323 the OR combination, which can produce surprising effects like this:
9331 // will throw SwitchError
9341 struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe)
9342 if (unsafe || isBitFlagEnum!(E))
9344 @safe @nogc pure nothrow:
9346 enum isBaseEnumType(T) = is(E == T);
9347 alias Base = OriginalType!E;
9357 if (allSatisfy!(isBaseEnumType, T))
9362 bool opCast(B: bool)() const
9367 Base opCast(B)() const
9373 auto opUnary(string op)() const
9376 return BitFlags(cast(E) cast(Base) ~mValue);
9379 auto ref opAssign(T...)(T flags)
9380 if (allSatisfy!(isBaseEnumType, T))
9383 foreach (E flag; flags)
9390 auto ref opAssign(E flag)
9396 auto ref opOpAssign(string op: "|")(BitFlags flags)
9398 mValue |= flags.mValue;
9402 auto ref opOpAssign(string op: "&")(BitFlags flags)
9404 mValue &= flags.mValue;
9408 auto ref opOpAssign(string op: "|")(E flag)
9414 auto ref opOpAssign(string op: "&")(E flag)
9420 auto opBinary(string op)(BitFlags flags) const
9421 if (op == "|" || op == "&")
9423 BitFlags result = this;
9424 result.opOpAssign!op(flags);
9428 auto opBinary(string op)(E flag) const
9429 if (op == "|" || op == "&")
9431 BitFlags result = this;
9432 result.opOpAssign!op(flag);
9436 auto opBinaryRight(string op)(E flag) const
9437 if (op == "|" || op == "&")
9439 return opBinary!op(flag);
9442 bool opDispatch(string name)() const
9443 if (__traits(hasMember, E, name))
9445 enum e = __traits(getMember, E, name);
9446 return (mValue & e) == e;
9449 void opDispatch(string name)(bool set)
9450 if (__traits(hasMember, E, name))
9452 enum e = __traits(getMember, E, name);
9460 /// Set values with the | operator and test with &
9461 @safe @nogc pure nothrow unittest
9468 // A default constructed BitFlags has no value set
9469 immutable BitFlags!Enum flags_empty;
9470 assert(!flags_empty.A);
9472 // Value can be set with the | operator
9473 immutable flags_A = flags_empty | Enum.A;
9475 // and tested using property access
9478 // or the & operator
9479 assert(flags_A & Enum.A);
9481 assert(Enum.A & flags_A);
9484 /// A default constructed BitFlags has no value set
9485 @safe @nogc pure nothrow unittest
9495 immutable BitFlags!Enum flags_empty;
9496 assert(!(flags_empty & (Enum.A | Enum.B | Enum.C)));
9497 assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C));
9500 // BitFlags can be variadically initialized
9501 @safe @nogc pure nothrow unittest
9503 import std.traits : EnumMembers;
9512 // Values can also be set using property access
9513 BitFlags!Enum flags;
9515 assert(flags & Enum.A);
9517 assert(!(flags & Enum.A));
9519 // BitFlags can be variadically initialized
9520 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
9521 assert(flags_AB.A && flags_AB.B && !flags_AB.C);
9523 // You can use the EnumMembers template to set all flags
9524 immutable BitFlags!Enum flags_all = EnumMembers!Enum;
9525 assert(flags_all.A && flags_all.B && flags_all.C);
9528 /// Binary operations: subtracting and intersecting flags
9529 @safe @nogc pure nothrow unittest
9537 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
9538 immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C);
9540 // Use the ~ operator for subtracting flags
9541 immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A);
9542 assert(!flags_B.A && flags_B.B && !flags_B.C);
9544 // use & between BitFlags for intersection
9545 assert(flags_B == (flags_BC & flags_AB));
9548 /// All the binary operators work in their assignment version
9549 @safe @nogc pure nothrow unittest
9557 BitFlags!Enum flags_empty, temp, flags_AB;
9558 flags_AB = Enum.A | Enum.B;
9561 assert(temp == (flags_empty | flags_AB));
9565 assert(temp == (flags_empty | Enum.B));
9569 assert(temp == (flags_empty & flags_AB));
9573 assert(temp == (flags_empty & Enum.A));
9576 /// Conversion to bool and int
9577 @safe @nogc pure nothrow unittest
9585 BitFlags!Enum flags;
9587 // BitFlags with no value set evaluate to false
9590 // BitFlags with at least one value set evaluate to true
9594 // This can be useful to check intersection between BitFlags
9595 BitFlags!Enum flags_AB = Enum.A | Enum.B;
9596 assert(flags & flags_AB);
9597 assert(flags & Enum.A);
9599 // You can of course get you raw value out of flags
9600 auto value = cast(int) flags;
9601 assert(value == Enum.A);
9604 /// You need to specify the `unsafe` parameter for enums with custom values
9605 @safe @nogc pure nothrow unittest
9614 static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; }));
9615 BitFlags!(UnsafeEnum, Yes.unsafe) flags;
9617 // property access tests for exact match of unsafe enums
9619 assert(!flags.BC); // only B
9621 assert(flags.BC); // both B and C
9623 assert(!flags.BC); // only C
9625 // property access sets all bits of unsafe enum group
9628 assert(!flags.A && flags.B && flags.C);
9631 assert(flags.A && !flags.B && !flags.C);
9634 // Negation of BitFlags should work with any base type.
9635 // Double-negation of BitFlags should work.
9636 @safe @nogc pure nothrow unittest
9638 static foreach (alias Base; AliasSeq!(
9656 auto flags = BitFlags!Enum(Enum.A);
9658 assert(flags == ~~flags);
9662 private enum false_(T) = false;
9666 Replaces all occurrences of `From` into `To`, in one or more types `T`. For
9667 example, `ReplaceType!(int, uint, Tuple!(int, float)[string])` yields
9668 `Tuple!(uint, float)[string]`. The types in which replacement is performed
9669 may be arbitrarily complex, including qualifiers, built-in type constructors
9670 (pointers, arrays, associative arrays, functions, and delegates), and template
9671 instantiations; replacement proceeds transitively through the type definition.
9672 However, member types in `struct`s or `class`es are not replaced because there
9673 are no ways to express the types resulting after replacement.
9675 This is an advanced type manipulation necessary e.g. for replacing the
9676 placeholder type `This` in $(REF Algebraic, std,variant).
9678 Returns: `ReplaceType` aliases itself to the type(s) that result after
9681 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T);
9687 is(ReplaceType!(int, string, int[]) == string[]) &&
9688 is(ReplaceType!(int, string, int[int]) == string[string]) &&
9689 is(ReplaceType!(int, string, const(int)[]) == const(string)[]) &&
9690 is(ReplaceType!(int, string, Tuple!(int[], float))
9691 == Tuple!(string[], float))
9696 Like $(LREF ReplaceType), but does not perform replacement in types for which
9697 `pred` evaluates to `true`.
9699 template ReplaceTypeUnless(alias pred, From, To, T...)
9703 static if (T.length == 1)
9705 static if (pred!(T[0]))
9706 alias ReplaceTypeUnless = T[0];
9707 else static if (is(T[0] == From))
9708 alias ReplaceTypeUnless = To;
9709 else static if (is(T[0] == const(U), U))
9710 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U));
9711 else static if (is(T[0] == immutable(U), U))
9712 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U));
9713 else static if (is(T[0] == shared(U), U))
9714 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U));
9715 else static if (is(T[0] == U*, U))
9717 static if (is(U == function))
9718 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]);
9720 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*;
9722 else static if (is(T[0] == delegate))
9724 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]);
9726 else static if (is(T[0] == function))
9728 static assert(0, "Function types not supported," ~
9729 " use a function pointer type instead of " ~ T[0].stringof);
9731 else static if (is(T[0] == U!V, alias U, V...))
9733 template replaceTemplateArgs(T...)
9735 static if (is(typeof(T[0]))) { // template argument is value or symbol
9736 static if (__traits(compiles, { alias _ = T[0]; }))
9738 alias replaceTemplateArgs = T[0];
9741 enum replaceTemplateArgs = T[0];
9743 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]);
9745 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V));
9747 else static if (is(T[0] == struct))
9748 // don't match with alias this struct below
9749 // https://issues.dlang.org/show_bug.cgi?id=15168
9750 alias ReplaceTypeUnless = T[0];
9751 else static if (is(T[0] == U[], U))
9752 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[];
9753 else static if (is(T[0] == U[n], U, size_t n))
9754 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n];
9755 else static if (is(T[0] == U[V], U, V))
9756 alias ReplaceTypeUnless =
9757 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)];
9759 alias ReplaceTypeUnless = T[0];
9761 else static if (T.length > 1)
9763 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]),
9764 ReplaceTypeUnless!(pred, From, To, T[1 .. $]));
9768 alias ReplaceTypeUnless = AliasSeq!();
9775 import std.traits : isArray;
9778 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) &&
9779 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) &&
9780 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[]))
9781 == Tuple!(string, int[]))
9785 private template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun)
9787 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun);
9788 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun));
9789 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return
9790 // tuple if Parameters!fun.length == 1
9794 enum linkage = functionLinkage!fun;
9795 alias attributes = functionAttributes!fun;
9796 enum variadicStyle = variadicFunctionStyle!fun;
9797 alias storageClasses = ParameterStorageClassTuple!fun;
9801 result ~= "extern(" ~ linkage ~ ") ";
9802 static if (attributes & FunctionAttribute.ref_)
9808 static if (is(fun == delegate))
9809 result ~= " delegate";
9811 result ~= " function";
9814 static foreach (i; 0 .. PX.length)
9818 if (storageClasses[i] & ParameterStorageClass.scope_)
9820 if (storageClasses[i] & ParameterStorageClass.in_)
9822 if (storageClasses[i] & ParameterStorageClass.out_)
9824 if (storageClasses[i] & ParameterStorageClass.ref_)
9826 if (storageClasses[i] & ParameterStorageClass.lazy_)
9828 if (storageClasses[i] & ParameterStorageClass.return_)
9829 result ~= "return ";
9831 result ~= "PX[" ~ i.stringof ~ "]";
9833 static if (variadicStyle == Variadic.typesafe)
9835 else static if (variadicStyle != Variadic.no)
9839 static if (attributes & FunctionAttribute.pure_)
9841 static if (attributes & FunctionAttribute.nothrow_)
9842 result ~= " nothrow";
9843 static if (attributes & FunctionAttribute.property)
9844 result ~= " @property";
9845 static if (attributes & FunctionAttribute.trusted)
9846 result ~= " @trusted";
9847 static if (attributes & FunctionAttribute.safe)
9849 static if (attributes & FunctionAttribute.nogc)
9851 static if (attributes & FunctionAttribute.system)
9852 result ~= " @system";
9853 static if (attributes & FunctionAttribute.const_)
9855 static if (attributes & FunctionAttribute.immutable_)
9856 result ~= " immutable";
9857 static if (attributes & FunctionAttribute.inout_)
9859 static if (attributes & FunctionAttribute.shared_)
9860 result ~= " shared";
9861 static if (attributes & FunctionAttribute.return_)
9862 result ~= " return";
9863 static if (attributes & FunctionAttribute.live)
9869 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";");
9874 template Test(Ts...)
9876 static if (Ts.length)
9878 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", "
9879 // ~Ts[1].stringof~", "~Ts[2].stringof~")");
9880 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]),
9881 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", "
9882 ~Ts[2].stringof~") == "
9883 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof);
9884 alias Test = Test!(Ts[4 .. $]);
9886 else alias Test = void;
9889 //import core.stdc.stdio;
9890 alias RefFun1 = ref int function(float, long);
9891 alias RefFun2 = ref float function(float, long);
9892 extern(C) int printf(const char*, ...) nothrow @nogc @system;
9893 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system;
9897 struct S1 { void foo() { x = 1; } }
9898 struct S2 { void bar() { x = 2; } }
9901 int, float, typeof(&func), float delegate(float),
9902 int, float, typeof(&printf), typeof(&floatPrintf),
9903 int, float, int function(out long, ...),
9904 float function(out long, ...),
9905 int, float, int function(ref float, long),
9906 float function(ref float, long),
9907 int, float, int function(ref int, long),
9908 float function(ref float, long),
9909 int, float, int function(out int, long),
9910 float function(out float, long),
9911 int, float, int function(lazy int, long),
9912 float function(lazy float, long),
9913 int, float, int function(out long, ref const int),
9914 float function(out long, ref const float),
9915 int, float, int function(in long, ref const int),
9916 float function(in long, ref const float),
9917 int, float, int function(long, in int),
9918 float function(long, in float),
9920 int, float, int, float,
9921 int, float, const int, const float,
9922 int, float, immutable int, immutable float,
9923 int, float, shared int, shared float,
9924 int, float, int*, float*,
9925 int, float, const(int)*, const(float)*,
9926 int, float, const(int*), const(float*),
9927 const(int)*, float, const(int*), const(float),
9928 int*, float, const(int)*, const(int)*,
9929 int, float, int[], float[],
9930 int, float, int[42], float[42],
9931 int, float, const(int)[42], const(float)[42],
9932 int, float, const(int[42]), const(float[42]),
9933 int, float, int[int], float[float],
9934 int, float, int[double], float[double],
9935 int, float, double[int], double[float],
9936 int, float, int function(float, long), float function(float, long),
9937 int, float, int function(float), float function(float),
9938 int, float, int function(float, int), float function(float, float),
9939 int, float, int delegate(float, long), float delegate(float, long),
9940 int, float, int delegate(float), float delegate(float),
9941 int, float, int delegate(float, int), float delegate(float, float),
9942 int, float, Unique!int, Unique!float,
9943 int, float, Tuple!(float, int), Tuple!(float, float),
9944 int, float, RefFun1, RefFun2,
9946 S1[1][][S1]* function(),
9947 S2[1][][S2]* function(),
9949 int[3] function( int[] arr, int[2] ...) pure @trusted,
9950 string[3] function(string[] arr, string[2] ...) pure @trusted,
9953 // https://issues.dlang.org/show_bug.cgi?id=15168
9954 static struct T1 { string s; alias s this; }
9955 static struct T2 { char[10] s; alias s this; }
9956 static struct T3 { string[string] s; alias s this; }
9957 alias Pass2 = Test!(
9958 ubyte, ubyte, T1, T1,
9959 ubyte, ubyte, T2, T2,
9960 ubyte, ubyte, T3, T3,
9964 // https://issues.dlang.org/show_bug.cgi?id=17116
9967 alias ConstDg = void delegate(float) const;
9968 alias B = void delegate(int) const;
9969 alias A = ReplaceType!(float, int, ConstDg);
9970 static assert(is(B == A));
9973 // https://issues.dlang.org/show_bug.cgi?id=19696
9976 static struct T(U) {}
9977 static struct S { T!int t; alias t this; }
9978 static assert(is(ReplaceType!(float, float, S) == S));
9981 // https://issues.dlang.org/show_bug.cgi?id=19697
9986 static assert(is(ReplaceType!(float, float, C)));
9989 // https://issues.dlang.org/show_bug.cgi?id=16132
9994 static assert(is(ReplaceType!(int, string, C) == C));
9997 // https://issues.dlang.org/show_bug.cgi?id=22325
10000 static struct Foo(alias f) {}
10001 static void bar() {}
10002 alias _ = ReplaceType!(int, int, Foo!bar);
10006 Ternary type with three truth values:
10009 $(LI `Ternary.yes` for `true`)
10010 $(LI `Ternary.no` for `false`)
10011 $(LI `Ternary.unknown` as an unknown state)
10014 Also known as trinary, trivalent, or trilean.
10017 $(HTTP en.wikipedia.org/wiki/Three-valued_logic,
10018 Three Valued Logic on Wikipedia)
10022 @safe @nogc nothrow pure:
10024 private ubyte value = 6;
10025 private static Ternary make(ubyte b)
10033 The possible states of the `Ternary`
10037 enum yes = make(2);
10039 enum unknown = make(6);
10042 Construct and assign from a `bool`, receiving `no` for `false` and `yes`
10045 this(bool b) { value = b << 1; }
10048 void opAssign(bool b) { value = b << 1; }
10051 Construct a ternary value from another ternary value
10053 this(const Ternary b) { value = b.value; }
10056 $(TABLE Truth table for logical operations,
10057 $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`))
10058 $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`))
10059 $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`))
10060 $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
10061 $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`))
10062 $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`))
10063 $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
10064 $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
10065 $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
10066 $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`))
10069 Ternary opUnary(string s)() if (s == "~")
10071 return make((386 >> value) & 6);
10075 Ternary opBinary(string s)(Ternary rhs) if (s == "|")
10077 return make((25_512 >> (value + rhs.value)) & 6);
10081 Ternary opBinary(string s)(Ternary rhs) if (s == "&")
10083 return make((26_144 >> (value + rhs.value)) & 6);
10087 Ternary opBinary(string s)(Ternary rhs) if (s == "^")
10089 return make((26_504 >> (value + rhs.value)) & 6);
10093 Ternary opBinary(string s)(bool rhs)
10094 if (s == "|" || s == "&" || s == "^")
10096 return this.opBinary!s(Ternary(rhs));
10101 @safe @nogc nothrow pure
10105 assert(a == Ternary.unknown);
10107 assert(~Ternary.yes == Ternary.no);
10108 assert(~Ternary.no == Ternary.yes);
10109 assert(~Ternary.unknown == Ternary.unknown);
10112 @safe @nogc nothrow pure
10115 alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown;
10116 Ternary[27] truthTableAnd =
10129 Ternary[27] truthTableOr =
10142 Ternary[27] truthTableXor =
10155 for (auto i = 0; i != truthTableAnd.length; i += 3)
10157 assert((truthTableAnd[i] & truthTableAnd[i + 1])
10158 == truthTableAnd[i + 2]);
10159 assert((truthTableOr[i] | truthTableOr[i + 1])
10160 == truthTableOr[i + 2]);
10161 assert((truthTableXor[i] ^ truthTableXor[i + 1])
10162 == truthTableXor[i + 2]);
10166 assert(a == Ternary.unknown);
10167 static assert(!is(typeof({ if (a) {} })));
10168 assert(!is(typeof({ auto b = Ternary(3); })));
10170 assert(a == Ternary.yes);
10172 assert(a == Ternary.no);
10173 a = Ternary.unknown;
10174 assert(a == Ternary.unknown);
10178 assert(~Ternary.yes == Ternary.no);
10179 assert(~Ternary.no == Ternary.yes);
10180 assert(~Ternary.unknown == Ternary.unknown);
10183 @safe @nogc nothrow pure
10186 Ternary a = Ternary(true);
10187 assert(a == Ternary.yes);
10188 assert((a & false) == Ternary.no);
10189 assert((a | false) == Ternary.yes);
10190 assert((a ^ true) == Ternary.no);
10191 assert((a ^ false) == Ternary.yes);
10194 // https://issues.dlang.org/show_bug.cgi?id=22511
10200 @disable this(this);
10201 this(ref return scope inout S rhs) inout
10203 this.b = rhs.b + 1;
10207 Nullable!S s1 = S(1);
10208 assert(s1.get().b == 2);
10209 Nullable!S s2 = s1;
10210 assert(s2.get().b == 3);
10218 this(this) { ++b; }
10221 Nullable!S s1 = S(1);
10222 assert(s1.get().b == 2);
10223 Nullable!S s2 = s1;
10224 assert(s2.get().b == 3);
10227 /// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed.
10228 /// Old code may be relying on `@safe`ty of some of the member functions which
10229 /// cannot be safe in the new scheme, and
10230 /// can avoid breakage by continuing to use this. `SafeRefCounted` should be
10231 /// preferred, as this type is outdated and unrecommended for new code.
10232 struct RefCounted(T, RefCountedAutoInitialize autoInit =
10233 RefCountedAutoInitialize.yes)
10235 version (D_BetterC)
10237 private enum enableGCScan = false;
10241 private enum enableGCScan = hasIndirections!T;
10244 extern(C) private pure nothrow @nogc static
10246 pragma(mangle, "free") void pureFree( void *ptr );
10247 static if (enableGCScan)
10248 import core.memory : GC;
10251 struct RefCountedStore
10253 private struct Impl
10259 private Impl* _store;
10261 private void initialize(A...)(auto ref A args)
10263 import core.lifetime : emplace, forward;
10266 version (D_Exceptions) scope(failure) deallocateStore();
10267 emplace(&_store._payload, forward!args);
10271 private void move(ref T source) nothrow pure
10273 import std.algorithm.mutation : moveEmplace;
10276 moveEmplace(source, _store._payload);
10280 // 'nothrow': can only generate an Error
10281 private void allocateStore() nothrow pure
10283 static if (enableGCScan)
10285 import std.internal.memory : enforceCalloc;
10286 _store = cast(Impl*) enforceCalloc(1, Impl.sizeof);
10287 GC.addRange(&_store._payload, T.sizeof);
10291 import std.internal.memory : enforceMalloc;
10292 _store = cast(Impl*) enforceMalloc(Impl.sizeof);
10296 private void deallocateStore() nothrow pure
10298 static if (enableGCScan)
10300 GC.removeRange(&this._store._payload);
10306 @property nothrow @safe pure @nogc
10307 bool isInitialized() const
10309 return _store !is null;
10312 @property nothrow @safe pure @nogc
10313 size_t refCount() const
10315 return isInitialized ? _store._count : 0;
10318 void ensureInitialized()()
10320 // By checking for `@disable this()` and failing early we can
10321 // produce a clearer error message.
10322 static assert(__traits(compiles, { static T t; }),
10323 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~
10324 "` because `" ~ fullyQualifiedName!T ~
10325 ".this()` is annotated with `@disable`.");
10326 if (!isInitialized) initialize();
10330 RefCountedStore _refCounted;
10332 @property nothrow @safe
10333 ref inout(RefCountedStore) refCountedStore() inout
10335 return _refCounted;
10338 this(A...)(auto ref A args) if (A.length > 0)
10341 assert(refCountedStore.isInitialized);
10345 import core.lifetime : forward;
10346 _refCounted.initialize(forward!args);
10351 _refCounted.move(val);
10354 this(this) @safe pure nothrow @nogc
10356 if (!_refCounted.isInitialized) return;
10357 ++_refCounted._store._count;
10362 if (!_refCounted.isInitialized) return;
10363 assert(_refCounted._store._count > 0);
10364 if (--_refCounted._store._count)
10366 // Done, destroy and deallocate
10367 .destroy(_refCounted._store._payload);
10368 _refCounted.deallocateStore();
10371 void opAssign(typeof(this) rhs)
10373 import std.algorithm.mutation : swap;
10375 swap(_refCounted._store, rhs._refCounted._store);
10378 void opAssign(T rhs)
10380 import std.algorithm.mutation : move;
10382 static if (autoInit == RefCountedAutoInitialize.yes)
10384 _refCounted.ensureInitialized();
10388 assert(_refCounted.isInitialized);
10390 move(rhs, _refCounted._store._payload);
10393 static if (autoInit == RefCountedAutoInitialize.yes)
10395 //Can't use inout here because of potential mutation
10397 ref T refCountedPayload() return
10399 _refCounted.ensureInitialized();
10400 return _refCounted._store._payload;
10404 @property nothrow @safe pure @nogc
10405 ref inout(T) refCountedPayload() inout return
10407 assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload.");
10408 return _refCounted._store._payload;
10411 alias refCountedPayload this;
10413 static if (is(T == struct) && !is(typeof((ref T t) => t.toString())))
10415 string toString(this This)()
10417 import std.conv : to;
10419 static if (autoInit)
10420 return to!string(refCountedPayload);
10423 if (!_refCounted.isInitialized)
10424 return This.stringof ~ "(RefCountedStore(null))";
10426 return to!string(_refCounted._store._payload);
10433 @betterC pure @system nothrow @nogc unittest
10435 auto rc1 = RefCounted!int(5);
10442 // More unit tests below SafeRefCounted
10445 * Like $(LREF safeRefCounted) but used to initialize $(LREF RefCounted)
10446 * instead. Intended for backwards compatibility, otherwise it is preferable
10447 * to use `safeRefCounted`.
10449 RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val)
10451 typeof(return) res;
10452 res._refCounted.move(val);
10461 static size_t nDestroyed;
10463 @disable this(this); // not copyable
10464 ~this() { name = null; ++nDestroyed; }
10467 auto file = File("name");
10468 assert(file.name == "name");
10469 static assert(!__traits(compiles, {auto file2 = file;}));
10470 assert(File.nDestroyed == 0);
10473 import std.algorithm.mutation : move;
10474 auto rcFile = refCounted(move(file));
10475 assert(rcFile.name == "name");
10476 assert(File.nDestroyed == 1);
10477 assert(file.name == null);
10479 auto rcFile2 = rcFile;
10480 assert(rcFile.refCountedStore.refCount == 2);
10481 assert(File.nDestroyed == 1);
10484 assert(File.nDestroyed == 2);
10487 // More unit tests below safeRefCounted