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
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;
83 alias Coord = Tuple!(int, "x", int, "y", int, "z");
85 c[1] = 1; // access by index
86 c.z = 1; // access by given name
87 assert(c == Coord(0, 1, 1));
89 // names can be omitted
90 alias DicEntry = Tuple!(string, string);
92 // tuples can also be constructed on instantiation
93 assert(tuple(2, 3, 4)[1] == 3);
94 // construction on instantiation works with names too
95 assert(tuple!("x", "y", "z")(2, 3, 4).y == 3);
97 // Rebindable references to const and immutable objects
99 class Widget { void foo() const @safe {} }
100 const w1 = new Widget, w2 = new Widget;
102 // w1 = w2 would not work; can't rebind const object
103 auto r = Rebindable!(const Widget)(w1);
104 // invoke method as if r were a Widget object
106 // rebind r to refer to another object
112 Encapsulates unique ownership of a resource.
114 When a `Unique!T` goes out of scope it will call `destroy`
115 on the resource `T` that it manages, unless it is transferred.
116 One important consequence of `destroy` is that it will call the
117 destructor of the resource `T`. GC-managed references are not
118 guaranteed to be valid during a destructor call, but other members of
119 `T`, such as file handles or pointers to `malloc` memory, will
120 still be valid during the destructor call. This allows the resource
121 `T` to deallocate or clean up any non-GC resources.
123 If it is desirable to persist a `Unique!T` outside of its original
124 scope, then it can be transferred. The transfer can be explicit, by
125 calling `release`, or implicit, when returning Unique from a
126 function. The resource `T` can be a polymorphic class object or
127 instance of an interface, in which case Unique behaves polymorphically
130 If `T` is a value type, then `Unique!T` will be implemented
131 as a reference to a `T`.
135 /** Represents a reference to `T`. Resolves to `T*` if `T` is a value type. */
136 static if (is(T == class) || is(T == interface))
142 // Deferred in case we get some language support for checking uniqueness.
145 Allows safe construction of `Unique`. It creates the resource and
146 guarantees unique ownership of it (unless `T` publishes aliases of
148 Note: Nested structs/classes cannot be created.
150 args = Arguments to pass to `T`'s constructor.
153 auto u = Unique!(C).create();
156 static Unique!T create(A...)(auto ref A args)
157 if (__traits(compiles, new T(args)))
165 Constructor that takes an rvalue.
166 It will ensure uniqueness, as long as the rvalue
167 isn't just a view on an lvalue (e.g., a cast).
170 Unique!Foo f = new Foo;
178 Constructor that takes an lvalue. It nulls its source.
179 The nulling will ensure uniqueness as long as there
180 are no previous aliases to the source.
189 Constructor that takes a `Unique` of a type that is convertible to our type.
191 Typically used to transfer a `Unique` rvalue of derived type to
192 a `Unique` of base type.
198 Unique!Object uo = uc.release;
208 /// Transfer ownership from a `Unique` of a type that is convertible to our type.
209 void opAssign(U)(Unique!U u)
212 // first delete any resource we own
227 /** Returns whether the resource exists. */
228 @property bool isEmpty() const
232 /** Transfer ownership to a `Unique` rvalue. Nullifies the current contents.
233 Same as calling std.algorithm.move on it.
237 import std.algorithm.mutation : move;
241 /** Forwards member access to contents. */
245 Postblit operator is undefined to prevent the cloning of `Unique` objects.
259 this(int i){this.i = i;}
263 // Construct a unique instance of S on the heap
264 Unique!S ut = new S(5);
265 // Implicit transfer of ownership
268 // Borrow a unique resource by ref
269 void increment(ref Unique!S ur)
273 void consume(Unique!S u2)
276 // Resource automatically deleted here
283 //consume(u1); // Error: u1 is not copyable
284 // Transfer ownership of the resource
291 // test conversion to base ref
297 // constructor conversion
298 Unique!Object u = Unique!C(new C);
299 static assert(!__traits(compiles, {u = new C;}));
302 assert(deleted == 1);
305 static assert(!__traits(compiles, {Unique!Object uo = uc;}));
306 Unique!Object uo = new C;
307 // opAssign conversion, deleting uo resource first
311 assert(deleted == 2);
318 ~this() { debug(Unique) writeln(" Bar destructor"); }
319 int val() const { return 4; }
321 alias UBar = Unique!(Bar);
324 debug(Unique) writeln("inside g");
327 auto ub = UBar(new Bar);
330 static assert(!__traits(compiles, {auto ub3 = g(ub);}));
331 auto ub2 = g(ub.release);
333 assert(!ub2.isEmpty);
353 int val() const { return 4; }
355 alias UBar = Unique!Bar;
358 debug(Unique) writeln("inside g");
363 assert(u.val() == 4);
364 // Resource automatically deleted here
366 auto ub = UBar(new BarImpl);
367 assert(BarImpl.count == 1);
370 static assert(!__traits(compiles, {auto ub3 = g(ub);}));
371 auto ub2 = g(ub.release);
373 assert(!ub2.isEmpty);
374 consume(ub2.release);
375 assert(BarImpl.count == 0);
383 int val() const { return 3; }
386 alias UFoo = Unique!(Foo);
393 auto uf = UFoo(new Foo);
396 static assert(!__traits(compiles, {auto uf3 = f(uf);}));
397 auto uf2 = f(uf.release);
399 assert(!uf2.isEmpty);
402 // ensure Unique behaves correctly through const access paths
405 struct Bar {int val;}
408 Unique!Bar bar = new Bar;
413 const Foo* ptr = &foo;
414 static assert(is(typeof(ptr) == const(Foo*)));
415 static assert(is(typeof(ptr.bar) == const(Unique!Bar)));
416 static assert(is(typeof(ptr.bar.val) == const(int)));
417 assert(ptr.bar.val == 6);
419 assert(ptr.bar.val == 7);
422 // Used in Tuple.toString
423 private template sharedToString(alias field)
424 if (is(typeof(field) == shared))
426 static immutable sharedToString = typeof(field).stringof;
429 private template sharedToString(alias field)
430 if (!is(typeof(field) == shared))
432 alias sharedToString = field;
435 private enum bool distinctFieldNames(names...) = __traits(compiles,
437 static foreach (__name; names)
438 static if (is(typeof(__name) : string))
439 mixin("enum int " ~ __name ~ " = 0;");
444 static assert(!distinctFieldNames!(string, "abc", string, "abc"));
445 static assert(distinctFieldNames!(string, "abc", int, "abd"));
446 static assert(!distinctFieldNames!(int, "abc", string, "abd", int, "abc"));
447 // https://issues.dlang.org/show_bug.cgi?id=19240
448 static assert(!distinctFieldNames!(int, "int"));
452 // Parse (type,name) pairs (FieldSpecs) out of the specified
453 // arguments. Some fields would have name, others not.
454 private template parseSpecs(Specs...)
456 static if (Specs.length == 0)
458 alias parseSpecs = AliasSeq!();
460 else static if (is(Specs[0]))
462 static if (is(typeof(Specs[1]) : string))
465 AliasSeq!(FieldSpec!(Specs[0 .. 2]),
466 parseSpecs!(Specs[2 .. $]));
471 AliasSeq!(FieldSpec!(Specs[0]),
472 parseSpecs!(Specs[1 .. $]));
477 static assert(0, "Attempted to instantiate Tuple with an "
478 ~"invalid argument: "~ Specs[0].stringof);
482 private template FieldSpec(T, string s = "")
488 // Used with staticMap.
489 private alias extractType(alias spec) = spec.Type;
490 private alias extractName(alias spec) = spec.name;
491 private template expandSpec(alias spec)
493 static if (spec.name.length == 0)
494 alias expandSpec = AliasSeq!(spec.Type);
496 alias expandSpec = AliasSeq!(spec.Type, spec.name);
500 private enum areCompatibleTuples(Tup1, Tup2, string op) =
501 isTuple!(OriginalType!Tup2) && Tup1.Types.length == Tup2.Types.length && is(typeof(
502 (ref Tup1 tup1, ref Tup2 tup2)
504 static foreach (i; 0 .. Tup1.Types.length)
506 auto lhs = typeof(tup1.field[i]).init;
507 auto rhs = typeof(tup2.field[i]).init;
508 static if (op == "=")
511 auto result = mixin("lhs "~op~" rhs");
515 private enum areBuildCompatibleTuples(Tup1, Tup2) =
516 isTuple!Tup2 && Tup1.Types.length == Tup2.Types.length && is(typeof(
518 static foreach (i; 0 .. Tup1.Types.length)
519 static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i]));
522 // Returns `true` iff a `T` can be initialized from a `U`.
523 private enum isBuildable(T, U) = is(typeof(
528 // Helper for partial instantiation
529 private template isBuildableFrom(U)
531 enum isBuildableFrom(T) = isBuildable!(T, U);
536 _Tuple of values, for example $(D Tuple!(int, string)) is a record that
537 stores an `int` and a `string`. `Tuple` can be used to bundle
538 values together, notably when returning multiple values from a
539 function. If `obj` is a `Tuple`, the individual members are
540 accessible with the syntax `obj[0]` for the first field, `obj[1]`
541 for the second, and so on.
543 See_Also: $(LREF tuple).
546 Specs = A list of types (and optionally, member names) that the `Tuple` contains.
548 template Tuple(Specs...)
549 if (distinctFieldNames!(Specs))
551 import std.meta : staticMap;
553 alias fieldSpecs = parseSpecs!Specs;
555 // Generates named fields as follows:
556 // alias name_0 = Identity!(field[0]);
557 // alias name_1 = Identity!(field[1]);
559 // NOTE: field[k] is an expression (which yields a symbol of a
560 // variable) and can't be aliased directly.
561 enum injectNamedFields = ()
564 static foreach (i, val; fieldSpecs)
566 immutable si = i.stringof;
567 decl ~= "alias _" ~ si ~ " = Identity!(field[" ~ si ~ "]);";
568 if (val.name.length != 0)
570 decl ~= "alias " ~ val.name ~ " = _" ~ si ~ ";";
576 // Returns Specs for a subtuple this[from .. to] preserving field
578 alias sliceSpecs(size_t from, size_t to) =
579 staticMap!(expandSpec, fieldSpecs[from .. to]);
584 * The types of the `Tuple`'s components.
586 alias Types = staticMap!(extractType, fieldSpecs);
588 private alias _Fields = Specs;
591 static if (Specs.length == 0) @safe unittest
593 import std.meta : AliasSeq;
594 alias Fields = Tuple!(int, "id", string, float);
595 static assert(is(Fields.Types == AliasSeq!(int, string, float)));
599 * The names of the `Tuple`'s components. Unnamed fields have empty names.
601 alias fieldNames = staticMap!(extractName, fieldSpecs);
604 static if (Specs.length == 0) @safe unittest
606 import std.meta : AliasSeq;
607 alias Fields = Tuple!(int, "id", string, float);
608 static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
612 * Use `t.expand` for a `Tuple` `t` to expand it into its
613 * components. The result of `expand` acts as if the `Tuple`'s components
614 * were listed as a list of values. (Ordinarily, a `Tuple` acts as a
618 mixin(injectNamedFields());
621 static if (Specs.length == 0) @safe unittest
623 auto t1 = tuple(1, " hello ", 'a');
624 assert(t1.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`);
626 void takeSeveralTypes(int n, string s, bool b)
628 assert(n == 4 && s == "test" && b == false);
631 auto t2 = tuple(4, "test", false);
632 //t.expand acting as a list of values
633 takeSeveralTypes(t2.expand);
636 static if (is(Specs))
638 // This is mostly to make t[n] work.
644 ref inout(Tuple!Types) _Tuple_super() inout @trusted
646 static foreach (i; 0 .. Types.length) // Rely on the field layout
648 static assert(typeof(return).init.tupleof[i].offsetof ==
651 return *cast(typeof(return)*) &(field[0]);
653 // This is mostly to make t[n] work.
654 alias _Tuple_super this;
657 // backwards compatibility
658 alias field = expand;
661 * Constructor taking one value for each field.
664 * values = A list of values that are either the same
665 * types as those given by the `Types` field
666 * of this `Tuple`, or can implicitly convert
667 * to those types. They must be in the same
668 * order as they appear in `Types`.
670 static if (Types.length > 0)
679 static if (Specs.length == 0) @safe unittest
681 alias ISD = Tuple!(int, string, double);
682 auto tup = ISD(1, "test", 3.2);
683 assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`);
687 * Constructor taking a compatible array.
690 * values = A compatible static array to build the `Tuple` from.
691 * Array slices are not supported.
693 this(U, size_t n)(U[n] values)
694 if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))
696 static foreach (i; 0 .. Types.length)
698 field[i] = values[i];
703 static if (Specs.length == 0) @safe unittest
706 Tuple!(int, int) t = ints;
710 * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible
711 * $(B iff) they are both of the same length, and, for each type `T` on the
712 * left-hand side, the corresponding type `U` on the right-hand side can
713 * implicitly convert to `T`.
716 * another = A compatible `Tuple` to build from. Its type must be
717 * compatible with the target `Tuple`'s type.
720 if (areBuildCompatibleTuples!(typeof(this), U))
722 field[] = another.field[];
726 static if (Specs.length == 0) @safe unittest
728 alias IntVec = Tuple!(int, int, int);
729 alias DubVec = Tuple!(double, double, double);
731 IntVec iv = tuple(1, 1, 1);
733 //Ok, int can implicitly convert to double
735 //Error: double cannot implicitly convert to int
740 * Comparison for equality. Two `Tuple`s are considered equal
741 * $(B iff) they fulfill the following criteria:
744 * $(LI Each `Tuple` is the same length.)
745 * $(LI For each type `T` on the left-hand side and each type
746 * `U` on the right-hand side, values of type `T` can be
747 * compared with values of type `U`.)
748 * $(LI For each value `v1` on the left-hand side and each value
749 * `v2` on the right-hand side, the expression `v1 == v2` is
753 * rhs = The `Tuple` to compare against. It must meeting the criteria
754 * for comparison between `Tuple`s.
757 * true if both `Tuple`s are equal, otherwise false.
759 bool opEquals(R)(R rhs)
760 if (areCompatibleTuples!(typeof(this), R, "=="))
762 return field[] == rhs.field[];
766 bool opEquals(R)(R rhs) const
767 if (areCompatibleTuples!(typeof(this), R, "=="))
769 return field[] == rhs.field[];
773 bool opEquals(R...)(auto ref R rhs)
774 if (R.length > 1 && areCompatibleTuples!(typeof(this), Tuple!R, "=="))
776 static foreach (i; 0 .. Types.length)
777 if (field[i] != rhs[i])
784 static if (Specs.length == 0) @safe unittest
786 Tuple!(int, string) t1 = tuple(1, "test");
787 Tuple!(double, string) t2 = tuple(1.0, "test");
788 //Ok, int can be compared with double and
789 //both have a value of 1
794 * Comparison for ordering.
797 * rhs = The `Tuple` to compare against. It must meet the criteria
798 * for comparison between `Tuple`s.
801 * For any values `v1` contained by the left-hand side tuple and any
802 * values `v2` contained by the right-hand side:
804 * 0 if `v1 == v2` for all members or the following value for the
805 * first position were the mentioned criteria is not satisfied:
808 * $(LI NaN, in case one of the operands is a NaN.)
809 * $(LI A negative number if the expression `v1 < v2` is true.)
810 * $(LI A positive number if the expression `v1 > v2` is true.))
813 if (areCompatibleTuples!(typeof(this), R, "<"))
815 static foreach (i; 0 .. Types.length)
817 if (field[i] != rhs.field[i])
819 import std.math.traits : isNaN;
820 static if (isFloatingPoint!(Types[i]))
825 static if (isFloatingPoint!(typeof(rhs.field[i])))
827 if (isNaN(rhs.field[i]))
830 static if (is(typeof(field[i].opCmp(rhs.field[i]))) &&
831 isFloatingPoint!(typeof(field[i].opCmp(rhs.field[i]))))
833 if (isNaN(field[i].opCmp(rhs.field[i])))
837 return field[i] < rhs.field[i] ? -1 : 1;
844 auto opCmp(R)(R rhs) const
845 if (areCompatibleTuples!(typeof(this), R, "<"))
847 static foreach (i; 0 .. Types.length)
849 if (field[i] != rhs.field[i])
851 import std.math.traits : isNaN;
852 static if (isFloatingPoint!(Types[i]))
857 static if (isFloatingPoint!(typeof(rhs.field[i])))
859 if (isNaN(rhs.field[i]))
862 static if (is(typeof(field[i].opCmp(rhs.field[i]))) &&
863 isFloatingPoint!(typeof(field[i].opCmp(rhs.field[i]))))
865 if (isNaN(field[i].opCmp(rhs.field[i])))
869 return field[i] < rhs.field[i] ? -1 : 1;
876 The first `v1` for which `v1 > v2` is true determines
877 the result. This could lead to unexpected behaviour.
879 static if (Specs.length == 0) @safe unittest
881 auto tup1 = tuple(1, 1, 1);
882 auto tup2 = tuple(1, 100, 100);
885 //Only the first result matters for comparison
892 Tuple concatenation is only allowed if all named fields are distinct (no named field of this tuple occurs in `t`
893 and no named field of `t` occurs in this tuple).
896 t = The `Tuple` to concatenate with
898 Returns: A concatenation of this tuple and `t`
900 auto opBinary(string op, T)(auto ref T t)
901 if (op == "~" && !(is(T : U[], U) && isTuple!U))
903 static if (isTuple!T)
905 static assert(distinctFieldNames!(_Fields, T._Fields),
906 "Cannot concatenate tuples with duplicate fields: " ~ fieldNames.stringof ~
907 " - " ~ T.fieldNames.stringof);
908 return Tuple!(_Fields, T._Fields)(expand, t.expand);
912 return Tuple!(_Fields, T)(expand, t);
917 auto opBinaryRight(string op, T)(auto ref T t)
918 if (op == "~" && !(is(T : U[], U) && isTuple!U))
920 static if (isTuple!T)
922 static assert(distinctFieldNames!(_Fields, T._Fields),
923 "Cannot concatenate tuples with duplicate fields: " ~ T.stringof ~
924 " - " ~ fieldNames.fieldNames.stringof);
925 return Tuple!(T._Fields, _Fields)(t.expand, expand);
929 return Tuple!(T, _Fields)(t, expand);
934 * Assignment from another `Tuple`.
937 * rhs = The source `Tuple` to assign from. Each element of the
938 * source `Tuple` must be implicitly assignable to each
939 * respective element of the target `Tuple`.
941 ref Tuple opAssign(R)(auto ref R rhs)
942 if (areCompatibleTuples!(typeof(this), R, "="))
944 import std.algorithm.mutation : swap;
946 static if (is(R : Tuple!Types) && !__traits(isRef, rhs) && isTuple!R)
950 // Cannot use swap at compile time
951 field[] = rhs.field[];
955 // Use swap-and-destroy to optimize rvalue assignment
956 swap!(Tuple!Types)(this, rhs);
961 // Do not swap; opAssign should be called on the fields.
962 field[] = rhs.field[];
968 * Renames the elements of a $(LREF Tuple).
970 * `rename` uses the passed `names` and returns a new
971 * $(LREF Tuple) using these names, with the content
973 * If fewer names are passed than there are members
974 * of the $(LREF Tuple) then those trailing members are unchanged.
975 * An empty string will remove the name for that member.
976 * It is an compile-time error to pass more names than
977 * there are members of the $(LREF Tuple).
979 ref rename(names...)() inout return
980 if (names.length == 0 || allSatisfy!(isSomeString, typeof(names)))
982 import std.algorithm.comparison : equal;
983 // to circumvent https://issues.dlang.org/show_bug.cgi?id=16418
984 static if (names.length == 0 || equal([names], [fieldNames]))
988 enum nT = Types.length;
989 enum nN = names.length;
990 static assert(nN <= nT, "Cannot have more names than tuple members");
991 alias allNames = AliasSeq!(names, fieldNames[nN .. $]);
993 import std.meta : Alias, aliasSeqOf;
995 template GetItem(size_t idx)
997 import std.array : empty;
999 alias GetItem = Alias!(Types[idx]);
1000 else static if (allNames[idx - nT].empty)
1001 alias GetItem = AliasSeq!();
1003 alias GetItem = Alias!(allNames[idx - nT]);
1006 import std.range : roundRobin, iota;
1007 alias NewTupleT = Tuple!(staticMap!(GetItem, aliasSeqOf!(
1008 roundRobin(iota(nT), iota(nT, 2*nT)))));
1009 return *(() @trusted => cast(NewTupleT*)&this)();
1014 static if (Specs.length == 0) @safe unittest
1016 auto t0 = tuple(4, "hello");
1018 auto t0Named = t0.rename!("val", "tag");
1019 assert(t0Named.val == 4);
1020 assert(t0Named.tag == "hello");
1022 Tuple!(float, "dat", size_t[2], "pos") t1;
1024 auto t1Named = t1.rename!"height";
1025 t1Named.height = 3.4f;
1026 assert(t1Named.height == 3.4f);
1027 assert(t1Named.pos == [2, 1]);
1028 t1Named.rename!"altitude".altitude = 5;
1029 assert(t1Named.height == 5);
1031 Tuple!(int, "a", int, int, "c") t2;
1033 auto t2Named = t2.rename!("", "b");
1034 // "a" no longer has a name
1035 static assert(!__traits(hasMember, typeof(t2Named), "a"));
1036 assert(t2Named[0] == 3);
1037 assert(t2Named.b == 4);
1038 assert(t2Named.c == 5);
1040 // not allowed to specify more names than the tuple has members
1041 static assert(!__traits(compiles, t2.rename!("a","b","c","d")));
1043 // use it in a range pipeline
1044 import std.range : iota, zip;
1045 import std.algorithm.iteration : map, sum;
1046 auto res = zip(iota(1, 4), iota(10, 13))
1047 .map!(t => t.rename!("a", "b"))
1048 .map!(t => t.a * t.b)
1052 const tup = Tuple!(int, "a", int, "b")(2, 3);
1053 const renamed = tup.rename!("c", "d");
1054 assert(renamed.c + renamed.d == 5);
1058 * Overload of $(LREF _rename) that takes an associative array
1059 * `translate` as a template parameter, where the keys are
1060 * either the names or indices of the members to be changed
1061 * and the new names are the corresponding values.
1062 * Every key in `translate` must be the name of a member of the
1064 * The same rules for empty strings apply as for the variadic
1065 * template overload of $(LREF _rename).
1067 ref rename(alias translate)() inout
1068 if (is(typeof(translate) : V[K], V, K) && isSomeString!V &&
1069 (isSomeString!K || is(K : size_t)))
1071 import std.meta : aliasSeqOf;
1072 import std.range : ElementType;
1073 static if (isSomeString!(ElementType!(typeof(translate.keys))))
1076 import std.conv : to;
1077 import std.algorithm.iteration : filter;
1078 import std.algorithm.searching : canFind;
1079 enum notFound = translate.keys
1080 .filter!(k => fieldNames.canFind(k) == -1);
1081 static assert(notFound.empty, "Cannot find members "
1082 ~ notFound.to!string ~ " in type "
1083 ~ typeof(this).stringof);
1085 return this.rename!(aliasSeqOf!(
1087 import std.array : empty;
1088 auto names = [fieldNames];
1089 foreach (ref n; names)
1091 if (auto p = n in translate)
1099 import std.algorithm.iteration : filter;
1100 import std.conv : to;
1101 enum invalid = translate.keys.
1102 filter!(k => k < 0 || k >= this.length);
1103 static assert(invalid.empty, "Indices " ~ invalid.to!string
1104 ~ " are out of bounds for tuple with length "
1105 ~ this.length.to!string);
1107 return this.rename!(aliasSeqOf!(
1109 auto names = [fieldNames];
1110 foreach (k, v; translate)
1118 static if (Specs.length == 0) @safe unittest
1120 //replacing names by their current name
1122 Tuple!(float, "dat", size_t[2], "pos") t1;
1124 auto t1Named = t1.rename!(["dat": "height"]);
1125 t1Named.height = 3.4;
1126 assert(t1Named.pos == [2, 1]);
1127 t1Named.rename!(["height": "altitude"]).altitude = 5;
1128 assert(t1Named.height == 5);
1130 Tuple!(int, "a", int, "b") t2;
1132 auto t2Named = t2.rename!(["a": "b", "b": "c"]);
1133 assert(t2Named.b == 3);
1134 assert(t2Named.c == 4);
1136 const t3 = Tuple!(int, "a", int, "b")(3, 4);
1137 const t3Named = t3.rename!(["a": "b", "b": "c"]);
1138 assert(t3Named.b == 3);
1139 assert(t3Named.c == 4);
1143 static if (Specs.length == 0) @safe unittest
1145 //replace names by their position
1147 Tuple!(float, "dat", size_t[2], "pos") t1;
1149 auto t1Named = t1.rename!([0: "height"]);
1150 t1Named.height = 3.4;
1151 assert(t1Named.pos == [2, 1]);
1152 t1Named.rename!([0: "altitude"]).altitude = 5;
1153 assert(t1Named.height == 5);
1155 Tuple!(int, "a", int, "b", int, "c") t2;
1156 t2 = tuple(3, 4, 5);
1157 auto t2Named = t2.rename!([0: "c", 2: "a"]);
1158 assert(t2Named.a == 5);
1159 assert(t2Named.b == 4);
1160 assert(t2Named.c == 3);
1163 static if (Specs.length == 0) @safe unittest
1165 //check that empty translations work fine
1166 enum string[string] a0 = null;
1167 enum string[int] a1 = null;
1168 Tuple!(float, "a", float, "b") t0;
1170 auto t1 = t0.rename!a0;
1174 auto t2 = t0.rename!a1;
1177 auto t3 = t0.rename;
1183 * Takes a slice by-reference of this `Tuple`.
1186 * from = A `size_t` designating the starting position of the slice.
1187 * to = A `size_t` designating the ending position (exclusive) of the slice.
1190 * A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original.
1191 * It has the same types and values as the range `[from, to$(RPAREN)` in
1195 ref inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout @trusted
1196 if (from <= to && to <= Types.length)
1199 (typeof(this).alignof % typeof(return).alignof == 0) &&
1200 (expand[from].offsetof % typeof(return).alignof == 0),
1201 "Slicing by reference is impossible because of an alignment mistmatch" ~
1202 " (See https://issues.dlang.org/show_bug.cgi?id=15645).");
1204 return *cast(typeof(return)*) &(field[from]);
1208 static if (Specs.length == 0) @safe unittest
1210 Tuple!(int, string, float, double) a;
1213 auto s = a.slice!(1, 3);
1214 static assert(is(typeof(s) == Tuple!(string, float)));
1215 assert(s[0] == "abc" && s[1] == 4.5);
1217 // https://issues.dlang.org/show_bug.cgi?id=15645
1218 Tuple!(int, short, bool, double) b;
1219 static assert(!__traits(compiles, b.slice!(2, 4)));
1223 Creates a hash of this `Tuple`.
1226 A `size_t` representing the hash of this `Tuple`.
1228 size_t toHash() const nothrow @safe
1231 static foreach (i, T; Types)
1233 static if (__traits(compiles, h = .hashOf(field[i])))
1234 const k = .hashOf(field[i]);
1237 // Workaround for when .hashOf is not both @safe and nothrow.
1238 static if (is(T : shared U, U) && __traits(compiles, (U* a) nothrow @safe => .hashOf(*a))
1239 && !__traits(hasMember, T, "toHash"))
1240 // BUG: Improperly casts away `shared`!
1241 const k = .hashOf(*(() @trusted => cast(U*) &field[i])());
1243 // BUG: Improperly casts away `shared`!
1244 const k = typeid(T).getHash((() @trusted => cast(const void*) &field[i])());
1249 // As in boost::hash_combine
1250 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine
1251 h ^= k + 0x9e3779b9 + (h << 6) + (h >>> 2);
1257 * Converts to string.
1260 * The string representation of this `Tuple`.
1262 string toString()() const
1264 import std.array : appender;
1265 auto app = appender!string();
1266 this.toString((const(char)[] chunk) => app ~= chunk);
1270 import std.format.spec : FormatSpec;
1273 * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`.
1275 * $(TABLE2 Formats supported by Tuple,
1276 * $(THEAD Format, Description)
1277 * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.))
1278 * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`$(COMMA) so
1279 * it may contain as many formats as the `Tuple` has fields.))
1280 * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format$(COMMA) that is applied
1281 * on all fields of the `Tuple`. The inner format must be compatible to all
1285 * sink = A `char` accepting delegate
1286 * fmt = A $(REF FormatSpec, std,format)
1288 void toString(DG)(scope DG sink) const
1290 auto f = FormatSpec!char();
1295 void toString(DG, Char)(scope DG sink, scope const ref FormatSpec!Char fmt) const
1297 import std.format : format, FormatException;
1298 import std.format.write : formattedWrite;
1299 import std.range : only;
1304 foreach (i, Type; Types)
1310 // TODO: Change this once formattedWrite() works for shared objects.
1311 static if (is(Type == class) && is(Type == shared))
1313 sink(Type.stringof);
1317 formattedWrite(sink, fmt.nested, this.field[i]);
1323 formattedWrite(sink, fmt.nested, staticMap!(sharedToString, this.expand));
1326 else if (fmt.spec == 's')
1328 enum header = Unqual!(typeof(this)).stringof ~ "(",
1332 foreach (i, Type; Types)
1338 // TODO: Change this once format() works for shared objects.
1339 static if (is(Type == class) && is(Type == shared))
1341 sink(Type.stringof);
1345 sink(format!("%(%s%)")(only(field[i])));
1352 const spec = fmt.spec;
1353 throw new FormatException(
1354 "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~
1355 Unqual!(typeof(this)).stringof ~ "', not '%" ~ spec ~ "'.");
1360 static if (Specs.length == 0) @safe unittest
1362 import std.format : format;
1364 Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ];
1367 assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`);
1369 // One Format for each individual component
1370 assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`);
1371 assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`);
1373 // One Format for all components
1374 assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`);
1377 assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`);
1381 static if (Specs.length == 0) @safe unittest
1383 import std.exception : assertThrown;
1384 import std.format : format, FormatException;
1386 // Error: %( %) missing.
1387 assertThrown!FormatException(
1388 format("%d, %f", tuple(1, 2.0)) == `1, 2.0`
1391 // Error: %( %| %) missing.
1392 assertThrown!FormatException(
1393 format("%d", tuple(1, 2)) == `1, 2`
1396 // Error: %d inadequate for double
1397 assertThrown!FormatException(
1398 format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0`
1407 Tuple!(int, int) point;
1408 // assign coordinates
1417 `Tuple` members can be named. It is legal to mix named and unnamed
1418 members. The method above is still applicable to all fields.
1422 alias Entry = Tuple!(int, "index", string, "value");
1426 assert(e[1] == "Hello");
1431 A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed
1432 fields, i.e. each naming imparts a separate type for the `Tuple`. Two
1433 `Tuple`s differing in naming only are still distinct, even though they
1434 might have the same structure.
1438 Tuple!(int, "x", int, "y") point1;
1439 Tuple!(int, int) point2;
1440 assert(!is(typeof(point1) == typeof(point2)));
1443 /// Use tuples as ranges
1446 import std.algorithm.iteration : sum;
1447 import std.range : only;
1448 auto t = tuple(1, 2);
1449 assert(t.expand.only.sum == 3);
1452 // https://issues.dlang.org/show_bug.cgi?id=4582
1455 static assert(!__traits(compiles, Tuple!(string, "id", int, "id")));
1456 static assert(!__traits(compiles, Tuple!(string, "str", int, "i", string, "str", float)));
1459 /// Concatenate tuples
1462 import std.meta : AliasSeq;
1463 auto t = tuple(1, "2") ~ tuple(ushort(42), true);
1464 static assert(is(t.Types == AliasSeq!(int, string, ushort, bool)));
1465 assert(t[1] == "2");
1467 assert(t[3] == true);
1470 // https://issues.dlang.org/show_bug.cgi?id=14637
1474 auto t = tuple!"foo"(1.0) ~ tuple!"bar"("3");
1475 static assert(is(t.Types == AliasSeq!(double, string)));
1476 static assert(t.fieldNames == tuple("foo", "bar"));
1477 assert(t.foo == 1.0);
1478 assert(t.bar == "3");
1481 // https://issues.dlang.org/show_bug.cgi?id=18824
1485 alias Type = Tuple!(int, string);
1487 auto t = tuple(2, "s");
1488 // Test opBinaryRight
1492 static assert(is(typeof(arr) == Type[]));
1495 static assert(is(typeof(c) == immutable(Type)[]));
1501 auto t = tuple!"foo"(1.0) ~ "3";
1502 static assert(is(t.Types == AliasSeq!(double, string)));
1503 assert(t.foo == 1.0);
1510 auto t = "2" ~ tuple!"foo"(1.0);
1511 static assert(is(t.Types == AliasSeq!(string, double)));
1512 assert(t.foo == 1.0);
1519 auto t = "2" ~ tuple!"foo"(1.0) ~ tuple(42, 3.0f) ~ real(1) ~ "a";
1520 static assert(is(t.Types == AliasSeq!(string, double, int, float, real, string)));
1521 assert(t.foo == 1.0);
1522 assert(t[0] == "2");
1523 assert(t[1] == 1.0);
1525 assert(t[3] == 3.0f);
1526 assert(t[4] == 1.0);
1527 assert(t[5] == "a");
1530 // ensure that concatenation of tuples with non-distinct fields is forbidden
1533 static assert(!__traits(compiles,
1534 tuple!("a")(0) ~ tuple!("a")("1")));
1535 static assert(!__traits(compiles,
1536 tuple!("a", "b")(0, 1) ~ tuple!("b", "a")("3", 1)));
1537 static assert(!__traits(compiles,
1538 tuple!("a")(0) ~ tuple!("b", "a")("3", 1)));
1539 static assert(!__traits(compiles,
1540 tuple!("a1", "a")(1.0, 0) ~ tuple!("a2", "a")("3", 0)));
1543 // Ensure that Tuple comparison with non-const opEquals works
1550 bool opEquals(Bad b)
1556 auto t = Tuple!(int, Bad, string)(1, Bad(1), "asdf");
1558 //Error: mutable method Bad.opEquals is not callable using a const object
1559 assert(t == AliasSeq!(1, Bad(1), "asdf"));
1562 // Ensure Tuple.toHash works
1565 Tuple!(int, int) point;
1566 assert(point.toHash == typeof(point).init.toHash);
1567 assert(tuple(1, 2) != point);
1568 assert(tuple(1, 2) == tuple(1, 2));
1570 assert(tuple(1, 2) != point);
1572 assert(tuple(1, 2) == point);
1575 @safe @betterC unittest
1577 auto t = tuple(1, 2);
1578 assert(t == tuple(1, 2));
1579 auto t3 = tuple(1, 'd');
1582 // https://issues.dlang.org/show_bug.cgi?id=20850
1583 // Assignment to enum tuple
1586 enum T : Tuple!(int*) { a = T(null) }
1591 // https://issues.dlang.org/show_bug.cgi?id=13663
1594 auto t = tuple(real.nan);
1604 float opCmp(S s) { return float.nan; }
1605 bool opEquals(S s) { return false; }
1608 auto t = tuple(S());
1614 // https://issues.dlang.org/show_bug.cgi?id=8015
1620 @property string toStr()
1631 Creates a copy of a $(LREF Tuple) with its fields in _reverse order.
1634 t = The `Tuple` to copy.
1639 auto reverse(T)(T t)
1642 import std.meta : Reverse;
1643 // @@@BUG@@@ Cannot be an internal function due to forward reference issues.
1645 // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple
1646 // return tuple(Reverse!(t.expand));
1648 ReverseTupleType!T result;
1649 auto tup = t.expand;
1650 result.expand = Reverse!tup;
1657 auto tup = tuple(1, "2");
1658 assert(tup.reverse == tuple("2", 1));
1661 /* Get a Tuple type with the reverse specification of Tuple T. */
1662 private template ReverseTupleType(T)
1665 static if (is(T : Tuple!A, A...))
1666 alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A);
1669 /* Reverse the Specs of a Tuple. */
1670 private template ReverseTupleSpecs(T...)
1672 static if (T.length > 1)
1674 static if (is(typeof(T[$-1]) : string))
1676 alias ReverseTupleSpecs = AliasSeq!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2]));
1680 alias ReverseTupleSpecs = AliasSeq!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1]));
1685 alias ReverseTupleSpecs = T;
1689 // ensure that internal Tuple unittests are compiled
1699 Tuple!(int, "a", int, "b") nosh;
1700 static assert(nosh.length == 2);
1703 assert(nosh.a == 5);
1704 assert(nosh.b == 6);
1707 Tuple!(short, double) b;
1708 static assert(b.length == 2);
1710 auto a = Tuple!(int, real)(b);
1711 assert(a[0] == 0 && a[1] == 5);
1712 a = Tuple!(int, real)(1, 2);
1713 assert(a[0] == 1 && a[1] == 2);
1714 auto c = Tuple!(int, "a", double, "b")(a);
1715 assert(c[0] == 1 && c[1] == 2);
1718 Tuple!(int, real) nosh;
1721 assert(nosh[0] == 5 && nosh[1] == 0);
1722 assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string);
1723 Tuple!(int, int) yessh;
1728 Tuple!(int, shared A) nosh;
1730 assert(nosh[0] == 5 && nosh[1] is null);
1731 assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))");
1734 Tuple!(int, string) t;
1737 assert(t[0] == 10 && t[1] == "str");
1738 assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string);
1741 Tuple!(int, "a", double, "b") x;
1742 static assert(x.a.offsetof == x[0].offsetof);
1743 static assert(x.b.offsetof == x[1].offsetof);
1746 assert(x[0] == 5 && x[1] == 4.5);
1747 assert(x.a == 5 && x.b == 4.5);
1751 Tuple!(int, real) t;
1752 static assert(is(typeof(t[0]) == int));
1753 static assert(is(typeof(t[1]) == real));
1758 assert(*p0 == t[0]);
1759 assert(*p1 == t[1]);
1763 Tuple!(int, "x", real, "y", double, "z", string) t;
1768 auto a = t.slice!(0, 3);
1769 assert(a.length == 3);
1773 auto b = t.slice!(2, 4);
1774 assert(b.length == 2);
1776 assert(b[1] == t[3]);
1780 Tuple!(Tuple!(int, real), Tuple!(string, "s")) t;
1781 static assert(is(typeof(t[0]) == Tuple!(int, real)));
1782 static assert(is(typeof(t[1]) == Tuple!(string, "s")));
1783 static assert(is(typeof(t[0][0]) == int));
1784 static assert(is(typeof(t[0][1]) == real));
1785 static assert(is(typeof(t[1].s) == string));
1786 t[0] = tuple(10, 20.0L);
1788 assert(t[0][0] == 10);
1789 assert(t[0][1] == 20.0L);
1790 assert(t[1].s == "abc");
1797 this(this) { ++count; }
1798 ~this() { --count; }
1799 void opAssign(S rhs) { count = rhs.count; }
1802 Tuple!(S, S) ssCopy = ss;
1803 assert(ssCopy[0].count == 1);
1804 assert(ssCopy[1].count == 1);
1805 ssCopy[1] = ssCopy[0];
1806 assert(ssCopy[1].count == 2);
1808 // https://issues.dlang.org/show_bug.cgi?id=2800
1812 Tuple!(int, int) _front;
1813 @property ref Tuple!(int, int) front() return { return _front; }
1814 @property bool empty() { return _front[0] >= 10; }
1815 void popFront() { ++_front[0]; }
1819 static assert(is(typeof(a) == Tuple!(int, int)));
1820 assert(0 <= a[0] && a[0] < 10);
1824 // Construction with compatible elements
1826 auto t1 = Tuple!(int, double)(1, 1);
1828 // https://issues.dlang.org/show_bug.cgi?id=8702
1829 auto t8702a = tuple(tuple(1));
1830 auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1));
1832 // Construction with compatible tuple
1837 Tuple!(int, "a", double, "b") y = x;
1841 static assert(!__traits(compiles, Tuple!(int, int)(y)));
1843 // https://issues.dlang.org/show_bug.cgi?id=6275
1847 alias T = Tuple!(const(int));
1850 // https://issues.dlang.org/show_bug.cgi?id=9431
1852 alias T = Tuple!(int[1][]);
1855 // https://issues.dlang.org/show_bug.cgi?id=7666
1857 auto tup = tuple(1, "2");
1858 assert(tup.reverse == tuple("2", 1));
1861 Tuple!(int, "x", string, "y") tup = tuple(1, "2");
1862 auto rev = tup.reverse;
1863 assert(rev == tuple("2", 1));
1864 assert(rev.x == 1 && rev.y == "2");
1867 Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup;
1868 tup = tuple('a', 'b', 3, "4", 'c', cast(byte) 0x0D, 0.00);
1869 auto rev = tup.reverse;
1870 assert(rev == tuple(0.00, cast(byte) 0x0D, 'c', "4", 3, 'b', 'a'));
1871 assert(rev.x == 3 && rev.y == "4");
1878 struct Equ1 { bool opEquals(Equ1) { return true; } }
1879 auto tm1 = tuple(Equ1.init);
1880 const tc1 = tuple(Equ1.init);
1881 static assert( is(typeof(tm1 == tm1)));
1882 static assert(!is(typeof(tm1 == tc1)));
1883 static assert(!is(typeof(tc1 == tm1)));
1884 static assert(!is(typeof(tc1 == tc1)));
1886 struct Equ2 { bool opEquals(const Equ2) const { return true; } }
1887 auto tm2 = tuple(Equ2.init);
1888 const tc2 = tuple(Equ2.init);
1889 static assert( is(typeof(tm2 == tm2)));
1890 static assert( is(typeof(tm2 == tc2)));
1891 static assert( is(typeof(tc2 == tm2)));
1892 static assert( is(typeof(tc2 == tc2)));
1894 // https://issues.dlang.org/show_bug.cgi?id=8686
1895 struct Equ3 { bool opEquals(T)(T) { return true; } }
1896 auto tm3 = tuple(Equ3.init);
1897 const tc3 = tuple(Equ3.init);
1898 static assert( is(typeof(tm3 == tm3)));
1899 static assert( is(typeof(tm3 == tc3)));
1900 static assert(!is(typeof(tc3 == tm3)));
1901 static assert(!is(typeof(tc3 == tc3)));
1903 struct Equ4 { bool opEquals(T)(T) const { return true; } }
1904 auto tm4 = tuple(Equ4.init);
1905 const tc4 = tuple(Equ4.init);
1906 static assert( is(typeof(tm4 == tm4)));
1907 static assert( is(typeof(tm4 == tc4)));
1908 static assert( is(typeof(tc4 == tm4)));
1909 static assert( is(typeof(tc4 == tc4)));
1913 struct Cmp1 { int opCmp(Cmp1) { return 0; } }
1914 auto tm1 = tuple(Cmp1.init);
1915 const tc1 = tuple(Cmp1.init);
1916 static assert( is(typeof(tm1 < tm1)));
1917 static assert(!is(typeof(tm1 < tc1)));
1918 static assert(!is(typeof(tc1 < tm1)));
1919 static assert(!is(typeof(tc1 < tc1)));
1921 struct Cmp2 { int opCmp(const Cmp2) const { return 0; } }
1922 auto tm2 = tuple(Cmp2.init);
1923 const tc2 = tuple(Cmp2.init);
1924 static assert( is(typeof(tm2 < tm2)));
1925 static assert( is(typeof(tm2 < tc2)));
1926 static assert( is(typeof(tc2 < tm2)));
1927 static assert( is(typeof(tc2 < tc2)));
1929 struct Cmp3 { int opCmp(T)(T) { return 0; } }
1930 auto tm3 = tuple(Cmp3.init);
1931 const tc3 = tuple(Cmp3.init);
1932 static assert( is(typeof(tm3 < tm3)));
1933 static assert( is(typeof(tm3 < tc3)));
1934 static assert(!is(typeof(tc3 < tm3)));
1935 static assert(!is(typeof(tc3 < tc3)));
1937 struct Cmp4 { int opCmp(T)(T) const { return 0; } }
1938 auto tm4 = tuple(Cmp4.init);
1939 const tc4 = tuple(Cmp4.init);
1940 static assert( is(typeof(tm4 < tm4)));
1941 static assert( is(typeof(tm4 < tc4)));
1942 static assert( is(typeof(tc4 < tm4)));
1943 static assert( is(typeof(tc4 < tc4)));
1945 // https://issues.dlang.org/show_bug.cgi?id=14890
1946 static void test14890(inout int[] dummy)
1948 alias V = Tuple!(int, int);
1953 inout V wv; // OK <- NG
1954 inout const V wcv; // OK <- NG
1956 static foreach (v1; AliasSeq!(mv, cv, iv, wv, wcv))
1957 static foreach (v2; AliasSeq!(mv, cv, iv, wv, wcv))
1963 int[2] ints = [ 1, 2 ];
1964 Tuple!(int, int) t = ints;
1965 assert(t[0] == 1 && t[1] == 2);
1966 Tuple!(long, uint) t2 = ints;
1967 assert(t2[0] == 1 && t2[1] == 2);
1972 auto t1 = Tuple!(int, "x", string, "y")(1, "a");
1974 assert(t1.y == "a");
1975 void foo(Tuple!(int, string) t2) {}
1978 Tuple!(int, int)[] arr;
1979 arr ~= tuple(10, 20); // OK
1980 arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK
1982 static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) ==
1983 typeof(Tuple!(int, string ).tupleof)));
1987 // https://issues.dlang.org/show_bug.cgi?id=10686
1988 immutable Tuple!(int) t1;
1989 auto r1 = t1[0]; // OK
1990 immutable Tuple!(int, "x") t2;
1991 auto r2 = t2[0]; // error
1995 import std.exception : assertCTFEable;
1997 // https://issues.dlang.org/show_bug.cgi?id=10218
2001 t = tuple(2); // assignment
2007 Tuple!(immutable(Foo)[]) a;
2012 //Test non-assignable
2017 alias IS = immutable S;
2018 static assert(!isAssignable!IS);
2022 alias TIS = Tuple!IS;
2026 alias TISIS = Tuple!(IS, IS);
2027 TISIS d = tuple(s, s);
2029 TISIS e = TISIS(ss);
2032 // https://issues.dlang.org/show_bug.cgi?id=9819
2035 alias T = Tuple!(int, "x", double, "foo");
2036 static assert(T.fieldNames[0] == "x");
2037 static assert(T.fieldNames[1] == "foo");
2039 alias Fields = Tuple!(int, "id", string, float);
2040 static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
2043 // https://issues.dlang.org/show_bug.cgi?id=13837
2046 // New behaviour, named arguments.
2048 typeof(tuple!("x")(1)) == Tuple!(int, "x")));
2050 typeof(tuple!("x")(1.0)) == Tuple!(double, "x")));
2052 typeof(tuple!("x")("foo")) == Tuple!(string, "x")));
2054 typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y")));
2056 auto a = tuple!("a", "b", "c")("1", 2, 3.0f);
2057 static assert(is(typeof(a.a) == string));
2058 static assert(is(typeof(a.b) == int));
2059 static assert(is(typeof(a.c) == float));
2061 // Old behaviour, but with explicit type parameters.
2063 typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double)));
2065 typeof(tuple!(const int)(1)) == Tuple!(const int)));
2067 typeof(tuple()) == Tuple!()));
2069 // Nonsensical behaviour
2070 static assert(!__traits(compiles, tuple!(1)(2)));
2071 static assert(!__traits(compiles, tuple!("x")(1, 2)));
2072 static assert(!__traits(compiles, tuple!("x", "y")(1)));
2073 static assert(!__traits(compiles, tuple!("x")()));
2074 static assert(!__traits(compiles, tuple!("x", int)(2)));
2079 class C { override size_t toHash() const nothrow @safe { return 0; } }
2080 Tuple!(Rebindable!(const C)) a;
2085 @nogc @safe unittest
2087 alias T = Tuple!(string, "s");
2094 import std.format : format, FormatException;
2095 import std.exception : assertThrown;
2097 //enum tupStr = tuple(1, 1.0).toString; // toString is *impure*.
2098 //static assert(tupStr == `Tuple!(int, double)(1, 1)`);
2101 // https://issues.dlang.org/show_bug.cgi?id=17803, parte uno
2104 auto a = tuple(3, "foo");
2105 assert(__traits(compiles, { a = (a = a); }));
2110 Tuple!(int[]) a, b, c;
2111 a = tuple([0, 1, 2]);
2113 assert(a[0].length == b[0].length && b[0].length == c[0].length);
2114 assert(a[0].ptr == b[0].ptr && b[0].ptr == c[0].ptr);
2118 Constructs a $(LREF Tuple) object instantiated and initialized according to
2119 the given arguments.
2122 Names = An optional list of strings naming each successive field of the `Tuple`
2123 or a list of types that the elements are being casted to.
2124 For a list of names,
2125 each name matches up with the corresponding field given by `Args`.
2126 A name does not have to be provided for every field, but as
2127 the names must proceed in order, it is not possible to skip
2128 one field and name the next after it.
2129 For a list of types,
2130 there must be exactly as many types as parameters.
2132 template tuple(Names...)
2136 args = Values to initialize the `Tuple` with. The `Tuple`'s type will
2137 be inferred from the types of the values given.
2140 A new `Tuple` with its type inferred from the arguments given.
2142 auto tuple(Args...)(Args args)
2144 static if (Names.length == 0)
2146 // No specified names, just infer types from Args...
2147 return Tuple!Args(args);
2149 else static if (!is(typeof(Names[0]) : string))
2151 // Names[0] isn't a string, must be explicit types.
2152 return Tuple!Names(args);
2156 // Names[0] is a string, so must be specifying names.
2157 static assert(Names.length == Args.length,
2158 "Insufficient number of names given.");
2160 // Interleave(a, b).and(c, d) == (a, c, b, d)
2161 // This is to get the interleaving of types and names for Tuple
2162 // e.g. Tuple!(int, "x", string, "y")
2163 template Interleave(A...)
2165 template and(B...) if (B.length == 1)
2167 alias and = AliasSeq!(A[0], B[0]);
2170 template and(B...) if (B.length != 1)
2172 alias and = AliasSeq!(A[0], B[0],
2173 Interleave!(A[1..$]).and!(B[1..$]));
2176 return Tuple!(Interleave!(Args).and!(Names))(args);
2184 auto value = tuple(5, 6.7, "hello");
2185 assert(value[0] == 5);
2186 assert(value[1] == 6.7);
2187 assert(value[2] == "hello");
2189 // Field names can be provided.
2190 auto entry = tuple!("index", "value")(4, "Hello");
2191 assert(entry.index == 4);
2192 assert(entry.value == "Hello");
2196 Returns `true` if and only if `T` is an instance of `std.typecons.Tuple`.
2199 T = The type to check.
2202 true if `T` is a `Tuple` type, false otherwise.
2204 enum isTuple(T) = __traits(compiles,
2206 void f(Specs...)(Tuple!Specs tup) {}
2213 static assert(isTuple!(Tuple!()));
2214 static assert(isTuple!(Tuple!(int)));
2215 static assert(isTuple!(Tuple!(int, real, string)));
2216 static assert(isTuple!(Tuple!(int, "x", real, "y")));
2217 static assert(isTuple!(Tuple!(int, Tuple!(real), string)));
2222 static assert(isTuple!(const Tuple!(int)));
2223 static assert(isTuple!(immutable Tuple!(int)));
2225 static assert(!isTuple!(int));
2226 static assert(!isTuple!(const int));
2229 static assert(!isTuple!(S));
2232 // used by both Rebindable and UnqualRef
2233 private mixin template RebindableCommon(T, U, alias This)
2234 if (is(T == class) || is(T == interface) || isAssociativeArray!T)
2242 void opAssign(return scope T another) pure nothrow @nogc
2244 // If `T` defines `opCast` we must infer the safety
2245 static if (hasMember!(T, "opCast"))
2247 // This will allow the compiler to infer the safety of `T.opCast!U`
2248 // without generating any runtime cost
2249 if (false) { stripped = cast(U) another; }
2251 () @trusted { stripped = cast(U) another; }();
2254 void opAssign(typeof(this) another) @trusted pure nothrow @nogc
2256 stripped = another.stripped;
2259 static if (is(T == const U) && is(T == const shared U))
2261 // safely assign immutable to const / const shared
2262 void opAssign(This!(immutable U) another) @trusted pure nothrow @nogc
2264 stripped = another.stripped;
2268 this(T initializer) pure nothrow @nogc
2270 // Infer safety from opAssign
2271 opAssign(initializer);
2274 @property inout(T) get() @trusted pure nothrow @nogc return scope inout
2279 bool opEquals()(auto ref const(typeof(this)) rhs) const
2281 // Must forward explicitly because 'stripped' is part of a union.
2282 // The necessary 'toHash' is forwarded to the class via alias this.
2283 return stripped == rhs.stripped;
2286 bool opEquals(const(U) rhs) const
2288 return stripped == rhs;
2295 `Rebindable!(T)` is a simple, efficient wrapper that behaves just
2296 like an object of type `T`, except that you can reassign it to
2297 refer to another object. For completeness, `Rebindable!(T)` aliases
2298 itself away to `T` if `T` is a non-const object type.
2300 You may want to use `Rebindable` when you want to have mutable
2301 storage referring to `const` objects, for example an array of
2302 references that must be sorted in place. `Rebindable` does not
2303 break the soundness of D's type system and does not incur any of the
2304 risks usually associated with `cast`.
2307 T = An object, interface, array slice type, or associative array type.
2309 template Rebindable(T)
2310 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2312 static if (is(T == const U, U) || is(T == immutable U, U))
2314 static if (isDynamicArray!T)
2316 import std.range.primitives : ElementEncodingType;
2317 alias Rebindable = const(ElementEncodingType!T)[];
2323 mixin RebindableCommon!(T, U, Rebindable);
2329 alias Rebindable = T;
2333 ///Regular `const` object references cannot be reassigned.
2336 class Widget { int x; int y() @safe const { return x; } }
2337 const a = new Widget;
2340 // error! can't modify const a
2342 // error! can't modify const a
2347 However, `Rebindable!(Widget)` does allow reassignment,
2348 while otherwise behaving exactly like a $(D const Widget).
2352 class Widget { int x; int y() const @safe { return x; } }
2353 auto a = Rebindable!(const Widget)(new Widget);
2356 // error! can't modify const a
2362 // https://issues.dlang.org/show_bug.cgi?id=16054
2365 Rebindable!(immutable Object) r;
2366 static assert(__traits(compiles, r.get()));
2367 static assert(!__traits(compiles, &r.get()));
2374 override size_t toHash() const nothrow @trusted { return 42; }
2376 Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash();
2377 assert(a.toHash() == 42, "Rebindable!A should offer toHash()"
2378 ~ " by forwarding to A.toHash().");
2381 // https://issues.dlang.org/show_bug.cgi?id=18615
2382 // Rebindable!A should use A.opEqualsa
2388 override bool opEquals(Object rhsObj)
2390 if (auto rhs = cast(const(CustomOpEq)) rhsObj)
2391 return this.x == rhs.x;
2396 CustomOpEq a = new CustomOpEq();
2397 CustomOpEq b = new CustomOpEq();
2399 assert(a == b, "a.x == b.x should be true (0 == 0).");
2401 Rebindable!(const(CustomOpEq)) ra = a;
2402 Rebindable!(const(CustomOpEq)) rb = b;
2404 assert(ra == rb, "Rebindable should use CustomOpEq's opEquals, not 'is'.");
2405 assert(ra == b, "Rebindable!(someQualifier(A)) should be comparable"
2406 ~ " against const(A) via A.opEquals.");
2407 assert(a == rb, "Rebindable!(someQualifier(A)) should be comparable"
2408 ~ " against const(A) via A.opEquals.");
2412 assert(ra != b, "Rebindable!(someQualifier(A)) should be comparable"
2413 ~ " against const(A) via A.opEquals.");
2414 assert(a != rb, "Rebindable!(someQualifier(A)) should be comparable"
2415 ~ " against const(A) via A.opEquals.");
2417 Rebindable!(const(Object)) o1 = new Object();
2418 Rebindable!(const(Object)) o2 = new Object();
2420 assert(o1 == o1, "When the class doesn't provide its own opEquals,"
2421 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2422 assert(o1 != o2, "When the class doesn't provide its own opEquals,"
2423 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2424 assert(o1 != new Object(), "Rebindable!(const(Object)) should be"
2425 ~ " comparable against Object itself and use Object.opEquals.");
2428 // https://issues.dlang.org/show_bug.cgi?id=18755
2433 auto opCast(T)() @system immutable pure nothrow
2435 *(cast(uint*) 0xdeadbeef) = 0xcafebabe;
2440 static assert(!__traits(compiles, () @safe {
2441 auto r = Rebindable!(immutable Foo)(new Foo);
2443 static assert(__traits(compiles, () @system {
2444 auto r = Rebindable!(immutable Foo)(new Foo);
2449 Convenience function for creating a `Rebindable` using automatic type
2453 obj = A reference to an object, interface, associative array, or an array slice
2454 to initialize the `Rebindable` with.
2457 A newly constructed `Rebindable` initialized with the given reference.
2459 Rebindable!T rebindable(T)(T obj)
2460 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2473 this(int p) { payload = p; }
2477 auto c2 = c.rebindable;
2478 assert(c2.payload == 1);
2479 // passing Rebindable to rebindable
2483 assert(c2.payload == 2);
2486 assert(c3.payload == 2);
2490 This function simply returns the `Rebindable` object passed in. It's useful
2491 in generic programming cases when a given object may be either a regular
2492 `class` or a `Rebindable`.
2495 obj = An instance of Rebindable!T.
2498 `obj` without any modification.
2500 Rebindable!T rebindable(T)(Rebindable!T obj)
2505 // TODO: remove me once the rebindable overloads have been joined
2512 this(int p) { payload = p; }
2516 auto c2 = c.rebindable;
2517 assert(c2.payload == 1);
2518 // passing Rebindable to rebindable
2520 assert(c2.payload == 1);
2525 interface CI { int foo() const; }
2527 int foo() const { return 42; }
2528 @property int bar() const { return 23; }
2530 Rebindable!(C) obj0;
2531 static assert(is(typeof(obj0) == C));
2533 Rebindable!(const(C)) obj1;
2534 static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof);
2535 static assert(is(typeof(obj1.stripped) == C));
2537 assert(obj1.get !is null);
2538 obj1 = new const(C);
2539 assert(obj1.get !is null);
2541 Rebindable!(immutable(C)) obj2;
2542 static assert(is(typeof(obj2.get) == immutable(C)));
2543 static assert(is(typeof(obj2.stripped) == C));
2544 obj2 = new immutable(C);
2545 assert(obj1.get !is null);
2548 assert(obj2.foo() == 42);
2549 assert(obj2.bar == 23);
2551 interface I { final int foo() const { return 42; } }
2552 Rebindable!(I) obj3;
2553 static assert(is(typeof(obj3) == I));
2555 Rebindable!(const I) obj4;
2556 static assert(is(typeof(obj4.get) == const I));
2557 static assert(is(typeof(obj4.stripped) == I));
2558 static assert(is(typeof(obj4.foo()) == int));
2559 obj4 = new class I {};
2561 Rebindable!(immutable C) obj5i;
2562 Rebindable!(const C) obj5c;
2566 static assert(!__traits(compiles, obj5i = obj5c));
2568 // Test the convenience functions.
2569 auto obj5convenience = rebindable(obj5i);
2570 assert(obj5convenience is obj5i);
2572 auto obj6 = rebindable(new immutable(C));
2573 static assert(is(typeof(obj6) == Rebindable!(immutable C)));
2574 assert(obj6.foo() == 42);
2576 auto obj7 = rebindable(new C);
2577 CI interface1 = obj7;
2578 auto interfaceRebind1 = rebindable(interface1);
2579 assert(interfaceRebind1.foo() == 42);
2581 const interface2 = interface1;
2582 auto interfaceRebind2 = rebindable(interface2);
2583 assert(interfaceRebind2.foo() == 42);
2585 auto arr = [1,2,3,4,5];
2586 const arrConst = arr;
2587 assert(rebindable(arr) == arr);
2588 assert(rebindable(arrConst) == arr);
2590 // https://issues.dlang.org/show_bug.cgi?id=7654
2591 immutable(char[]) s7654;
2592 Rebindable!(typeof(s7654)) r7654 = s7654;
2594 static foreach (T; AliasSeq!(char, wchar, char, int))
2596 static assert(is(Rebindable!(immutable(T[])) == immutable(T)[]));
2597 static assert(is(Rebindable!(const(T[])) == const(T)[]));
2598 static assert(is(Rebindable!(T[]) == T[]));
2601 // https://issues.dlang.org/show_bug.cgi?id=12046
2602 static assert(!__traits(compiles, Rebindable!(int[1])));
2603 static assert(!__traits(compiles, Rebindable!(const int[1])));
2605 // Pull request 3341
2606 Rebindable!(immutable int[int]) pr3341 = [123:345];
2607 assert(pr3341[123] == 345);
2608 immutable int[int] pr3341_aa = [321:543];
2610 assert(pr3341[321] == 543);
2611 assert(rebindable(pr3341_aa)[321] == 543);
2615 Similar to `Rebindable!(T)` but strips all qualifiers from the reference as
2616 opposed to just constness / immutability. Primary intended use case is with
2617 shared (having thread-local reference to shared class data)
2620 T = A class or interface type.
2622 template UnqualRef(T)
2623 if (is(T == class) || is(T == interface))
2625 static if (is(T == immutable U, U)
2626 || is(T == const shared U, U)
2627 || is(T == const U, U)
2628 || is(T == shared U, U))
2632 mixin RebindableCommon!(T, U, UnqualRef);
2637 alias UnqualRef = T;
2646 static shared(Data) a;
2647 static UnqualRef!(shared Data) b;
2651 auto thread = new core.thread.Thread({
2652 a = new shared Data();
2653 b = new shared Data();
2666 alias T = UnqualRef!(const shared C);
2667 static assert(is(typeof(T.stripped) == C));
2673 Order the provided members to minimize size while preserving alignment.
2674 Alignment is not always optimal for 80-bit reals, nor for structs declared
2678 E = A list of the types to be aligned, representing fields
2679 of an aggregate such as a `struct` or `class`.
2681 names = The names of the fields that are to be aligned.
2684 A string to be mixed in to an aggregate, such as a `struct` or `class`.
2686 string alignForSize(E...)(const char[][] names...)
2688 // Sort all of the members by .alignof.
2689 // BUG: Alignment is not always optimal for align(1) structs
2690 // or 80-bit reals or 64-bit primitives on x86.
2691 // TRICK: Use the fact that .alignof is always a power of 2,
2692 // and maximum 16 on extant systems. Thus, we can perform
2693 // a very limited radix sort.
2694 // Contains the members with .alignof = 64,32,16,8,4,2,1
2696 assert(E.length == names.length,
2697 "alignForSize: There should be as many member names as the types");
2699 string[7] declaration = ["", "", "", "", "", "", ""];
2704 auto k = a >= 64? 0 : a >= 32? 1 : a >= 16? 2 : a >= 8? 3 : a >= 4? 4 : a >= 2? 5 : 6;
2705 declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n";
2709 foreach (decl; declaration)
2718 mixin(alignForSize!(byte[6], double)(["name", "height"]));
2724 enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w");
2725 struct Foo { int x; }
2726 enum y = alignForSize!(ubyte, Foo, double)("x", "y", "z");
2728 enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
2729 enum passNormalY = y == "double z;\nFoo y;\nubyte x;\n";
2731 enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
2732 enum passAbnormalY = y == "Foo y;\ndouble z;\nubyte x;\n";
2733 // ^ blame https://issues.dlang.org/show_bug.cgi?id=231
2735 static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof);
2736 static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof);
2739 // https://issues.dlang.org/show_bug.cgi?id=12914
2742 immutable string[] fieldNames = ["x", "y"];
2745 mixin(alignForSize!(byte, int)(fieldNames));
2750 Defines a value paired with a distinctive "null" state that denotes
2751 the absence of a value. If default constructed, a $(D
2752 Nullable!T) object starts in the null state. Assigning it renders it
2753 non-null. Calling `nullify` can nullify it again.
2755 Practically `Nullable!T` stores a `T` and a `bool`.
2759 private union DontCallDestructorT
2761 import std.traits : hasIndirections;
2762 static if (hasIndirections!T)
2768 private DontCallDestructorT _value = DontCallDestructorT.init;
2770 private bool _isNull = true;
2773 * Constructor initializing `this` with `value`.
2776 * value = The value to initialize this `Nullable` with.
2778 this(inout T value) inout
2780 _value.payload = value;
2784 static if (hasElaborateDestructor!T)
2790 destroy(_value.payload);
2795 this (ref return scope inout Nullable!T rhs) inout
2797 _isNull = rhs._isNull;
2799 _value.payload = rhs._value.payload;
2801 _value = DontCallDestructorT.init;
2805 * If they are both null, then they are equal. If one is null and the other
2806 * is not, then they are not equal. If they are both non-null, then they are
2807 * equal if their values are equal.
2809 bool opEquals(this This, Rhs)(auto ref Rhs rhs)
2810 if (!is(CommonType!(This, Rhs) == void))
2812 static if (is(This == Rhs))
2818 return _value.payload == rhs._value.payload;
2822 alias Common = CommonType!(This, Rhs);
2823 return cast(Common) this == cast(Common) rhs;
2828 bool opEquals(this This, Rhs)(auto ref Rhs rhs)
2829 if (is(CommonType!(This, Rhs) == void) && is(typeof(this.get == rhs)))
2831 return _isNull ? false : rhs == _value.payload;
2838 Nullable!int a = 42;
2839 Nullable!int b = 42;
2840 Nullable!int c = 27;
2842 assert(empty == empty);
2843 assert(empty == Nullable!int.init);
2851 assert(empty != 42);
2859 immutable Nullable!int a = 42;
2860 Nullable!int b = 42;
2861 immutable Nullable!int c = 29;
2862 Nullable!int d = 29;
2873 assert(a == const Nullable!int(42));
2874 assert(a != Nullable!int(29));
2877 // https://issues.dlang.org/show_bug.cgi?id=17482
2880 import std.variant : Variant;
2881 Nullable!Variant a = Variant(12);
2887 size_t toHash() const @safe nothrow
2889 static if (__traits(compiles, .hashOf(_value.payload)))
2890 return _isNull ? 0 : .hashOf(_value.payload);
2892 // Workaround for when .hashOf is not both @safe and nothrow.
2893 return _isNull ? 0 : typeid(T).getHash(&_value.payload);
2897 * Gives the string `"Nullable.null"` if `isNull` is `true`. Otherwise, the
2898 * result is equivalent to calling $(REF formattedWrite, std,format) on the
2902 * writer = A `char` accepting
2903 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
2904 * fmt = A $(REF FormatSpec, std,format) which is used to represent
2905 * the value if this Nullable is not null
2907 * A `string` if `writer` and `fmt` are not set; `void` otherwise.
2911 import std.array : appender;
2912 auto app = appender!string();
2913 auto spec = singleSpec("%s");
2914 toString(app, spec);
2919 string toString() const
2921 import std.array : appender;
2922 auto app = appender!string();
2923 auto spec = singleSpec("%s");
2924 toString(app, spec);
2929 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt)
2930 if (isOutputRange!(W, char))
2932 import std.range.primitives : put;
2934 put(writer, "Nullable.null");
2936 formatValue(writer, _value.payload, fmt);
2940 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) const
2941 if (isOutputRange!(W, char))
2943 import std.range.primitives : put;
2945 put(writer, "Nullable.null");
2947 formatValue(writer, _value.payload, fmt);
2951 * Check if `this` is in the null state.
2954 * true $(B iff) `this` is in the null state, otherwise false.
2956 @property bool isNull() const @safe pure nothrow
2971 // https://issues.dlang.org/show_bug.cgi?id=14940
2974 import std.array : appender;
2975 import std.format.write : formattedWrite;
2977 auto app = appender!string();
2979 formattedWrite(app, "%s", a);
2980 assert(app.data == "1");
2983 // https://issues.dlang.org/show_bug.cgi?id=19799
2986 import std.format : format;
2988 const Nullable!string a = const(Nullable!string)();
2994 * Forces `this` to the null state.
2998 static if (is(T == class) || is(T == interface))
2999 _value.payload = null;
3001 .destroy(_value.payload);
3008 Nullable!int ni = 0;
3016 * Assigns `value` to the internally-held state. If the assignment
3017 * succeeds, `this` becomes non-null.
3020 * value = A value of type `T` to assign to this `Nullable`.
3022 Nullable opAssign()(T value)
3024 import std.algorithm.mutation : moveEmplace, move;
3026 // the lifetime of the value in copy shall be managed by
3027 // this Nullable, so we must avoid calling its destructor.
3028 auto copy = DontCallDestructorT(value);
3032 // trusted since payload is known to be uninitialized.
3033 () @trusted { moveEmplace(copy.payload, _value.payload); }();
3037 move(copy.payload, _value.payload);
3044 * If this `Nullable` wraps a type that already has a null value
3045 * (such as a pointer), then assigning the null value to this
3046 * `Nullable` is no different than assigning any other value of
3047 * type `T`, and the resulting code will look very strange. It
3048 * is strongly recommended that this be avoided by instead using
3049 * the version of `Nullable` that takes an additional `nullValue`
3050 * template argument.
3055 Nullable!(int*) npi;
3060 assert(!npi.isNull);
3064 * Gets the value if not null. If `this` is in the null state, and the optional
3065 * parameter `fallback` was provided, it will be returned. Without `fallback`,
3066 * calling `get` with a null state is invalid.
3068 * When the fallback type is different from the Nullable type, `get(T)` returns
3072 * fallback = the value to return in case the `Nullable` is null.
3075 * The value held internally by this `Nullable`.
3077 @property ref inout(T) get() inout @safe pure nothrow
3079 enum message = "Called `get' on null Nullable!" ~ T.stringof ~ ".";
3080 assert(!isNull, message);
3081 return _value.payload;
3085 @property inout(T) get()(inout(T) fallback) inout
3087 return isNull ? fallback : _value.payload;
3091 @property auto get(U)(inout(U) fallback) inout
3093 return isNull ? fallback : _value.payload;
3098 auto nullable(T)(T t)
3100 return Nullable!T(t);
3106 struct CustomerRecord
3113 Nullable!CustomerRecord getByName(string name)
3115 //A bunch of hairy stuff
3117 return Nullable!CustomerRecord.init;
3120 auto queryResult = getByName("Doe, John");
3121 if (!queryResult.isNull)
3123 //Process Mr. Doe's customer record
3124 auto address = queryResult.get.address;
3125 auto customerNum = queryResult.get.customerNum;
3127 //Do some things with this customer's info
3131 //Add the customer to the database
3138 import std.exception : assertThrown;
3140 auto a = 42.nullable;
3142 assert(a.get == 42);
3146 assertThrown!Throwable(a.get);
3150 auto k = Nullable!int(74);
3157 static int f(scope const Nullable!int x) {
3158 return x.isNull ? 42 : x.get;
3169 import std.exception : assertThrown;
3171 static struct S { int x; }
3177 assert(s.get != S(0));
3179 assert(s.get.x == 9190);
3181 assertThrown!Throwable(s.get.x = 9441);
3185 // Ensure Nullable can be used in pure/nothrow/@safe environment.
3186 function() @safe pure nothrow
3199 // Ensure Nullable can be used when the value is not pure/nothrow/@safe
3203 this(this) @system {}
3210 assert(s.get.x == 5);
3215 // https://issues.dlang.org/show_bug.cgi?id=9404
3218 alias N = Nullable!int;
3223 b = a; // `N b = a;` works fine
3230 //Check nullable immutable is constructable
3232 auto a1 = Nullable!(immutable int)();
3233 auto a2 = Nullable!(immutable int)(1);
3236 //Check immutable nullable is constructable
3238 auto a1 = immutable (Nullable!int)();
3239 auto a2 = immutable (Nullable!int)(1);
3245 alias NInt = Nullable!int;
3249 //from other Nullable null
3254 //from other Nullable non-null
3259 //Construct from similar nullable
3260 auto a3 = immutable(NInt)();
3267 //from other Nullable null
3273 //from other Nullable non-null
3279 //Construct from similar nullable
3280 auto a3 = immutable(NInt)();
3288 //Check nullable is nicelly embedable in a struct
3293 static struct S2 //inspired from 9404
3300 void opAssign(ref S2 other)
3305 static foreach (S; AliasSeq!(S1, S2))
3314 // https://issues.dlang.org/show_bug.cgi?id=10268
3318 JSONValue value = null;
3319 auto na = Nullable!JSONValue(value);
3321 struct S1 { int val; }
3322 struct S2 { int* val; }
3323 struct S3 { immutable int* val; }
3327 immutable si = immutable S1(1);
3328 auto x1 = Nullable!S1(sm);
3329 auto x2 = immutable Nullable!S1(sm);
3330 auto x3 = Nullable!S1(si);
3331 auto x4 = immutable Nullable!S1(si);
3332 assert(x1.get.val == 1);
3333 assert(x2.get.val == 1);
3334 assert(x3.get.val == 1);
3335 assert(x4.get.val == 1);
3343 immutable si = immutable S2(&ni);
3344 auto x1 = Nullable!S2(sm);
3345 static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); }));
3346 static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); }));
3347 auto x4 = immutable Nullable!S2(si);
3348 assert(*x1.get.val == 10);
3349 assert(*x4.get.val == 10);
3354 immutable si = immutable S3(&ni);
3355 auto x1 = Nullable!S3(sm);
3356 auto x2 = immutable Nullable!S3(sm);
3357 auto x3 = Nullable!S3(si);
3358 auto x4 = immutable Nullable!S3(si);
3359 assert(*x1.get.val == 10);
3360 assert(*x2.get.val == 10);
3361 assert(*x3.get.val == 10);
3362 assert(*x4.get.val == 10);
3366 // https://issues.dlang.org/show_bug.cgi?id=10357
3369 import std.datetime;
3370 Nullable!SysTime time = SysTime(0);
3373 // https://issues.dlang.org/show_bug.cgi?id=10915
3376 import std.conv : to;
3379 Appender!string buffer;
3382 assert(ni.to!string() == "Nullable.null");
3383 assert((cast(const) ni).to!string() == "Nullable.null");
3385 struct Test { string s; }
3386 alias NullableTest = Nullable!Test;
3388 NullableTest nt = Test("test");
3389 // test output range version
3390 assert(nt.to!string() == `Test("test")`);
3391 // test appender version
3392 assert(nt.toString() == `Test("test")`);
3393 // test const version
3394 assert((cast(const) nt).toString() == `const(Test)("test")`);
3396 NullableTest ntn = Test("null");
3397 assert(ntn.to!string() == `Test("null")`);
3408 override string toString()
3410 return d.to!string();
3413 Nullable!TestToString ntts = new TestToString(2.5);
3414 assert(ntts.to!string() == "2.5");
3417 // https://issues.dlang.org/show_bug.cgi?id=14477
3420 static struct DisabledDefaultConstructor
3425 Nullable!DisabledDefaultConstructor var;
3426 var = DisabledDefaultConstructor(5);
3430 // https://issues.dlang.org/show_bug.cgi?id=17440
3433 static interface I { }
3440 canary = 0x5050DEAD;
3445 auto nc = nullable(c);
3447 assert(c.canary == 0xA71FE);
3450 auto ni = nullable(i);
3452 assert(c.canary == 0xA71FE);
3455 // https://issues.dlang.org/show_bug.cgi?id=19037
3458 import std.datetime : SysTime;
3464 nothrow invariant { assert(b == true); }
3468 static bool destroyed;
3471 this(bool b) { this.b = b; }
3472 ~this() @safe { destroyed = true; }
3474 // mustn't call opAssign on Test.init in Nullable!Test, because the invariant
3475 // will be called before opAssign on the Test.init that is in Nullable
3476 // and Test.init violates its invariant.
3477 void opAssign(Test rhs) @safe { assert(false); }
3486 Test.destroyed = false;
3490 assert(Test.destroyed);
3492 Test.destroyed = false;
3494 // don't run destructor on T.init in Nullable on scope exit!
3495 assert(!Test.destroyed);
3497 // check that the contained type's destructor is called on assignment
3502 // can't be static, since we need a specific value's pointer
3507 if (this.destroyedRef)
3509 *this.destroyedRef = true;
3520 // reset from rvalue destruction in Nullable's opAssign
3523 // overwrite Nullable
3526 // the original S should be destroyed.
3527 assert(destroyed == true);
3529 // check that the contained type's destructor is still called when required
3532 bool destructorCalled = false;
3537 ~this() { *this.destroyed = true; }
3543 assert(!destructorCalled);
3545 Nullable!S ns = Nullable!S(S(&destructorCalled));
3547 destructorCalled = false; // reset after S was destroyed in the NS constructor
3549 assert(destructorCalled);
3552 // check that toHash on Nullable is forwarded to the contained type
3557 size_t toHash() const @safe pure nothrow { return 5; }
3560 Nullable!S s1 = S();
3561 Nullable!S s2 = Nullable!S();
3563 assert(typeid(Nullable!S).getHash(&s1) == 5);
3564 assert(typeid(Nullable!S).getHash(&s2) == 0);
3567 // https://issues.dlang.org/show_bug.cgi?id=21704
3570 import std.array : staticArray;
3576 ~this() { destroyed = true; }
3580 Nullable!(Probe[1]) test = [Probe()].staticArray;
3586 // https://issues.dlang.org/show_bug.cgi?id=21705
3592 bool opEquals(S rhs) { return n == rhs.n; }
3595 Nullable!S test1 = S(1), test2 = S(1);
3599 assert(test1 == test2);
3602 // https://issues.dlang.org/show_bug.cgi?id=22101
3609 ~this() { impure++; }
3616 // https://issues.dlang.org/show_bug.cgi?id=22100
3619 Nullable!int a, b, c;
3621 a = b = c = nullable(5);
3625 Just like `Nullable!T`, except that the null state is defined as a
3626 particular value. For example, $(D Nullable!(uint, uint.max)) is an
3627 `uint` that sets aside the value `uint.max` to denote a null
3628 state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D
3629 Nullable!T) because it does not need to store an extra `bool`.
3632 T = The wrapped type for which Nullable provides a null value.
3634 nullValue = The null value which denotes the null state of this
3635 `Nullable`. Must be of type `T`.
3637 struct Nullable(T, T nullValue)
3639 private T _value = nullValue;
3642 Constructor initializing `this` with `value`.
3645 value = The value to initialize this `Nullable` with.
3654 import std.format.spec : FormatSpec;
3655 import std.format.write : formatValue;
3656 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
3657 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt)
3661 sink.formatValue("Nullable.null", fmt);
3665 sink.formatValue(_value, fmt);
3671 Check if `this` is in the null state.
3674 true $(B iff) `this` is in the null state, otherwise false.
3676 @property bool isNull() const
3678 //Need to use 'is' if T is a nullable type and
3679 //nullValue is null, or it's a compiler error
3680 static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null)
3682 return _value is nullValue;
3684 //Need to use 'is' if T is a float type
3685 //because NaN != NaN
3686 else static if (__traits(isFloating, T) || __traits(compiles, { static assert(!(nullValue == nullValue)); }))
3688 return _value is nullValue;
3692 return _value == nullValue;
3699 Nullable!(int, -1) ni;
3700 //Initialized to "null" state
3709 assert(typeof(this).init.isNull, typeof(this).stringof ~
3710 ".isNull does not work correctly because " ~ T.stringof ~
3711 " has an == operator that is non-reflexive and could not be" ~
3712 " determined before runtime to be non-reflexive!");
3715 // https://issues.dlang.org/show_bug.cgi?id=11135
3716 // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed
3717 version (none) @system unittest
3719 static foreach (T; AliasSeq!(float, double, real))
3721 Nullable!(T, T.init) nf;
3722 //Initialized to "null" state
3724 assert(nf is typeof(nf).init);
3735 Forces `this` to the null state.
3745 Nullable!(int, -1) ni = 0;
3753 Assigns `value` to the internally-held state. If the assignment
3754 succeeds, `this` becomes non-null. No null checks are made. Note
3755 that the assignment may leave `this` in the null state.
3758 value = A value of type `T` to assign to this `Nullable`.
3759 If it is `nullvalue`, then the internal state of
3760 this `Nullable` will be set to null.
3762 void opAssign()(T value)
3764 import std.algorithm.mutation : swap;
3766 swap(value, _value);
3770 If this `Nullable` wraps a type that already has a null value
3771 (such as a pointer), and that null value is not given for
3772 `nullValue`, then assigning the null value to this `Nullable`
3773 is no different than assigning any other value of type `T`,
3774 and the resulting code will look very strange. It is strongly
3775 recommended that this be avoided by using `T`'s "built in"
3776 null value for `nullValue`.
3781 enum nullVal = cast(int*) 0xCAFEBABE;
3782 Nullable!(int*, nullVal) npi;
3787 assert(!npi.isNull);
3791 Gets the value. `this` must not be in the null state.
3792 This function is also called for the implicit conversion to `T`.
3794 Preconditions: `isNull` must be `false`.
3796 The value held internally by this `Nullable`.
3798 @property ref inout(T) get() inout
3800 //@@@6169@@@: We avoid any call that might evaluate nullValue's %s,
3801 //Because it might messup get's purity and safety inference.
3802 enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue).";
3803 assert(!isNull, message);
3810 import std.exception : assertThrown, assertNotThrown;
3812 Nullable!(int, -1) ni;
3813 //`get` is implicitly called. Will throw
3814 //an error in non-release mode
3815 assertThrown!Throwable(ni == 0);
3818 assertNotThrown!Throwable(ni == 0);
3822 Implicitly converts to `T`.
3823 `this` must not be in the null state.
3829 auto nullable(alias nullValue, T)(T t)
3830 if (is (typeof(nullValue) == T))
3832 return Nullable!(T, nullValue)(t);
3838 Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle)
3840 //Find the needle, returning -1 if not found
3842 return Nullable!(size_t, size_t.max).init;
3845 void sendLunchInvite(string name)
3849 //It's safer than C...
3850 auto coworkers = ["Jane", "Jim", "Marry", "Fred"];
3851 auto pos = indexOf(coworkers, "Bob");
3854 //Send Bob an invitation to lunch
3855 sendLunchInvite(coworkers[pos]);
3859 //Bob not found; report the error
3862 //And there's no overhead
3863 static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof);
3869 import std.exception : assertThrown;
3871 Nullable!(int, int.min) a;
3873 assertThrown!Throwable(a.get);
3877 static assert(a.sizeof == int.sizeof);
3883 auto a = nullable!(int.min)(8);
3889 @nogc nothrow pure @safe unittest
3891 // https://issues.dlang.org/show_bug.cgi?id=19226
3892 // fully handle non-self-equal nullValue
3893 static struct Fraction
3898 return denominator == 0;
3900 bool opEquals(const Fraction rhs) const
3902 return !isNaN && denominator == rhs.denominator;
3905 alias N = Nullable!(Fraction, Fraction.init);
3906 assert(N.init.isNull);
3911 static int f(scope const Nullable!(int, int.min) x) {
3912 return x.isNull ? 42 : x.get;
3914 Nullable!(int, int.min) a;
3923 // Ensure Nullable can be used in pure/nothrow/@safe environment.
3924 function() @safe pure nothrow
3926 Nullable!(int, int.min) n;
3937 // Ensure Nullable can be used when the value is not pure/nothrow/@system
3941 bool opEquals(const S s) const @system { return s.x == x; }
3944 Nullable!(S, S(711)) s;
3954 //Check nullable is nicelly embedable in a struct
3957 Nullable!(int, 0) ni;
3959 static struct S2 //inspired from 9404
3961 Nullable!(int, 0) ni;
3966 void opAssign(S2 other)
3971 static foreach (S; AliasSeq!(S1, S2))
3981 import std.conv : to;
3983 // https://issues.dlang.org/show_bug.cgi?id=10915
3984 Nullable!(int, 1) ni = 1;
3985 assert(ni.to!string() == "Nullable.null");
3987 struct Test { string s; }
3988 alias NullableTest = Nullable!(Test, Test("null"));
3990 NullableTest nt = Test("test");
3991 assert(nt.to!string() == `Test("test")`);
3993 NullableTest ntn = Test("null");
3994 assert(ntn.to!string() == "Nullable.null");
4005 override string toString()
4007 return d.to!string();
4010 alias NullableTestToString = Nullable!(TestToString, null);
4012 NullableTestToString ntts = new TestToString(2.5);
4013 assert(ntts.to!string() == "2.5");
4018 Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull.
4020 When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`,
4021 pass it to the function you provide and wrap the result in another `Nullable` (if necessary).
4022 If the `Nullable` is null, `apply` will return null itself.
4026 fun = a function operating on the content of the nullable
4029 `fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`.
4032 $(HTTPS en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad)
4034 template apply(alias fun)
4036 import std.functional : unaryFun;
4038 auto apply(T)(auto ref T t)
4039 if (isInstanceOf!(Nullable, T) && is(typeof(unaryFun!fun(T.init.get))))
4041 alias FunType = typeof(unaryFun!fun(T.init.get));
4043 enum MustWrapReturn = !isInstanceOf!(Nullable, FunType);
4045 static if (MustWrapReturn)
4047 alias ReturnType = Nullable!FunType;
4051 alias ReturnType = FunType;
4056 static if (MustWrapReturn)
4058 return unaryFun!fun(t.get).nullable;
4062 return unaryFun!fun(t.get);
4067 return ReturnType.init;
4073 nothrow pure @nogc @safe unittest
4075 alias toFloat = i => cast(float) i;
4077 Nullable!int sample;
4079 // apply(null) results in a null `Nullable` of the function's return type.
4080 Nullable!float f = sample.apply!toFloat;
4081 assert(sample.isNull && f.isNull);
4085 // apply(non-null) calls the function and wraps the result in a `Nullable`.
4086 f = sample.apply!toFloat;
4087 assert(!sample.isNull && !f.isNull);
4088 assert(f.get == 3.0f);
4092 nothrow pure @nogc @safe unittest
4094 alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init;
4096 Nullable!int sample;
4098 // when the function already returns a `Nullable`, that `Nullable` is not wrapped.
4099 auto result = sample.apply!greaterThree;
4100 assert(sample.isNull && result.isNull);
4102 // The function may decide to return a null `Nullable`.
4104 result = sample.apply!greaterThree;
4105 assert(!sample.isNull && result.isNull);
4107 // Or it may return a value already wrapped in a `Nullable`.
4109 result = sample.apply!greaterThree;
4110 assert(!sample.isNull && !result.isNull);
4111 assert(result.get == 4);
4114 // test that Nullable.get(default) can merge types
4115 @safe @nogc nothrow pure
4118 Nullable!ubyte sample = Nullable!ubyte();
4120 // Test that get(U) returns the common type of the Nullable type and the parameter type.
4121 assert(sample.get(1000) == 1000);
4124 // Workaround for https://issues.dlang.org/show_bug.cgi?id=20670
4125 @safe @nogc nothrow pure
4128 immutable struct S { }
4130 S[] array = Nullable!(S[])().get(S[].init);
4133 // regression test for https://issues.dlang.org/show_bug.cgi?id=21199
4134 @safe @nogc nothrow pure
4138 assert(S(5).nullable.apply!"a.i" == 5);
4141 // regression test for https://issues.dlang.org/show_bug.cgi?id=22176
4142 @safe @nogc nothrow pure
4150 // Nullable shouldn't cause S to generate an
4151 // opAssign that would check the invariant.
4159 Just like `Nullable!T`, except that the object refers to a value
4160 sitting elsewhere in memory. This makes assignments overwrite the
4161 initially assigned value. Internally `NullableRef!T` only stores a
4162 pointer to `T` (i.e., $(D Nullable!T.sizeof == (T*).sizeof)).
4164 struct NullableRef(T)
4169 Constructor binding `this` to `value`.
4172 value = The value to bind to.
4174 this(T* value) @safe pure nothrow
4181 import std.format.spec : FormatSpec;
4182 import std.format.write : formatValue;
4183 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
4184 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt)
4188 sink.formatValue("Nullable.null", fmt);
4192 sink.formatValue(*_value, fmt);
4198 Binds the internal state to `value`.
4201 value = A pointer to a value of type `T` to bind this `NullableRef` to.
4203 void bind(T* value) @safe pure nothrow
4211 NullableRef!int nr = new int(42);
4214 int* n = new int(1);
4220 Returns `true` if and only if `this` is in the null state.
4223 true if `this` is in the null state, otherwise false.
4225 @property bool isNull() const @safe pure nothrow
4227 return _value is null;
4236 int* n = new int(42);
4238 assert(!nr.isNull && nr == 42);
4242 Forces `this` to the null state.
4244 void nullify() @safe pure nothrow
4252 NullableRef!int nr = new int(42);
4260 Assigns `value` to the internally-held state.
4263 value = A value of type `T` to assign to this `NullableRef`.
4264 If the internal state of this `NullableRef` has not
4265 been initialized, an error will be thrown in
4268 void opAssign()(T value)
4269 if (isAssignable!T) //@@@9416@@@
4271 enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ ".";
4272 assert(!isNull, message);
4279 import std.exception : assertThrown, assertNotThrown;
4283 assertThrown!Throwable(nr = 42);
4285 nr.bind(new int(0));
4287 assertNotThrown!Throwable(nr = 42);
4292 Gets the value. `this` must not be in the null state.
4293 This function is also called for the implicit conversion to `T`.
4295 @property ref inout(T) get() inout @safe pure nothrow
4297 enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ ".";
4298 assert(!isNull, message);
4305 import std.exception : assertThrown, assertNotThrown;
4308 //`get` is implicitly called. Will throw
4309 //an error in non-release mode
4310 assertThrown!Throwable(nr == 0);
4312 nr.bind(new int(0));
4313 assertNotThrown!Throwable(nr == 0);
4317 Implicitly converts to `T`.
4318 `this` must not be in the null state.
4324 auto nullableRef(T)(T* t)
4326 return NullableRef!T(t);
4332 import std.exception : assertThrown;
4335 auto a = nullableRef(&x);
4346 assertThrown!Throwable(a.get);
4347 assertThrown!Throwable(a = 71);
4355 static int f(scope const NullableRef!int x) {
4356 return x.isNull ? 42 : x.get;
4359 auto a = nullableRef(&x);
4366 // Ensure NullableRef can be used in pure/nothrow/@safe environment.
4367 function() @safe pure nothrow
4369 auto storage = new int;
4378 assert(*storage == 2294);
4385 // Ensure NullableRef can be used when the value is not pure/nothrow/@safe
4389 this(this) @system {}
4390 bool opEquals(const S s) const @system { return s.x == x; }
4393 auto storage = S(5);
4405 //Check nullable is nicelly embedable in a struct
4410 static struct S2 //inspired from 9404
4417 void opAssign(S2 other)
4422 static foreach (S; AliasSeq!(S1, S2))
4431 // https://issues.dlang.org/show_bug.cgi?id=10915
4434 import std.conv : to;
4436 NullableRef!int nri;
4437 assert(nri.to!string() == "Nullable.null");
4443 NullableRef!Test nt = new Test("test");
4444 assert(nt.to!string() == `Test("test")`);
4455 override string toString()
4457 return d.to!string();
4460 TestToString tts = new TestToString(2.5);
4461 NullableRef!TestToString ntts = &tts;
4462 assert(ntts.to!string() == "2.5");
4467 `BlackHole!Base` is a subclass of `Base` which automatically implements
4468 all abstract member functions in `Base` as do-nothing functions. Each
4469 auto-implemented function just returns the default value of the return type
4470 without doing anything.
4473 $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole)
4474 Perl module by Sean M. Burke.
4477 Base = A non-final class for `BlackHole` to inherit from.
4480 $(LREF AutoImplement), $(LREF generateEmptyFunction)
4482 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction);
4487 import std.math.traits : isNaN;
4489 static abstract class C
4492 this(int v) { m_value = v; }
4493 int value() @property { return m_value; }
4495 abstract real realValue() @property;
4496 abstract void doSomething();
4499 auto c = new BlackHole!C(42);
4500 assert(c.value == 42);
4502 // Returns real.init which is NaN
4503 assert(c.realValue.isNaN);
4504 // Abstract functions are implemented as do-nothing
4510 import std.math.traits : isNaN;
4514 interface I_1 { real test(); }
4515 auto o = new BlackHole!I_1;
4516 assert(o.test().isNaN()); // NaN
4523 this(int v) { m_value = v; }
4524 int value() @property { return m_value; }
4526 abstract real realValue() @property;
4527 abstract void doSomething();
4530 auto c = new BlackHole!C(42);
4531 assert(c.value == 42);
4533 assert(c.realValue.isNaN); // NaN
4537 // https://issues.dlang.org/show_bug.cgi?id=12058
4540 inout(Object) foo() inout;
4545 nothrow pure @nogc @safe unittest
4549 I foo() nothrow pure @nogc @safe return scope;
4552 scope cb = new BlackHole!I();
4558 `WhiteHole!Base` is a subclass of `Base` which automatically implements
4559 all abstract member functions as functions that always fail. These functions
4560 simply throw an `Error` and never return. `Whitehole` is useful for
4561 trapping the use of class member functions that haven't been implemented.
4564 $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole)
4565 Perl module by Michael G Schwern.
4568 Base = A non-final class for `WhiteHole` to inherit from.
4571 $(LREF AutoImplement), $(LREF generateAssertTrap)
4573 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction);
4578 import std.exception : assertThrown;
4582 abstract void notYetImplemented();
4585 auto c = new WhiteHole!C;
4586 assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error
4589 // https://issues.dlang.org/show_bug.cgi?id=20232
4590 nothrow pure @safe unittest
4594 I foo() nothrow pure @safe return scope;
4597 if (0) // Just checking attribute interference
4599 scope cw = new WhiteHole!I();
4605 class NotImplementedError : Error
4607 this(string method) nothrow pure @safe
4609 super(method ~ " is not implemented");
4615 import std.exception : assertThrown;
4623 auto o = new WhiteHole!I_1;
4624 assertThrown!NotImplementedError(o.foo());
4625 assertThrown!NotImplementedError(o.bar());
4631 abstract void notYetImplemented();
4634 auto c = new WhiteHole!C;
4637 c.notYetImplemented();
4646 `AutoImplement` automatically implements (by default) all abstract member
4647 functions in the class or interface `Base` in specified way.
4649 The second version of `AutoImplement` automatically implements
4650 `Interface`, while deriving from `BaseClass`.
4653 how = template which specifies _how functions will be implemented/overridden.
4655 Two arguments are passed to `how`: the type `Base` and an alias
4656 to an implemented function. Then `how` must return an implemented
4657 function body as a string.
4659 The generated function body can use these keywords:
4661 $(LI `a0`, `a1`, …: arguments passed to the function;)
4662 $(LI `args`: a tuple of the arguments;)
4663 $(LI `self`: an alias to the function itself;)
4664 $(LI `parent`: an alias to the overridden function (if any).)
4667 You may want to use templated property functions (instead of Implicit
4668 Template Properties) to generate complex functions:
4669 --------------------
4670 // Prints log messages for each call to overridden functions.
4671 string generateLogger(C, alias fun)() @property
4674 enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
4677 stmt ~= q{ struct Importer { import std.stdio; } };
4678 stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
4679 static if (!__traits(isAbstractFunction, fun))
4681 static if (is(ReturnType!fun == void))
4682 stmt ~= q{ parent(args); };
4685 auto r = parent(args);
4686 Importer.writeln("--> ", r);
4692 --------------------
4694 what = template which determines _what functions should be
4695 implemented/overridden.
4697 An argument is passed to `what`: an alias to a non-final member
4698 function in `Base`. Then `what` must return a boolean value.
4699 Return `true` to indicate that the passed function should be
4700 implemented/overridden.
4702 --------------------
4703 // Sees if fun returns something.
4704 enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
4705 --------------------
4710 Generated code is inserted in the scope of `std.typecons` module. Thus,
4711 any useful functions outside `std.typecons` cannot be used in the generated
4712 code. To workaround this problem, you may `import` necessary things in a
4713 local struct, as done in the `generateLogger()` template in the above
4720 $(LI Variadic arguments to constructors are not forwarded to super.)
4721 $(LI Deep interface inheritance causes compile error with messages like
4722 "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar
4723 does not override any function". [$(BUGZILLA 2525)] )
4724 $(LI The `parent` keyword is actually a delegate to the super class'
4725 corresponding member function. [$(BUGZILLA 2540)] )
4726 $(LI Using alias template parameter in `how` and/or `what` may cause
4727 strange compile error. Use template tuple parameter instead to workaround
4728 this problem. [$(BUGZILLA 4217)] )
4731 class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base
4732 if (!is(how == class))
4734 private alias autoImplement_helper_ =
4735 AutoImplement_Helper!("autoImplement_helper_", "Base", Base, typeof(this), how, what);
4736 mixin(autoImplement_helper_.code);
4740 class AutoImplement(
4741 Interface, BaseClass, alias how,
4742 alias what = isAbstractFunction) : BaseClass, Interface
4743 if (is(Interface == interface) && is(BaseClass == class))
4745 private alias autoImplement_helper_ = AutoImplement_Helper!(
4746 "autoImplement_helper_", "Interface", Interface, typeof(this), how, what);
4747 mixin(autoImplement_helper_.code);
4753 interface PackageSupplier
4759 static abstract class AbstractFallbackPackageSupplier : PackageSupplier
4761 protected PackageSupplier default_, fallback;
4763 this(PackageSupplier default_, PackageSupplier fallback)
4765 this.default_ = default_;
4766 this.fallback = fallback;
4773 template fallback(T, alias func)
4775 import std.format : format;
4776 // for all implemented methods:
4777 // - try default first
4778 // - only on a failure run & return fallback
4780 scope (failure) return fallback.%1$s(args);
4781 return default_.%1$s(args);
4782 }.format(__traits(identifier, func));
4785 // combines two classes and use the second one as fallback
4786 alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback);
4788 class FailingPackageSupplier : PackageSupplier
4790 int foo(){ throw new Exception("failure"); }
4791 int bar(){ return 2;}
4794 class BackupPackageSupplier : PackageSupplier
4796 int foo(){ return -1; }
4797 int bar(){ return -1;}
4800 auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier());
4802 assert(registry.foo() == -1);
4803 assert(registry.bar() == 2);
4807 * Code-generating stuffs are encupsulated in this helper template so that
4808 * namespace pollution, which can cause name confliction with Base's public
4809 * members, should be minimized.
4811 private template AutoImplement_Helper(string myName, string baseName,
4812 Base, Self, alias generateMethodBody, alias cherrypickMethod)
4815 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4817 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4819 // Returns function overload sets in the class C, filtered with pred.
4820 template enumerateOverloads(C, alias pred)
4822 template Impl(names...)
4824 import std.meta : Filter;
4825 static if (names.length > 0)
4827 alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0]));
4828 alias next = Impl!(names[1 .. $]);
4830 static if (methods.length > 0)
4831 alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next);
4836 alias Impl = AliasSeq!();
4839 alias enumerateOverloads = Impl!(__traits(allMembers, C));
4842 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4844 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4846 // Add a non-final check to the cherrypickMethod.
4847 enum bool canonicalPicker(fun.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) =
4848 !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun);
4851 * A tuple of overload sets, each item of which consists of functions to be
4852 * implemented by the generated code.
4854 alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker);
4857 * Super class of this AutoImplement instance
4859 alias Super = BaseTypeTuple!(Self)[0];
4860 static assert(is(Super == class));
4861 static assert(is(Base == interface) || is(Super == Base));
4864 * A tuple of the super class' constructors. Used for forwarding
4865 * constructor calls.
4867 static if (__traits(hasMember, Super, "__ctor"))
4868 alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Super, "__ctor"));
4870 alias ctorOverloadSet = OverloadSet!("__ctor"); // empty
4873 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4875 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4878 * The generated code will be mixed into AutoImplement, which will be
4879 * instantiated in this module's scope. Thus, any user-defined types are
4880 * out of scope and cannot be used directly (i.e. by their names).
4882 * We will use FuncInfo instances for accessing return types and parameter
4883 * types of the implemented functions. The instances will be populated to
4884 * the AutoImplement's scope in a certain way; see the populate() below.
4887 // Returns the preferred identifier for the FuncInfo instance for the i-th
4888 // overloaded function with the name.
4889 template INTERNAL_FUNCINFO_ID(string name, size_t i)
4891 import std.format : format;
4893 enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i);
4897 * Insert FuncInfo instances about all the target functions here. This
4898 * enables the generated code to access type information via, for example,
4899 * "autoImplement_helper_.F_foo_1".
4901 template populate(overloads...)
4903 static if (overloads.length > 0)
4905 mixin populate!(overloads[0].name, overloads[0].contents);
4906 mixin populate!(overloads[1 .. $]);
4909 template populate(string name, methods...)
4911 static if (methods.length > 0)
4913 mixin populate!(name, methods[0 .. $ - 1]);
4915 alias target = methods[$ - 1];
4916 enum ith = methods.length - 1;
4917 mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;");
4921 public mixin populate!(targetOverloadSets);
4922 public mixin populate!( ctorOverloadSet );
4925 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4926 // Code-generating policies
4927 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4929 /* Common policy configurations for generating constructors and methods. */
4930 template CommonGeneratingPolicy()
4932 // base class identifier which generated code should use
4933 enum string BASE_CLASS_ID = baseName;
4935 // FuncInfo instance identifier which generated code should use
4936 template FUNCINFO_ID(string name, size_t i)
4938 enum string FUNCINFO_ID =
4939 myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i);
4943 /* Policy configurations for generating constructors. */
4944 template ConstructorGeneratingPolicy()
4946 mixin CommonGeneratingPolicy;
4948 /* Generates constructor body. Just forward to the base class' one. */
4949 string generateFunctionBody(ctor.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
4951 enum varstyle = variadicFunctionStyle!(typeof(&ctor[0]));
4953 static if (varstyle & (Variadic.c | Variadic.d))
4955 // the argptr-forwarding problem
4956 //pragma(msg, "Warning: AutoImplement!(", Base, ") ",
4957 // "ignored variadic arguments to the constructor ",
4958 // FunctionTypeOf!(typeof(&ctor[0])) );
4960 return "super(args);";
4964 /* Policy configurations for genearting target methods. */
4965 template MethodGeneratingPolicy()
4967 mixin CommonGeneratingPolicy;
4969 /* Geneartes method body. */
4970 string generateFunctionBody(func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
4972 return generateMethodBody!(Base, func); // given
4977 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4979 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4981 alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!());
4982 alias MethodGenerator = MemberFunctionGenerator!(MethodGeneratingPolicy!());
4984 public enum string code =
4985 ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~
4986 MethodGenerator.generateCode!(targetOverloadSets);
4988 debug (SHOW_GENERATED_CODE)
4990 pragma(msg, "-------------------- < ", Base, " >");
4992 pragma(msg, "--------------------");
4996 //debug = SHOW_GENERATED_CODE;
5000 // no function to implement
5003 auto o = new BlackHole!I_1;
5007 interface I_3 { void test(int, in int, out int, ref int, lazy int); }
5008 auto o = new BlackHole!I_3;
5010 // use of user-defined type
5013 interface I_4 { S test(); }
5014 auto o = new BlackHole!I_4;
5024 auto o = new BlackHole!I_5;
5026 // constructor forwarding
5030 this(int n) { assert(n == 42); }
5031 this(string s) { assert(s == "Deeee"); }
5034 auto o1 = new BlackHole!C_6(42);
5035 auto o2 = new BlackHole!C_6("Deeee");
5036 auto o3 = new BlackHole!C_6(1, 2, 3, 4);
5043 int test_pure() pure;
5044 int test_nothrow() nothrow;
5045 int test_property() @property;
5046 int test_safe() @safe;
5047 int test_trusted() @trusted;
5048 int test_system() @system;
5049 int test_pure_nothrow() pure nothrow;
5051 auto o = new BlackHole!I_7;
5057 void test_const() const;
5058 void test_immutable() immutable;
5059 void test_shared() shared;
5060 void test_shared_const() shared const;
5062 auto o = new BlackHole!I_8;
5068 private string foo_;
5074 protected string boilerplate() @property
5076 return "Boilerplate stuff.";
5079 public string foo() @property
5087 string testMethod(size_t);
5090 static string generateTestMethod(C, alias fun)() @property
5092 return "return this.boilerplate[0 .. a0];";
5095 auto o = new AutoImplement!(I_10, C_9, generateTestMethod)("Testing");
5096 assert(o.testMethod(11) == "Boilerplate");
5097 assert(o.foo == "Testing");
5099 /+ // deep inheritance
5101 // https://issues.dlang.org/show_bug.cgi?id=2525
5102 // https://issues.dlang.org/show_bug.cgi?id=3525
5103 // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic()
5104 interface I { void foo(); }
5107 static abstract class C_9 : K {}
5108 auto o = new BlackHole!C_9;
5112 // https://issues.dlang.org/show_bug.cgi?id=17177
5113 // AutoImplement fails on function overload sets with
5114 // "cannot infer type from overloaded function symbol"
5117 static class Issue17177
5122 Issue17177 overloaded(string n)
5136 static string how(C, alias fun)()
5138 static if (!is(ReturnType!fun == void))
5141 return parent(args);
5152 import std.meta : templateNot;
5153 alias Implementation = AutoImplement!(Issue17177, how, templateNot!isFinalFunction);
5156 version (StdUnittest)
5158 // https://issues.dlang.org/show_bug.cgi?id=10647
5159 // Add prefix "issue10647_" as a workaround for
5160 // https://issues.dlang.org/show_bug.cgi?id=1238
5161 private string issue10647_generateDoNothing(C, alias fun)() @property
5165 static if (is(ReturnType!fun == void))
5169 string returnType = ReturnType!fun.stringof;
5170 stmt ~= "return "~returnType~".init;";
5175 private template issue10647_isAlwaysTrue(alias fun)
5177 enum issue10647_isAlwaysTrue = true;
5180 // Do nothing template
5181 private template issue10647_DoNothing(Base)
5183 alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue);
5186 // A class to be overridden
5187 private class issue10647_Foo{
5193 auto foo = new issue10647_DoNothing!issue10647_Foo();
5198 Used by MemberFunctionGenerator.
5200 package template OverloadSet(string nam, T...)
5202 enum string name = nam;
5207 Used by MemberFunctionGenerator.
5209 package template FuncInfo(alias func)
5210 if (is(typeof(&func)))
5212 alias RT = ReturnType!(typeof(&func));
5213 alias PT = Parameters!(typeof(&func));
5215 package template FuncInfo(Func)
5217 alias RT = ReturnType!Func;
5218 alias PT = Parameters!Func;
5222 General-purpose member function generator.
5223 --------------------
5224 template GeneratingPolicy()
5226 // [optional] the name of the class where functions are derived
5227 enum string BASE_CLASS_ID;
5229 // [optional] define this if you have only function types
5230 enum bool WITHOUT_SYMBOL;
5232 // [optional] Returns preferred identifier for i-th parameter.
5233 template PARAMETER_VARIABLE_ID(size_t i);
5235 // Returns the identifier of the FuncInfo instance for the i-th overload
5236 // of the specified name. The identifier must be accessible in the scope
5237 // where generated code is mixed.
5238 template FUNCINFO_ID(string name, size_t i);
5240 // Returns implemented function body as a string. When WITHOUT_SYMBOL is
5241 // defined, the latter is used.
5242 template generateFunctionBody(alias func);
5243 template generateFunctionBody(string name, FuncType);
5245 --------------------
5247 package template MemberFunctionGenerator(alias Policy)
5250 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5252 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5254 alias format = std.format.format;
5256 enum CONSTRUCTOR_NAME = "__ctor";
5258 // true if functions are derived from a base class
5259 enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID");
5261 // true if functions are specified as types, not symbols
5262 enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL");
5264 // preferred identifier for i-th parameter variable
5265 static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID"))
5267 alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID;
5271 enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i);
5272 // default: a0, a1, ...
5275 // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach.
5276 template CountUp(size_t n)
5279 alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1);
5281 alias CountUp = AliasSeq!();
5285 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5287 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5290 * Runs through all the target overload sets and generates D code which
5291 * implements all the functions in the overload sets.
5293 public string generateCode(overloads...)() @property
5297 // run through all the overload sets
5298 foreach (i_; CountUp!(0 + overloads.length)) // workaround
5300 enum i = 0 + i_; // workaround
5301 alias oset = overloads[i];
5303 code ~= generateCodeForOverloadSet!(oset);
5305 static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME)
5307 // The generated function declarations may hide existing ones
5308 // in the base class (cf. HiddenFuncError), so we put an alias
5309 // declaration here to reveal possible hidden functions.
5310 code ~= format("alias %s = %s.%s;\n",
5312 // super: https://issues.dlang.org/show_bug.cgi?id=2540
5313 Policy.BASE_CLASS_ID,
5320 // handle each overload set
5321 private string generateCodeForOverloadSet(alias oset)() @property
5325 foreach (i_; CountUp!(0 + oset.contents.length)) // workaround
5327 enum i = 0 + i_; // workaround
5328 code ~= generateFunction!(
5329 Policy.FUNCINFO_ID!(oset.name, i), oset.name,
5330 oset.contents[i]) ~ "\n";
5336 * Returns D code which implements the function func. This function
5337 * actually generates only the declarator part; the function body part is
5338 * generated by the functionGenerator() policy.
5340 public string generateFunction(
5341 string myFuncInfo, string name, func... )() @property
5343 import std.format : format;
5345 enum isCtor = (name == CONSTRUCTOR_NAME);
5347 string code; // the result
5349 auto paramsRes = generateParameters!(myFuncInfo, func)();
5350 code ~= paramsRes.imports;
5352 /*** Function Declarator ***/
5354 alias Func = FunctionTypeOf!(func);
5355 alias FA = FunctionAttribute;
5356 enum atts = functionAttributes!(func);
5357 enum realName = isCtor ? "this" : name;
5359 // FIXME?? Make it so that these aren't CTFE funcs any more, since
5360 // Format is deprecated, and format works at compile time?
5361 /* Made them CTFE funcs just for the sake of Format!(...) */
5363 // return type with optional "ref"
5364 static string make_returnType()
5370 if (atts & FA.ref_) rtype ~= "ref ";
5371 rtype ~= myFuncInfo ~ ".RT";
5375 enum returnType = make_returnType();
5377 // function attributes attached after declaration
5378 static string make_postAtts()
5381 if (atts & FA.pure_ ) poatts ~= " pure";
5382 if (atts & FA.nothrow_) poatts ~= " nothrow";
5383 if (atts & FA.property) poatts ~= " @property";
5384 if (atts & FA.safe ) poatts ~= " @safe";
5385 if (atts & FA.trusted ) poatts ~= " @trusted";
5386 if (atts & FA.scope_ ) poatts ~= " scope";
5387 if (atts & FA.return_ ) poatts ~= " return";
5390 enum postAtts = make_postAtts();
5392 // function storage class
5393 static string make_storageClass()
5396 if (is(Func == shared)) postc ~= " shared";
5397 if (is(Func == const)) postc ~= " const";
5398 if (is(Func == inout)) postc ~= " inout";
5399 if (is(Func == immutable)) postc ~= " immutable";
5402 enum storageClass = make_storageClass();
5405 if (__traits(isVirtualMethod, func))
5406 code ~= "override ";
5407 code ~= format("extern(%s) %s %s(%s) %s %s\n",
5408 functionLinkage!(func),
5412 postAtts, storageClass );
5415 /*** Function Body ***/
5418 enum nparams = Parameters!(func).length;
5420 /* Declare keywords: args, self and parent. */
5423 preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n";
5426 preamble ~= "alias self = " ~ name ~ ";\n";
5427 if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func))
5428 preamble ~= `alias parent = __traits(getMember, super, "` ~ name ~ `");`;
5432 static if (WITHOUT_SYMBOL)
5433 enum fbody = Policy.generateFunctionBody!(name, func);
5435 enum fbody = Policy.generateFunctionBody!(func);
5446 * Returns D code which declares function parameters,
5447 * and optionally any imports (e.g. core.vararg)
5448 * "ref int a0, real a1, ..."
5450 static struct GenParams { string imports, params; }
5451 private GenParams generateParameters(string myFuncInfo, func...)()
5453 alias STC = ParameterStorageClass;
5454 alias stcs = ParameterStorageClassTuple!(func);
5455 enum nparams = stcs.length;
5457 string imports = ""; // any imports required
5458 string params = ""; // parameters
5460 foreach (i, stc; stcs)
5462 if (i > 0) params ~= ", ";
5464 // Parameter storage classes.
5465 if (stc & STC.scope_) params ~= "scope ";
5466 if (stc & STC.in_) params ~= "in ";
5467 if (stc & STC.out_ ) params ~= "out ";
5468 if (stc & STC.ref_ ) params ~= "ref ";
5469 if (stc & STC.lazy_ ) params ~= "lazy ";
5471 // Take parameter type from the FuncInfo.
5472 params ~= format("%s.PT[%s]", myFuncInfo, i);
5474 // Declare a parameter variable.
5475 params ~= " " ~ PARAMETER_VARIABLE_ID!(i);
5478 // Add some ellipsis part if needed.
5479 auto style = variadicFunctionStyle!(func);
5480 final switch (style)
5485 case Variadic.c, Variadic.d:
5486 imports ~= "import core.vararg;\n";
5487 // (...) or (a, b, ...)
5488 params ~= (nparams == 0) ? "..." : ", ...";
5491 case Variadic.typesafe:
5496 return typeof(return)(imports, params);
5499 // Returns D code which enumerates n parameter variables using comma as the
5500 // separator. "a0, a1, a2, a3"
5501 private string enumerateParameters(size_t n)() @property
5505 foreach (i_; CountUp!(n))
5507 enum i = 0 + i_; // workaround
5508 if (i > 0) params ~= ", ";
5509 params ~= PARAMETER_VARIABLE_ID!(i);
5517 Predefined how-policies for `AutoImplement`. These templates are also used by
5518 `BlackHole` and `WhiteHole`, respectively.
5520 template generateEmptyFunction(C, func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)
5522 static if (is(ReturnType!(func) == void))
5523 enum string generateEmptyFunction = q{
5525 else static if (functionAttributes!(func) & FunctionAttribute.ref_)
5526 enum string generateEmptyFunction = q{
5527 static typeof(return) dummy;
5531 enum string generateEmptyFunction = q{
5532 return typeof(return).init;
5539 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction);
5547 auto i = new BlackHole!I();
5548 // generateEmptyFunction returns the default value of the return type without doing anything
5550 assert(i.bar is null);
5554 template generateAssertTrap(C, func...)
5556 enum string generateAssertTrap =
5557 `throw new NotImplementedError("` ~ C.stringof ~ "."
5558 ~ __traits(identifier, func) ~ `");`;
5564 import std.exception : assertThrown;
5566 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap);
5574 auto i = new WhiteHole!I();
5575 // generateAssertTrap throws an exception for every unimplemented function of the interface
5576 assertThrown!NotImplementedError(i.foo);
5577 assertThrown!NotImplementedError(i.bar);
5582 pragma(mangle, "_d_toObject")
5583 extern(C) pure nothrow Object typecons_d_toObject(void* p);
5587 * Avoids opCast operator overloading.
5589 private template dynamicCast(T)
5590 if (is(T == class) || is(T == interface))
5593 T dynamicCast(S)(inout S source)
5594 if (is(S == class) || is(S == interface))
5596 static if (is(Unqual!S : Unqual!T))
5598 import std.traits : QualifierOf;
5599 alias Qual = QualifierOf!S; // SharedOf or MutableOf
5600 alias TmpT = Qual!(Unqual!T);
5601 inout(TmpT) tmp = source; // bypass opCast by implicit conversion
5602 return *cast(T*)(&tmp); // + variable pointer cast + dereference
5606 return cast(T) typecons_d_toObject(*cast(void**)(&source));
5613 class C { @disable void opCast(T)(); }
5615 static assert(!__traits(compiles, cast(Object) c));
5616 auto o = dynamicCast!Object(c);
5619 interface I { @disable void opCast(T)(); Object instance(); }
5620 interface J { @disable void opCast(T)(); Object instance(); }
5621 class D : I, J { Object instance() { return this; } }
5623 static assert(!__traits(compiles, cast(J) i));
5624 J j = dynamicCast!J(i);
5625 assert(i.instance() is j.instance());
5629 Supports structural based typesafe conversion.
5631 If `Source` has structural conformance with the `interface` `Targets`,
5632 wrap creates an internal wrapper class which inherits `Targets` and
5633 wraps the `src` object, then returns it.
5635 `unwrap` can be used to extract objects which have been wrapped by `wrap`.
5637 template wrap(Targets...)
5638 if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
5640 import std.meta : staticMap;
5643 auto wrap(Source)(inout Source src) @trusted pure nothrow
5644 if (Targets.length == 1 && is(Source : Targets[0]))
5646 alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]);
5647 return dynamicCast!(inout T)(src);
5649 // structural upcast
5650 template wrap(Source)
5651 if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets))
5653 auto wrap(inout Source src)
5655 static assert(hasRequireMethods!(),
5656 "Source "~Source.stringof~
5657 " does not have structural conformance to "~
5660 alias T = Select!(is(Source == shared), shared Impl, Impl);
5661 return new inout T(src);
5664 template FuncInfo(string s, F)
5670 // https://issues.dlang.org/show_bug.cgi?id=12064: Remove NVI members
5671 template OnlyVirtual(members...)
5673 enum notFinal(alias T) = !__traits(isFinalFunction, T);
5674 import std.meta : Filter;
5675 alias OnlyVirtual = Filter!(notFinal, members);
5678 // Concat all Targets function members into one tuple
5679 template Concat(size_t i = 0)
5681 static if (i >= Targets.length)
5682 alias Concat = AliasSeq!();
5685 alias Concat = AliasSeq!(OnlyVirtual!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1)));
5689 // Remove duplicated functions based on the identifier name and function type covariance
5690 template Uniq(members...)
5692 static if (members.length == 0)
5693 alias Uniq = AliasSeq!();
5696 alias func = members[0];
5697 enum name = __traits(identifier, func);
5698 alias type = FunctionTypeOf!func;
5699 template check(size_t i, mem...)
5701 static if (i >= mem.length)
5702 enum ptrdiff_t check = -1;
5705 enum ptrdiff_t check =
5706 __traits(identifier, func) == __traits(identifier, mem[i]) &&
5707 !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void)
5708 ? i : check!(i + 1, mem);
5711 enum ptrdiff_t x = 1 + check!(0, members[1 .. $]);
5714 alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x]));
5715 alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]);
5717 static if (remain.length >= 1 && remain[0].name == name &&
5718 !is(DerivedFunctionType!(typex, remain[0].type) == void))
5720 alias F = DerivedFunctionType!(typex, remain[0].type);
5721 alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]);
5724 alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain);
5728 alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $]));
5732 alias TargetMembers = Uniq!(Concat!()); // list of FuncInfo
5733 alias SourceMembers = GetOverloadedMethods!Source; // list of function symbols
5735 // Check whether all of SourceMembers satisfy covariance target in TargetMembers
5736 template hasRequireMethods(size_t i = 0)
5738 static if (i >= TargetMembers.length)
5739 enum hasRequireMethods = true;
5742 enum hasRequireMethods =
5743 findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 &&
5744 hasRequireMethods!(i + 1);
5748 // Internal wrapper class
5749 final class Impl : Structural, Targets
5752 Source _wrap_source;
5754 this( inout Source s) inout @safe pure nothrow { _wrap_source = s; }
5755 this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; }
5757 // BUG: making private should work with NVI.
5758 protected final inout(Object) _wrap_getSource() inout @trusted
5760 return dynamicCast!(inout Object)(_wrap_source);
5763 import std.conv : to;
5764 import core.lifetime : forward;
5765 template generateFun(size_t i)
5767 enum name = TargetMembers[i].name;
5768 enum fa = functionAttributes!(TargetMembers[i].type);
5769 static @property stc()
5772 if (fa & FunctionAttribute.property) r ~= "@property ";
5773 if (fa & FunctionAttribute.ref_) r ~= "ref ";
5774 if (fa & FunctionAttribute.pure_) r ~= "pure ";
5775 if (fa & FunctionAttribute.nothrow_) r ~= "nothrow ";
5776 if (fa & FunctionAttribute.trusted) r ~= "@trusted ";
5777 if (fa & FunctionAttribute.safe) r ~= "@safe ";
5780 static @property mod()
5782 alias type = AliasSeq!(TargetMembers[i].type)[0];
5784 static if (is(type == immutable)) r ~= " immutable";
5787 static if (is(type == shared)) r ~= " shared";
5788 static if (is(type == const)) r ~= " const";
5789 else static if (is(type == inout)) r ~= " inout";
5794 enum n = to!string(i);
5795 static if (fa & FunctionAttribute.property)
5797 static if (Parameters!(TargetMembers[i].type).length == 0)
5798 enum fbody = "_wrap_source."~name;
5800 enum fbody = "_wrap_source."~name~" = forward!args";
5804 enum fbody = "_wrap_source."~name~"(forward!args)";
5807 "override "~stc~"ReturnType!(TargetMembers["~n~"].type) "
5808 ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~
5809 "{ return "~fbody~"; }";
5813 static foreach (i; 0 .. TargetMembers.length)
5814 mixin(generateFun!i);
5819 template wrap(Targets...)
5820 if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets))
5822 import std.meta : staticMap;
5824 alias wrap = .wrap!(staticMap!(Unqual, Targets));
5828 template unwrap(Target)
5829 if (isMutable!Target)
5832 auto unwrap(Source)(inout Source src) @trusted pure nothrow
5833 if (is(Target : Source))
5835 alias T = Select!(is(Source == shared), shared Target, Target);
5836 return dynamicCast!(inout T)(src);
5838 // structural downcast
5839 auto unwrap(Source)(inout Source src) @trusted pure nothrow
5840 if (!is(Target : Source))
5842 alias T = Select!(is(Source == shared), shared Target, Target);
5843 Object o = dynamicCast!(Object)(src); // remove qualifier
5846 if (auto a = dynamicCast!(Structural)(o))
5848 if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource()))
5851 else if (auto d = dynamicCast!(inout T)(o))
5861 template unwrap(Target)
5862 if (!isMutable!Target)
5864 alias unwrap = .unwrap!(Unqual!Target);
5873 @property int height();
5877 @property int height();
5881 int quack() { return 1; }
5882 @property int height() { return 10; }
5886 int quack() { return 2; }
5887 @property int height() { return 20; }
5890 Duck d1 = new Duck();
5891 Human h1 = new Human();
5893 interface Refleshable
5898 // does not have structural conformance
5899 static assert(!__traits(compiles, d1.wrap!Refleshable));
5900 static assert(!__traits(compiles, h1.wrap!Refleshable));
5903 Quack qd = d1.wrap!Quack;
5905 assert(qd.quack() == 1); // calls Duck.quack
5907 Duck d2 = qd.unwrap!Duck;
5910 // structural upcast
5911 Quack qh = h1.wrap!Quack;
5912 assert(qh.quack() == 2); // calls Human.quack
5913 // structural downcast
5914 Human h2 = qh.unwrap!Human;
5917 // structural upcast (two steps)
5918 Quack qx = h1.wrap!Quack; // Human -> Quack
5919 Flyer fx = qx.wrap!Flyer; // Quack -> Flyer
5920 assert(fx.height == 20); // calls Human.height
5921 // structural downcast (two steps)
5922 Quack qy = fx.unwrap!Quack; // Flyer -> Quack
5923 Human hy = qy.unwrap!Human; // Quack -> Human
5925 // structural downcast (one step)
5926 Human hz = fx.unwrap!Human; // Flyer -> Human
5933 import std.traits : FunctionAttribute, functionAttributes;
5934 interface A { int run(); }
5935 interface B { int stop(); @property int status(); }
5938 int run() { return 1; }
5939 int stop() { return 2; }
5940 @property int status() { return 3; }
5944 auto ab = x.wrap!(A, B);
5947 assert(a.run() == 1);
5948 assert(b.stop() == 2);
5949 assert(b.status == 3);
5950 static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
5953 // Internal class to support dynamic cross-casting
5954 private interface Structural
5956 inout(Object) _wrap_getSource() inout @safe pure nothrow;
5963 int draw() { return 1; }
5964 int draw(int v) { return v; }
5966 int draw() const { return 2; }
5967 int draw() shared { return 3; }
5968 int draw() shared const { return 4; }
5969 int draw() immutable { return 5; }
5976 int draw() shared const;
5977 int draw() immutable;
5985 auto sa = new shared A();
5986 auto ia = new immutable A();
5988 Drawable md = ma.wrap!Drawable;
5989 const Drawable cd = ma.wrap!Drawable;
5990 shared Drawable sd = sa.wrap!Drawable;
5991 shared const Drawable scd = sa.wrap!Drawable;
5992 immutable Drawable id = ia.wrap!Drawable;
5993 assert( md.draw() == 1);
5994 assert( cd.draw() == 2);
5995 assert( sd.draw() == 3);
5996 assert(scd.draw() == 4);
5997 assert( id.draw() == 5);
6000 Drawable2 d = ma.wrap!Drawable2;
6001 static assert(!__traits(compiles, d.draw()));
6002 assert(d.draw(10) == 10);
6006 // https://issues.dlang.org/show_bug.cgi?id=10377
6009 import std.range, std.algorithm;
6011 interface MyInputRange(T)
6013 @property T front();
6015 @property bool empty();
6018 //auto o = iota(0,10,1).inputRangeObject();
6019 //pragma(msg, __traits(allMembers, typeof(o)));
6020 auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)();
6021 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6024 // https://issues.dlang.org/show_bug.cgi?id=10536
6033 int foo() { return 1; }
6034 @disable void opCast(T, this X)(); // !
6037 Interface i = new Pluggable().wrap!Interface;
6038 assert(i.foo() == 1);
6042 // Enhancement 10538
6050 int opDispatch(string name, A...)(A args) { return 100; }
6053 Interface i = wrap!Interface(new Pluggable());
6054 assert(i.foo() == 100);
6055 assert(i.bar(10) == 100);
6058 // https://issues.dlang.org/show_bug.cgi?id=12064
6064 final int nvi1(){return foo();}
6070 final int nvi2(){return bar();}
6075 int foo() { return 42;}
6076 int bar() { return 12064;}
6079 auto baz = new Baz();
6080 auto foobar = baz.wrap!(I, J)();
6081 assert(foobar.nvi1 == 42);
6082 assert(foobar.nvi2 == 12064);
6085 // Make a tuple of non-static function symbols
6086 package template GetOverloadedMethods(T)
6088 import std.meta : Filter;
6090 alias allMembers = __traits(allMembers, T);
6091 template follows(size_t i = 0)
6093 static if (i >= allMembers.length)
6095 alias follows = AliasSeq!();
6097 else static if (!__traits(compiles, mixin("T."~allMembers[i])))
6099 alias follows = follows!(i + 1);
6103 enum name = allMembers[i];
6105 template isMethod(alias f)
6107 static if (is(typeof(&f) F == F*) && is(F == function))
6108 enum isMethod = !__traits(isStaticFunction, f);
6110 enum isMethod = false;
6112 alias follows = AliasSeq!(
6113 Filter!(isMethod, __traits(getOverloads, T, name)),
6117 alias GetOverloadedMethods = follows!();
6119 // find a function from Fs that has same identifier and covariant type with f
6120 private template findCovariantFunction(alias finfo, Source, Fs...)
6122 template check(size_t i = 0)
6124 static if (i >= Fs.length)
6125 enum ptrdiff_t check = -1;
6128 enum ptrdiff_t check =
6129 (finfo.name == __traits(identifier, Fs[i])) &&
6130 isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type)
6131 ? i : check!(i + 1);
6135 static if (x == -1 && is(typeof(Source.opDispatch)))
6137 alias Params = Parameters!(finfo.type);
6138 enum ptrdiff_t findCovariantFunction =
6139 is(typeof(( Source).init.opDispatch!(finfo.name)(Params.init))) ||
6140 is(typeof(( const Source).init.opDispatch!(finfo.name)(Params.init))) ||
6141 is(typeof(( immutable Source).init.opDispatch!(finfo.name)(Params.init))) ||
6142 is(typeof(( shared Source).init.opDispatch!(finfo.name)(Params.init))) ||
6143 is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init)))
6144 ? ptrdiff_t.max : -1;
6147 enum ptrdiff_t findCovariantFunction = x;
6150 private enum TypeModifier
6152 mutable = 0, // type is mutable
6153 const_ = 1, // type is const
6154 immutable_ = 2, // type is immutable
6155 shared_ = 4, // type is shared
6156 inout_ = 8, // type is wild
6158 private template TypeMod(T)
6160 static if (is(T == immutable))
6162 enum mod1 = TypeModifier.immutable_;
6167 enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0;
6168 static if (is(T == const))
6169 enum mod2 = TypeModifier.const_;
6170 else static if (is(T == inout))
6171 enum mod2 = TypeModifier.inout_;
6173 enum mod2 = TypeModifier.mutable;
6175 enum TypeMod = cast(TypeModifier)(mod1 | mod2);
6180 template UnittestFuncInfo(alias f)
6182 enum name = __traits(identifier, f);
6183 alias type = FunctionTypeOf!f;
6188 int draw() { return 1; }
6189 @property int value() { return 2; }
6190 final int run() { return 3; }
6192 alias methods = GetOverloadedMethods!A;
6195 alias @property int F2();
6197 alias nothrow @trusted uint F4();
6198 alias int F5(Object);
6199 alias bool F6(Object);
6200 static assert(methods.length == 3 + 4);
6201 static assert(__traits(identifier, methods[0]) == "draw" && is(typeof(&methods[0]) == F1*));
6202 static assert(__traits(identifier, methods[1]) == "value" && is(typeof(&methods[1]) == F2*));
6203 static assert(__traits(identifier, methods[2]) == "run" && is(typeof(&methods[2]) == F1*));
6206 @property int value();
6209 static assert(findCovariantFunction!(UnittestFuncInfo!draw, A, methods) == 0);
6210 static assert(findCovariantFunction!(UnittestFuncInfo!value, A, methods) == 1);
6211 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1);
6212 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, A, methods) == -1);
6214 // considering opDispatch
6217 void opDispatch(string name, A...)(A) {}
6219 alias methodsB = GetOverloadedMethods!B;
6220 static assert(findCovariantFunction!(UnittestFuncInfo!draw, B, methodsB) == ptrdiff_t.max);
6221 static assert(findCovariantFunction!(UnittestFuncInfo!value, B, methodsB) == ptrdiff_t.max);
6222 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max);
6223 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, B, methodsB) == ptrdiff_t.max);
6226 package template DerivedFunctionType(T...)
6228 static if (!T.length)
6230 alias DerivedFunctionType = void;
6232 else static if (T.length == 1)
6234 static if (is(T[0] == function))
6236 alias DerivedFunctionType = T[0];
6240 alias DerivedFunctionType = void;
6243 else static if (is(T[0] P0 == function) && is(T[1] P1 == function))
6245 alias FA = FunctionAttribute;
6247 alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0;
6248 alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1;
6249 enum FA0 = functionAttributes!F0;
6250 enum FA1 = functionAttributes!F1;
6252 template CheckParams(size_t i = 0)
6254 static if (i >= P0.length)
6255 enum CheckParams = true;
6258 enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) &&
6259 CheckParams!(i + 1);
6262 static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) &&
6263 P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 &&
6264 variadicFunctionStyle!F0 == variadicFunctionStyle!F1 &&
6265 functionLinkage!F0 == functionLinkage!F1 &&
6266 ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0)
6268 alias R = Select!(is(R0 : R1), R0, R1);
6269 alias FX = FunctionTypeOf!(R function(P0));
6270 // @system is default
6271 alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system);
6272 alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]);
6275 alias DerivedFunctionType = void;
6278 alias DerivedFunctionType = void;
6282 // attribute covariance
6284 static assert(is(DerivedFunctionType!(F1, F1) == F1));
6285 alias int F2() pure nothrow;
6286 static assert(is(DerivedFunctionType!(F1, F2) == F2));
6287 alias int F3() @safe;
6288 alias int F23() @safe pure nothrow;
6289 static assert(is(DerivedFunctionType!(F2, F3) == F23));
6291 // return type covariance
6293 static assert(is(DerivedFunctionType!(F1, F4) == void));
6298 static assert(is(DerivedFunctionType!(F5, F6) == F6));
6299 alias typeof(null) F7();
6302 static assert(is(DerivedFunctionType!(F5, F7) == F7));
6303 static assert(is(DerivedFunctionType!(F7, F8) == void));
6304 static assert(is(DerivedFunctionType!(F7, F9) == F7));
6306 // variadic type equality
6308 alias int F11(int...);
6309 alias int F12(int, ...);
6310 static assert(is(DerivedFunctionType!(F10, F11) == void));
6311 static assert(is(DerivedFunctionType!(F10, F12) == void));
6312 static assert(is(DerivedFunctionType!(F11, F12) == void));
6315 alias extern(C) int F13(int);
6316 alias extern(D) int F14(int);
6317 alias extern(Windows) int F15(int);
6318 static assert(is(DerivedFunctionType!(F13, F14) == void));
6319 static assert(is(DerivedFunctionType!(F13, F15) == void));
6320 static assert(is(DerivedFunctionType!(F14, F15) == void));
6322 // ref & @property equality
6324 alias ref int F17(int);
6325 alias @property int F18(int);
6326 static assert(is(DerivedFunctionType!(F16, F17) == void));
6327 static assert(is(DerivedFunctionType!(F16, F18) == void));
6328 static assert(is(DerivedFunctionType!(F17, F18) == void));
6331 package template Bind(alias Template, args1...)
6333 alias Bind(args2...) = Template!(args1, args2);
6338 Options regarding auto-initialization of a `RefCounted` object (see
6339 the definition of `RefCounted` below).
6341 enum RefCountedAutoInitialize
6343 /// Do not auto-initialize the object
6345 /// Auto-initialize the object
6352 import core.exception : AssertError;
6353 import std.exception : assertThrown;
6360 RefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto;
6361 RefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto;
6363 assert(rcAuto.refCountedPayload.a == 42);
6365 assertThrown!AssertError(rcNoAuto.refCountedPayload);
6366 rcNoAuto.refCountedStore.ensureInitialized;
6367 assert(rcNoAuto.refCountedPayload.a == 42);
6371 Defines a reference-counted object containing a `T` value as
6374 An instance of `RefCounted` is a reference to a structure,
6375 which is referred to as the $(I store), or $(I storage implementation
6376 struct) in this documentation. The store contains a reference count
6377 and the `T` payload. `RefCounted` uses `malloc` to allocate
6378 the store. As instances of `RefCounted` are copied or go out of
6379 scope, they will automatically increment or decrement the reference
6380 count. When the reference count goes down to zero, `RefCounted`
6381 will call `destroy` against the payload and call `free` to
6382 deallocate the store. If the `T` payload contains any references
6383 to GC-allocated memory, then `RefCounted` will add it to the GC memory
6384 that is scanned for pointers, and remove it from GC scanning before
6385 `free` is called on the store.
6387 One important consequence of `destroy` is that it will call the
6388 destructor of the `T` payload. GC-managed references are not
6389 guaranteed to be valid during a destructor call, but other members of
6390 `T`, such as file handles or pointers to `malloc` memory, will
6391 still be valid during the destructor call. This allows the `T` to
6392 deallocate or clean up any non-GC resources immediately after the
6393 reference count has reached zero.
6395 `RefCounted` is unsafe and should be used with care. No references
6396 to the payload should be escaped outside the `RefCounted` object.
6398 The `autoInit` option makes the object ensure the store is
6399 automatically initialized. Leaving $(D autoInit ==
6400 RefCountedAutoInitialize.yes) (the default option) is convenient but
6401 has the cost of a test whenever the payload is accessed. If $(D
6402 autoInit == RefCountedAutoInitialize.no), user code must call either
6403 `refCountedStore.isInitialized` or `refCountedStore.ensureInitialized`
6404 before attempting to access the payload. Not doing so results in null
6405 pointer dereference.
6407 If `T.this()` is annotated with `@disable` then `autoInit` must be
6408 `RefCountedAutoInitialize.no` in order to compile.
6410 struct RefCounted(T, RefCountedAutoInitialize autoInit =
6411 RefCountedAutoInitialize.yes)
6412 if (!is(T == class) && !(is(T == interface)))
6416 private enum enableGCScan = false;
6420 private enum enableGCScan = hasIndirections!T;
6423 // TODO remove pure when https://issues.dlang.org/show_bug.cgi?id=15862 has been fixed
6424 extern(C) private pure nothrow @nogc static
6426 pragma(mangle, "free") void pureFree( void *ptr );
6427 static if (enableGCScan)
6429 pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null );
6430 pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p );
6434 /// `RefCounted` storage implementation.
6435 struct RefCountedStore
6443 private Impl* _store;
6445 private void initialize(A...)(auto ref A args)
6447 import core.lifetime : emplace, forward;
6450 version (D_Exceptions) scope(failure) deallocateStore();
6451 emplace(&_store._payload, forward!args);
6455 private void move(ref T source) nothrow pure
6457 import std.algorithm.mutation : moveEmplace;
6460 moveEmplace(source, _store._payload);
6464 // 'nothrow': can only generate an Error
6465 private void allocateStore() nothrow pure
6467 static if (enableGCScan)
6469 import std.internal.memory : enforceCalloc;
6470 _store = cast(Impl*) enforceCalloc(1, Impl.sizeof);
6471 pureGcAddRange(&_store._payload, T.sizeof);
6475 import std.internal.memory : enforceMalloc;
6476 _store = cast(Impl*) enforceMalloc(Impl.sizeof);
6480 private void deallocateStore() nothrow pure
6482 static if (enableGCScan)
6484 pureGcRemoveRange(&this._store._payload);
6491 Returns `true` if and only if the underlying store has been
6492 allocated and initialized.
6494 @property nothrow @safe pure @nogc
6495 bool isInitialized() const
6497 return _store !is null;
6501 Returns underlying reference count if it is allocated and initialized
6502 (a positive integer), and `0` otherwise.
6504 @property nothrow @safe pure @nogc
6505 size_t refCount() const
6507 return isInitialized ? _store._count : 0;
6511 Makes sure the payload was properly initialized. Such a
6512 call is typically inserted before using the payload.
6514 This function is unavailable if `T.this()` is annotated with
6517 void ensureInitialized()()
6519 // By checking for `@disable this()` and failing early we can
6520 // produce a clearer error message.
6521 static assert(__traits(compiles, { static T t; }),
6522 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~
6523 "` because `" ~ fullyQualifiedName!T ~
6524 ".this()` is annotated with `@disable`.");
6525 if (!isInitialized) initialize();
6529 RefCountedStore _refCounted;
6531 /// Returns storage implementation struct.
6532 @property nothrow @safe
6533 ref inout(RefCountedStore) refCountedStore() inout
6539 Constructor that initializes the payload.
6541 Postcondition: `refCountedStore.isInitialized`
6543 this(A...)(auto ref A args) if (A.length > 0)
6546 assert(refCountedStore.isInitialized);
6550 import core.lifetime : forward;
6551 _refCounted.initialize(forward!args);
6557 _refCounted.move(val);
6561 Constructor that tracks the reference count appropriately. If $(D
6562 !refCountedStore.isInitialized), does nothing.
6564 this(this) @safe pure nothrow @nogc
6566 if (!_refCounted.isInitialized) return;
6567 ++_refCounted._store._count;
6571 Destructor that tracks the reference count appropriately. If $(D
6572 !refCountedStore.isInitialized), does nothing. When the reference count goes
6573 down to zero, calls `destroy` agaist the payload and calls `free`
6574 to deallocate the corresponding resource.
6578 if (!_refCounted.isInitialized) return;
6579 assert(_refCounted._store._count > 0);
6580 if (--_refCounted._store._count)
6582 // Done, destroy and deallocate
6583 .destroy(_refCounted._store._payload);
6584 _refCounted.deallocateStore();
6588 Assignment operators
6590 void opAssign(typeof(this) rhs)
6592 import std.algorithm.mutation : swap;
6594 swap(_refCounted._store, rhs._refCounted._store);
6598 void opAssign(T rhs)
6600 import std.algorithm.mutation : move;
6602 static if (autoInit == RefCountedAutoInitialize.yes)
6604 _refCounted.ensureInitialized();
6608 assert(_refCounted.isInitialized);
6610 move(rhs, _refCounted._store._payload);
6613 //version to have a single properly ddoc'ed function (w/ correct sig)
6617 Returns a reference to the payload. If (autoInit ==
6618 RefCountedAutoInitialize.yes), calls $(D
6619 refCountedStore.ensureInitialized). Otherwise, just issues $(D
6620 assert(refCountedStore.isInitialized)). Used with $(D alias
6621 refCountedPayload this;), so callers can just use the `RefCounted`
6624 $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
6625 So if $(D autoInit == RefCountedAutoInitialize.no)
6626 or called for a constant or immutable object, then
6627 `refCountedPayload` will also be qualified as safe and nothrow
6628 (but will still assert if not initialized).
6631 ref T refCountedPayload() return;
6634 @property nothrow @safe pure @nogc
6635 ref inout(T) refCountedPayload() inout return;
6639 static if (autoInit == RefCountedAutoInitialize.yes)
6641 //Can't use inout here because of potential mutation
6643 ref T refCountedPayload() return
6645 _refCounted.ensureInitialized();
6646 return _refCounted._store._payload;
6650 @property nothrow @safe pure @nogc
6651 ref inout(T) refCountedPayload() inout return
6653 assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload.");
6654 return _refCounted._store._payload;
6659 Returns a reference to the payload. If (autoInit ==
6660 RefCountedAutoInitialize.yes), calls $(D
6661 refCountedStore.ensureInitialized). Otherwise, just issues $(D
6662 assert(refCountedStore.isInitialized)).
6664 alias refCountedPayload this;
6666 static if (is(T == struct) && !is(typeof((ref T t) => t.toString())))
6668 string toString(this This)()
6670 import std.conv : to;
6672 static if (autoInit)
6673 return to!string(refCountedPayload);
6676 if (!_refCounted.isInitialized)
6677 return This.stringof ~ "(RefCountedStore(null))";
6679 return to!string(_refCounted._store._payload);
6686 @betterC pure @system nothrow @nogc unittest
6688 // A pair of an `int` and a `size_t` - the latter being the
6689 // reference count - will be dynamically allocated
6690 auto rc1 = RefCounted!int(5);
6692 // No more allocation, add just one extra reference count
6694 // Reference semantics
6697 // the pair will be freed when rc1 and rc2 go out of scope
6700 pure @system unittest
6704 auto rc1 = RefCounted!int(5);
6707 assert(rc1._refCounted._store._count == 1);
6709 assert(rc1._refCounted._store._count == 2);
6710 // Reference semantics
6714 assert(rc2._refCounted._store._count == 2);
6716 assert(rc1._refCounted._store._count == 2);
6718 assert(p._refCounted._store == null);
6720 // RefCounted as a member
6726 x._refCounted.initialize(y);
6730 auto another = this;
6736 assert(a.x._refCounted._store._count == 2,
6737 "https://issues.dlang.org/show_bug.cgi?id=4356 still unfixed");
6740 @betterC pure @system nothrow @nogc unittest
6742 import std.algorithm.mutation : swap;
6744 RefCounted!int p1, p2;
6748 // https://issues.dlang.org/show_bug.cgi?id=6606
6749 @betterC @safe pure nothrow @nogc unittest
6760 alias SRC = RefCounted!S;
6763 // https://issues.dlang.org/show_bug.cgi?id=6436
6764 @betterC @system pure unittest
6768 this(int rval) { assert(rval == 1); }
6769 this(ref int lval) { assert(lval == 3); ++lval; }
6772 auto s1 = RefCounted!S(1);
6774 auto s2 = RefCounted!S(lval);
6778 // gc_addRange coverage
6779 @betterC @system pure unittest
6781 struct S { int* p; }
6783 auto s = RefCounted!S(null);
6786 @betterC @system pure nothrow @nogc unittest
6789 a = 5; //This should not assert
6793 b = a; //This should not assert either
6796 RefCounted!(int*) c;
6799 // https://issues.dlang.org/show_bug.cgi?id=21638
6800 @betterC @system pure nothrow @nogc unittest
6802 static struct NoDefaultCtor
6805 this(int x) @nogc nothrow pure { this.x = x; }
6808 auto rc = RefCounted!(NoDefaultCtor, RefCountedAutoInitialize.no)(5);
6812 // https://issues.dlang.org/show_bug.cgi?id=20502
6815 import std.conv : to;
6816 // Check that string conversion is transparent for refcounted
6817 // structs that do not have either toString or alias this.
6818 static struct A { Object a; }
6819 auto a = A(new Object());
6820 auto r = refCounted(a);
6821 assert(to!string(r) == to!string(a));
6822 assert(to!string(cast(const) r) == to!string(cast(const) a));
6823 // Check that string conversion is still transparent for refcounted
6824 // structs that have alias this.
6825 static struct B { int b; alias b this; }
6826 static struct C { B b; alias b this; }
6827 assert(to!string(refCounted(C(B(123)))) == to!string(C(B(123))));
6828 // https://issues.dlang.org/show_bug.cgi?id=22093
6829 // Check that uninitialized refcounted structs that previously could be
6830 // converted to strings still can be.
6831 alias R = typeof(r);
6833 cast(void) (((const ref R a) => to!string(a))(r2));
6834 cast(void) to!string(RefCounted!(A, RefCountedAutoInitialize.no).init);
6838 * Initializes a `RefCounted` with `val`. The template parameter
6839 * `T` of `RefCounted` is inferred from `val`.
6840 * This function can be used to move non-copyable values to the heap.
6841 * It also disables the `autoInit` option of `RefCounted`.
6844 * val = The value to be reference counted
6846 * An initialized `RefCounted` containing `val`.
6848 * $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared)
6850 RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val)
6853 res._refCounted.move(val);
6862 static size_t nDestroyed;
6864 @disable this(this); // not copyable
6865 ~this() { name = null; ++nDestroyed; }
6868 auto file = File("name");
6869 assert(file.name == "name");
6870 // file cannot be copied and has unique ownership
6871 static assert(!__traits(compiles, {auto file2 = file;}));
6873 assert(File.nDestroyed == 0);
6875 // make the file refcounted to share ownership
6877 // We write a compound statement (brace-delimited scope) in which all `RefCounted!File` handles are created and deleted.
6878 // This allows us to see (after the scope) what happens after all handles have been destroyed.
6880 // We move the content of `file` to a separate (and heap-allocated) `File` object,
6881 // managed-and-accessed via one-or-multiple (initially: one) `RefCounted!File` objects ("handles").
6883 // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`);
6884 // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`).
6885 // It appears that writing `name = null;` in the destructor is redundant,
6886 // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator),
6887 // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor.
6888 import std.algorithm.mutation : move;
6889 auto rcFile = refCounted(move(file));
6890 assert(rcFile.name == "name");
6891 assert(File.nDestroyed == 1);
6892 assert(file.name == null);
6894 // We create another `RefCounted!File` handle to the same separate `File` object.
6895 // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified).
6896 auto rcFile2 = rcFile;
6897 assert(rcFile.refCountedStore.refCount == 2);
6898 assert(File.nDestroyed == 1);
6900 // The separate `File` object is deleted when the last `RefCounted!File` handle is destroyed
6901 // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`)
6902 // (=> `File.nDestroyed` is incremented again, from 1 to 2):
6903 assert(File.nDestroyed == 2);
6907 Creates a proxy for the value `a` that will forward all operations
6908 while disabling implicit conversions. The aliased item `a` must be
6909 an $(B lvalue). This is useful for creating a new type from the
6910 "base" type (though this is $(B not) a subtype-supertype
6911 relationship; the new type is not related to the old type in any way,
6914 The new type supports all operations that the underlying type does,
6915 including all operators such as `+`, `--`, `<`, `[]`, etc.
6918 a = The value to act as a proxy for all operations. It must
6921 mixin template Proxy(alias a)
6923 private alias ValueType = typeof({ return a; }());
6925 /* Determine if 'T.a' can referenced via a const(T).
6926 * Use T* as the parameter because 'scope' inference needs a fully
6927 * analyzed T, which doesn't work when accessibleFrom() is used in a
6928 * 'static if' in the definition of Proxy or T.
6930 private enum bool accessibleFrom(T) =
6931 is(typeof((T* self){ cast(void) mixin("(*self)."~__traits(identifier, a)); }));
6933 static if (is(typeof(this) == class))
6935 override bool opEquals(Object o)
6937 if (auto b = cast(typeof(this))o)
6939 return a == mixin("b."~__traits(identifier, a));
6944 bool opEquals(T)(T b)
6945 if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
6947 static if (is(typeof(a.opEquals(b))))
6948 return a.opEquals(b);
6949 else static if (is(typeof(b.opEquals(a))))
6950 return b.opEquals(a);
6955 override int opCmp(Object o)
6957 if (auto b = cast(typeof(this))o)
6959 return a < mixin("b."~__traits(identifier, a)) ? -1
6960 : a > mixin("b."~__traits(identifier, a)) ? +1 : 0;
6962 static if (is(ValueType == class))
6965 throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString);
6968 int opCmp(T)(auto ref const T b)
6969 if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
6971 static if (is(typeof(a.opCmp(b))))
6973 else static if (is(typeof(b.opCmp(a))))
6976 return a < b ? -1 : a > b ? +1 : 0;
6979 static if (accessibleFrom!(const typeof(this)))
6981 override size_t toHash() const nothrow @safe
6983 static if (__traits(compiles, .hashOf(a)))
6986 // Workaround for when .hashOf is not both @safe and nothrow.
6988 static if (is(typeof(&a) == ValueType*))
6991 auto v = a; // if a is (property) function
6992 // BUG: Improperly casts away `shared`!
6993 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)());
7000 auto ref opEquals(this X, B)(auto ref B b)
7002 static if (is(immutable B == immutable typeof(this)))
7004 return a == mixin("b."~__traits(identifier, a));
7010 auto ref opCmp(this X, B)(auto ref B b)
7012 static if (is(typeof(a.opCmp(b))))
7014 else static if (is(typeof(b.opCmp(a))))
7016 else static if (isFloatingPoint!ValueType || isFloatingPoint!B)
7017 return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan;
7019 return a < b ? -1 : (a > b);
7022 static if (accessibleFrom!(const typeof(this)))
7024 size_t toHash() const nothrow @safe
7026 static if (__traits(compiles, .hashOf(a)))
7029 // Workaround for when .hashOf is not both @safe and nothrow.
7031 static if (is(typeof(&a) == ValueType*))
7034 auto v = a; // if a is (property) function
7035 // BUG: Improperly casts away `shared`!
7036 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)());
7042 auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); }
7044 auto ref opCast(T, this X)() { return cast(T) a; }
7046 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; }
7047 auto ref opSlice(this X )() { return a[]; }
7048 auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b .. e]; }
7050 auto ref opUnary (string op, this X )() { return mixin(op~"a"); }
7051 auto ref opIndexUnary(string op, this X, D...)(auto ref D i) { return mixin(op~"a[i]"); }
7052 auto ref opSliceUnary(string op, this X )() { return mixin(op~"a[]"); }
7053 auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b .. e]"); }
7055 auto ref opBinary(string op, this X, B)(auto ref B b)
7056 if (op == "in" && is(typeof(a in b)) || op != "in")
7058 return mixin("a "~op~" b");
7060 auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); }
7062 static if (!is(typeof(this) == class))
7065 static if (isAssignable!ValueType)
7067 auto ref opAssign(this X)(auto ref typeof(this) v)
7069 a = mixin("v."~__traits(identifier, a));
7075 @disable void opAssign(this X)(auto ref typeof(this) v);
7079 auto ref opAssign (this X, V )(auto ref V v) if (!is(V == typeof(this))) { return a = v; }
7080 auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i) { return a[i] = v; }
7081 auto ref opSliceAssign(this X, V )(auto ref V v) { return a[] = v; }
7082 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; }
7084 auto ref opOpAssign (string op, this X, V )(auto ref V v)
7086 return mixin("a = a "~op~" v");
7088 auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i)
7090 return mixin("a[i] " ~op~"= v");
7092 auto ref opSliceOpAssign(string op, this X, V )(auto ref V v)
7094 return mixin("a[] " ~op~"= v");
7096 auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e)
7098 return mixin("a[b .. e] "~op~"= v");
7101 template opDispatch(string name)
7103 static if (is(typeof(__traits(getMember, a, name)) == function))
7105 // non template function
7106 auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); }
7108 else static if (is(typeof({ enum x = mixin("a."~name); })))
7110 // built-in type field, manifest constant, and static non-mutable field
7111 enum opDispatch = mixin("a."~name);
7113 else static if (__traits(isTemplate, mixin("a."~name)))
7116 template opDispatch(T...)
7118 enum targs = T.length ? "!T" : "";
7119 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
7124 // field or property function
7125 @property auto ref opDispatch(this X)() { return mixin("a."~name); }
7126 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
7131 import std.traits : isArray;
7133 static if (isArray!ValueType)
7135 auto opDollar() const { return a.length; }
7137 else static if (is(typeof(a.opDollar!0)))
7139 auto ref opDollar(size_t pos)() { return a.opDollar!pos(); }
7141 else static if (is(typeof(a.opDollar) == function))
7143 auto ref opDollar() { return a.opDollar(); }
7145 else static if (is(typeof(a.opDollar)))
7147 alias opDollar = a.opDollar;
7159 this(int n){ value = n; }
7164 // Enable operations that original type has.
7167 assert(n * 2 == 22);
7169 void func(int n) { }
7171 // Disable implicit conversions to original type.
7176 ///The proxied value must be an $(B lvalue).
7181 //Won't work; the literal '1'
7182 //is an rvalue, not an lvalue
7185 //Okay, n is an lvalue
7189 this(int n) { this.n = n; }
7197 struct NewObjectType
7200 //Ok, obj is an lvalue
7203 this (Object o) { obj = o; }
7206 NewObjectType not = new Object();
7207 assert(__traits(compiles, not.toHash()));
7211 There is one exception to the fact that the new type is not related to the
7212 old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member)
7213 functions are usable with the new type; they will be forwarded on to the
7218 import std.math.traits : isInfinity;
7221 assert(!f.isInfinity);
7228 this(float f) { _ = f; }
7232 assert(!nf.isInfinity);
7241 this(int n) inout { value = n; }
7244 static immutable arr = [1,2,3];
7247 static foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt))
7250 static assert(!__traits(compiles, { int x = m; }));
7251 static assert(!__traits(compiles, { void func(int n){} func(m); }));
7257 assert(cast(double) m == 10.0);
7258 assert(m + 10 == 20);
7260 assert(m * 20 == 200);
7262 assert(10 + m == 20);
7263 assert(15 - m == 5);
7264 assert(20 * m == 200);
7265 assert(50 / m == 5);
7266 static if (is(T == MyInt)) // mutable
7269 assert(m++ == 11); assert(m == 12);
7271 assert(m-- == 11); assert(m == 10);
7273 m = 20; assert(m == 20);
7275 static assert(T.max == int.max);
7276 static assert(T.min == int.min);
7277 static assert(T.init == int.init);
7278 static assert(T.str == "str");
7279 static assert(T.arr == [1,2,3]);
7284 static struct MyArray
7286 private int[] value;
7288 this(int[] arr) { value = arr; }
7289 this(immutable int[] arr) immutable { value = arr; }
7292 static foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray))
7294 static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; })))
7295 T a = [1,2,3,4].idup; // workaround until qualified ctor is properly supported
7298 assert(a == [1,2,3,4]);
7299 assert(a != [5,6,7,8]);
7301 version (LittleEndian)
7302 assert(cast(ulong[]) a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]);
7304 assert(cast(ulong[]) a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]);
7305 assert(a ~ [10,11] == [1,2,3,4,10,11]);
7307 assert(a[] == [1,2,3,4]);
7308 assert(a[2 .. 4] == [3,4]);
7309 static if (is(T == MyArray)) // mutable
7312 a = [5,6,7,8]; assert(a == [5,6,7,8]);
7313 a[0] = 0; assert(a == [0,6,7,8]);
7314 a[] = 1; assert(a == [1,1,1,1]);
7315 a[0 .. 3] = 2; assert(a == [2,2,2,1]);
7316 a[0] += 2; assert(a == [4,2,2,1]);
7317 a[] *= 2; assert(a == [8,4,4,2]);
7318 a[0 .. 2] /= 2; assert(a == [4,2,4,2]);
7328 @property int val1() const { return field; }
7329 @property void val1(int n) { field = n; }
7331 @property ref int val2() { return field; }
7333 int func(int x, int y) const { return x; }
7334 void func1(ref int a) { a = 9; }
7336 T ifti1(T)(T t) { return t; }
7337 void ifti2(Args...)(Args args) { }
7338 void ifti3(T, Args...)(Args args) { }
7340 T opCast(T)(){ return T.init; }
7342 T tempfunc(T)() { return T.init; }
7348 this(Foo f) { foo = f; }
7351 auto h = new Hoge(new Foo());
7354 static assert(!__traits(compiles, { Foo f = h; }));
7357 h.field = 1; // lhs of assign
7358 n = h.field; // rhs of assign
7359 assert(h.field == 1); // lhs of BinExp
7360 assert(1 == h.field); // rhs of BinExp
7363 // getter/setter property function
7366 assert(h.val1 == 4);
7367 assert(4 == h.val1);
7370 // ref getter property function
7373 assert(h.val2 == 8);
7374 assert(8 == h.val2);
7378 assert(h.func(2,4) == 2);
7383 assert(h.ifti1(4) == 4);
7387 // https://issues.dlang.org/show_bug.cgi?id=5896 test
7388 assert(h.opCast!int() == 0);
7389 assert(cast(int) h == 0);
7390 const ih = new const Hoge(new Foo());
7391 static assert(!__traits(compiles, ih.opCast!int()));
7392 static assert(!__traits(compiles, cast(int) ih));
7394 // template member function
7395 assert(h.tempfunc!int() == 0);
7398 @system unittest // about Proxy inside a class
7403 mixin Proxy!payload;
7404 this(int i){ payload = i; }
7405 string opCall(string msg){ return msg; }
7406 int pow(int i){ return payload ^^ i; }
7412 mixin Proxy!payload;
7413 this(int i){ payload = new MyClass(i); }
7419 mixin Proxy!payload;
7420 this(int i){ payload = i; }
7424 Object a = new MyClass(5);
7425 Object b = new MyClass(5);
7426 Object c = new MyClass2(5);
7427 Object d = new MyClass3(5);
7429 assert((cast(MyClass) a) == 5);
7430 assert(5 == (cast(MyClass) b));
7431 assert(5 == cast(MyClass2) c);
7435 // oops! above line is unexpected, isn't it?
7436 // the reason is below.
7437 // MyClass2.opEquals knows MyClass but,
7438 // MyClass.opEquals doesn't know MyClass2.
7439 // so, c.opEquals(a) is true, but a.opEquals(c) is false.
7440 // furthermore, opEquals(T) couldn't be invoked.
7441 assert((cast(MyClass2) c) != (cast(MyClass) a));
7444 Object e = new MyClass2(7);
7445 assert(a < cast(MyClass2) e); // OK. and
7446 assert(e > a); // OK, but...
7447 // assert(a < e); // RUNTIME ERROR!
7448 // assert((cast(MyClass) a) < e); // RUNTIME ERROR!
7449 assert(3 < cast(MyClass) a);
7450 assert((cast(MyClass2) e) < 11);
7453 assert((cast(MyClass2) e)("hello") == "hello");
7456 assert((cast(MyClass)(cast(MyClass2) c)) == a);
7457 assert((cast(int)(cast(MyClass2) c)) == 5);
7463 mixin Proxy!payload;
7464 this(string s){ payload = s; }
7469 mixin Proxy!payload;
7470 this(string s){ payload = new MyClass4(s); }
7472 auto f = new MyClass4("hello");
7473 assert(f[1] == 'e');
7474 auto g = new MyClass5("hello");
7475 assert(f[1] == 'e');
7478 assert(f[2 .. 4] == "ll");
7481 assert(-(cast(MyClass2) c) == -5);
7484 assert((cast(MyClass) a) + (cast(MyClass2) c) == 10);
7485 assert(5 + cast(MyClass) a == 10);
7488 (cast(MyClass2) c) = 11;
7489 assert((cast(MyClass2) c) == 11);
7490 (cast(MyClass2) c) = new MyClass(13);
7491 assert((cast(MyClass2) c) == 13);
7494 assert((cast(MyClass2) c) += 4);
7495 assert((cast(MyClass2) c) == 17);
7498 assert((cast(MyClass2) c).pow(2) == 289);
7501 assert(f[2..$-1] == "ll");
7507 assert(hash[b] == 19);
7508 assert(hash[c] == 21);
7517 mixin Proxy!payload;
7525 @disable void opAssign(typeof(this));
7531 mixin Proxy!payload;
7534 static assert(!__traits(compiles, f = f));
7540 mixin Proxy!payload;
7542 // override default Proxy behavior
7543 void opAssign(typeof(this) rhs){}
7549 // https://issues.dlang.org/show_bug.cgi?id=8613
7556 this(string s) { val = s; }
7560 names[Name("a")] = true;
7561 bool* b = Name("a") in names;
7564 // workaround for https://issues.dlang.org/show_bug.cgi?id=19669
7565 private enum isDIP1000 = __traits(compiles, () @safe {
7570 // excludes struct S; it's 'mixin Proxy!foo' doesn't compile with -dip1000
7571 static if (isDIP1000) {} else
7574 // https://issues.dlang.org/show_bug.cgi?id=14213
7575 // using function for the payload
7578 int foo() { return 12; }
7582 assert(s + 1 == 13);
7583 assert(s * 2 == 24);
7590 int foo() { return 12; }
7596 // Check all floating point comparisons for both Proxy and Typedef,
7597 // also against int and a Typedef!int, to be as regression-proof
7598 // as possible. https://issues.dlang.org/show_bug.cgi?id=15561
7601 static struct MyFloatImpl
7606 static void allFail(T0, T1)(T0 a, T1 b)
7614 static foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double,
7615 float, real, Typedef!int, int))
7617 static foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float))
7622 static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1))
7645 $(B Typedef) allows the creation of a unique type which is
7646 based on an existing type. Unlike the `alias` feature,
7647 $(B Typedef) ensures the two types are not considered as equals.
7651 init = Optional initial value for the new type.
7652 cookie = Optional, used to create multiple unique types which are
7653 based on the same origin type `T`
7655 Note: If a library routine cannot handle the Typedef type,
7656 you can use the `TypedefType` template to extract the
7657 type which the Typedef wraps.
7659 struct Typedef(T, T init = T.init, string cookie=null)
7661 private T Typedef_payload = init;
7663 // https://issues.dlang.org/show_bug.cgi?id=18415
7664 // prevent default construction if original type does too.
7665 static if ((is(T == struct) || is(T == union)) && !is(typeof({T t;})))
7672 Typedef_payload = init;
7677 this(tdef.Typedef_payload);
7680 // We need to add special overload for cast(Typedef!X) exp,
7681 // thus we can't simply inherit Proxy!Typedef_payload
7682 T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)()
7684 return T2(cast(T) Typedef_payload);
7687 auto ref opCast(T2, this X)()
7689 return cast(T2) Typedef_payload;
7692 mixin Proxy!Typedef_payload;
7694 pure nothrow @nogc @safe @property
7696 alias TD = typeof(this);
7697 static if (isIntegral!T)
7699 static TD min() {return TD(T.min);}
7700 static TD max() {return TD(T.max);}
7702 else static if (isFloatingPoint!T)
7704 static TD infinity() {return TD(T.infinity);}
7705 static TD nan() {return TD(T.nan);}
7706 static TD dig() {return TD(T.dig);}
7707 static TD epsilon() {return TD(T.epsilon);}
7708 static TD mant_dig() {return TD(T.mant_dig);}
7709 static TD max_10_exp() {return TD(T.max_10_exp);}
7710 static TD max_exp() {return TD(T.max_exp);}
7711 static TD min_10_exp() {return TD(T.min_10_exp);}
7712 static TD min_exp() {return TD(T.min_exp);}
7713 static TD max() {return TD(T.max);}
7714 static TD min_normal() {return TD(T.min_normal);}
7715 TD re() {return TD(Typedef_payload.re);}
7716 TD im() {return TD(Typedef_payload.im);}
7721 * Convert wrapped value to a human readable string
7723 string toString(this T)()
7725 import std.array : appender;
7726 auto app = appender!string();
7727 auto spec = singleSpec("%s");
7728 toString(app, spec);
7733 void toString(this T, W)(ref W writer, scope const ref FormatSpec!char fmt)
7734 if (isOutputRange!(W, char))
7736 formatValue(writer, Typedef_payload, fmt);
7742 import std.conv : to;
7745 auto td = Typedef!int(i);
7746 assert(i.to!string == td.to!string);
7753 alias MyInt = Typedef!int;
7759 /// custom initialization values
7762 alias MyIntInit = Typedef!(int, 42);
7763 static assert(is(TypedefType!MyIntInit == int));
7764 static assert(MyIntInit() == 42);
7767 /// Typedef creates a new type
7770 alias MyInt = Typedef!int;
7771 static void takeInt(int) {}
7772 static void takeMyInt(MyInt) {}
7776 static assert(!__traits(compiles, takeMyInt(i)));
7779 static assert(!__traits(compiles, takeInt(myInt)));
7780 takeMyInt(myInt); // ok
7783 /// Use the optional `cookie` argument to create different types of the same base type
7786 alias TypeInt1 = Typedef!int;
7787 alias TypeInt2 = Typedef!int;
7789 // The two Typedefs are the same type.
7790 static assert(is(TypeInt1 == TypeInt2));
7792 alias MoneyEuros = Typedef!(float, float.init, "euros");
7793 alias MoneyDollars = Typedef!(float, float.init, "dollars");
7795 // The two Typedefs are _not_ the same type.
7796 static assert(!is(MoneyEuros == MoneyDollars));
7799 // https://issues.dlang.org/show_bug.cgi?id=12461
7802 alias Int = Typedef!int;
7810 Get the underlying type which a `Typedef` wraps.
7811 If `T` is not a `Typedef` it will alias itself to `T`.
7813 template TypedefType(T)
7815 static if (is(T : Typedef!Arg, Arg))
7816 alias TypedefType = Arg;
7818 alias TypedefType = T;
7824 import std.conv : to;
7826 alias MyInt = Typedef!int;
7827 static assert(is(TypedefType!MyInt == int));
7829 /// Instantiating with a non-Typedef will return that type
7830 static assert(is(TypedefType!int == int));
7834 // extract the needed type
7835 MyInt myInt = MyInt( num.to!(TypedefType!MyInt) );
7838 // cast to the underlying type to get the value that's being wrapped
7839 int x = cast(TypedefType!MyInt) myInt;
7841 alias MyIntInit = Typedef!(int, 42);
7842 static assert(is(TypedefType!MyIntInit == int));
7843 static assert(MyIntInit() == 42);
7849 static assert(!__traits(compiles, { int y = x; }));
7850 static assert(!__traits(compiles, { long z = x; }));
7855 static assert(Typedef!int.init == int.init);
7857 Typedef!(float, 1.0) z; // specifies the init
7860 static assert(typeof(z).init == 1.0);
7862 alias Dollar = Typedef!(int, 0, "dollar");
7863 alias Yen = Typedef!(int, 0, "yen");
7864 static assert(!is(Dollar == Yen));
7866 Typedef!(int[3]) sa;
7867 static assert(sa.length == 3);
7868 static assert(typeof(sa).length == 3);
7870 Typedef!(int[3]) dollar1;
7871 assert(dollar1[0..$] is dollar1[0 .. 3]);
7873 Typedef!(int[]) dollar2;
7875 assert(dollar2[0..$] is dollar2[0 .. 3]);
7877 static struct Dollar1
7879 static struct DollarToken {}
7880 enum opDollar = DollarToken.init;
7881 auto opSlice(size_t, DollarToken) { return 1; }
7882 auto opSlice(size_t, size_t) { return 2; }
7885 Typedef!Dollar1 drange1;
7886 assert(drange1[0..$] == 1);
7887 assert(drange1[0 .. 1] == 2);
7889 static struct Dollar2
7891 size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; }
7892 size_t opIndex(size_t i, size_t j) { return i + j; }
7895 Typedef!Dollar2 drange2;
7896 assert(drange2[$, $] == 101);
7898 static struct Dollar3
7900 size_t opDollar() { return 123; }
7901 size_t opIndex(size_t i) { return i; }
7904 Typedef!Dollar3 drange3;
7905 assert(drange3[$] == 123);
7908 // https://issues.dlang.org/show_bug.cgi?id=18415
7909 @safe @nogc pure nothrow unittest
7911 struct NoDefCtorS{@disable this();}
7912 union NoDefCtorU{@disable this();}
7913 static assert(!is(typeof({Typedef!NoDefCtorS s;})));
7914 static assert(!is(typeof({Typedef!NoDefCtorU u;})));
7917 // https://issues.dlang.org/show_bug.cgi?id=11703
7918 @safe @nogc pure nothrow unittest
7920 alias I = Typedef!int;
7921 static assert(is(typeof(I.min) == I));
7922 static assert(is(typeof(I.max) == I));
7924 alias F = Typedef!double;
7925 static assert(is(typeof(F.infinity) == F));
7926 static assert(is(typeof(F.epsilon) == F));
7929 assert(!is(typeof(F.re).stringof == double));
7930 assert(!is(typeof(F.im).stringof == double));
7935 // https://issues.dlang.org/show_bug.cgi?id=8655
7936 import std.typecons;
7937 import std.bitmanip;
7938 static import core.stdc.config;
7940 alias c_ulong = Typedef!(core.stdc.config.c_ulong);
7945 c_ulong, "NameOffset", 31,
7946 c_ulong, "NameIsString", 1
7951 // https://issues.dlang.org/show_bug.cgi?id=12596
7954 import std.typecons;
7955 alias TD = Typedef!int;
7961 @safe unittest // about toHash
7963 import std.typecons;
7965 alias TD = Typedef!int;
7968 assert(td[TD(1)] == 1);
7972 alias TD = Typedef!(int[]);
7974 td[TD([1,2,3,4])] = 2;
7975 assert(td[TD([1,2,3,4])] == 2);
7979 alias TD = Typedef!(int[][]);
7981 td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3;
7982 assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3);
7986 struct MyStruct{ int x; }
7987 alias TD = Typedef!MyStruct;
7989 td[TD(MyStruct(10))] = 4;
7990 assert(TD(MyStruct(20)) !in td);
7991 assert(td[TD(MyStruct(10))] == 4);
7995 static struct MyStruct2
7998 size_t toHash() const nothrow @safe { return x; }
7999 bool opEquals(ref const MyStruct2 r) const { return r.x == x; }
8002 alias TD = Typedef!MyStruct2;
8004 td[TD(MyStruct2(50))] = 5;
8005 assert(td[TD(MyStruct2(50))] == 5);
8010 alias TD = Typedef!MyClass;
8012 auto c = new MyClass;
8014 assert(TD(new MyClass) !in td);
8015 assert(td[TD(c)] == 6);
8021 alias String = Typedef!(char[]);
8022 alias CString = Typedef!(const(char)[]);
8023 CString cs = "fubar";
8024 String s = cast(String) cs;
8026 char[] s2 = cast(char[]) cs;
8027 const(char)[] cs2 = cast(const(char)[])s;
8031 @system unittest // toString
8033 import std.meta : AliasSeq;
8034 import std.conv : to;
8039 static foreach (T; AliasSeq!(int, bool, float, double, real,
8042 int*, int[], int[2], int[int]))
8047 Typedef!(const T) ctd;
8048 Typedef!(immutable T) itd;
8050 assert(t.to!string() == td.to!string());
8052 static if (!(is(T == TestS) || is(T == TestC)))
8054 assert(t.to!string() == ctd.to!string());
8055 assert(t.to!string() == itd.to!string());
8060 @safe @nogc unittest // typedef'ed type with custom operators
8065 int opCmp(MyInt other)
8067 if (value < other.value)
8069 return !(value == other.value);
8073 auto m1 = Typedef!MyInt(MyInt(1));
8074 auto m2 = Typedef!MyInt(MyInt(2));
8079 Allocates a `class` object right inside the current scope,
8080 therefore avoiding the overhead of `new`. This facility is unsafe;
8081 it is the responsibility of the user to not escape a reference to the
8082 object outside the scope.
8084 The class destructor will be called when the result of `scoped()` is
8087 Scoped class instances can be embedded in a parent `class` or `struct`,
8088 just like a child struct instance. Scoped member variables must have
8089 type `typeof(scoped!Class(args))`, and be initialized with a call to
8090 scoped. See below for an example.
8093 It's illegal to move a class instance even if you are sure there
8094 are no pointers to it. As such, it is illegal to move a scoped object.
8099 // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for
8100 // small objects). We will just use the maximum of filed alignments.
8101 alias alignment = classInstanceAlignment!T;
8102 alias aligned = _alignUp!alignment;
8104 static struct Scoped
8106 // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory.
8107 private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void;
8109 @property inout(T) Scoped_payload() inout
8111 void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr);
8112 // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly.
8113 immutable size_t d = alignedStore - Scoped_store.ptr;
8114 size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof];
8117 import core.stdc.string : memmove;
8118 memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T));
8121 return cast(inout(T)) alignedStore;
8123 alias Scoped_payload this;
8126 @disable this(this);
8130 // `destroy` will also write .init but we have no functions in druntime
8131 // for deterministic finalization and memory releasing for now.
8132 .destroy(Scoped_payload);
8136 /** Returns the _scoped object.
8137 Params: args = Arguments to pass to `T`'s constructor.
8139 @system auto scoped(Args...)(auto ref Args args)
8141 import core.lifetime : emplace, forward;
8143 Scoped result = void;
8144 void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr);
8145 immutable size_t d = alignedStore - result.Scoped_store.ptr;
8146 *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d;
8147 emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], forward!args);
8163 // Standard usage, constructing A on the stack
8164 auto a1 = scoped!A();
8167 // Result of `scoped` call implicitly converts to a class reference
8169 assert(aRef.x == 42);
8171 // Scoped destruction
8173 auto a2 = scoped!A(1);
8176 // a2 is destroyed here, calling A's destructor
8178 // aRef is now an invalid reference
8180 // Here the temporary scoped A is immediately destroyed.
8181 // This means the reference is then invalid.
8184 // Wrong, should use `auto`
8185 A invalid = scoped!A();
8191 import std.algorithm.mutation : move;
8192 auto invalid = a1.move; // illegal, scoped objects can't be moved
8194 static assert(!is(typeof({
8195 auto e1 = a1; // illegal, scoped objects can't be copied
8196 assert([a1][0].x == 42); // ditto
8198 static assert(!is(typeof({
8199 alias ScopedObject = typeof(a1);
8200 auto e2 = ScopedObject(); // illegal, must be built via scoped!A
8201 auto e3 = ScopedObject(1); // ditto
8205 alias makeScopedA = scoped!A;
8206 auto a3 = makeScopedA();
8207 auto a4 = makeScopedA(1);
8209 // Use as member variable
8212 typeof(scoped!A()) a; // note the trailing parentheses
8224 assert(aRef.x == 5);
8225 destroy(b1); // calls A's destructor for b1.a
8226 // aRef is now an invalid reference
8230 assert(b2.a.x == 6);
8231 destroy(*b2); // calls A's destructor for b2.a
8234 private size_t _alignUp(size_t alignment)(size_t n)
8235 if (alignment > 0 && !((alignment - 1) & alignment))
8237 enum badEnd = alignment - 1; // 0b11, 0b111, ...
8238 return (n + badEnd) & ~badEnd;
8241 // https://issues.dlang.org/show_bug.cgi?id=6580 testcase
8244 enum alignment = (void*).alignof;
8247 static class C1 { byte b; }
8248 static class C2 { byte[2] b; }
8249 static class C3 { byte[3] b; }
8250 static class C7 { byte[7] b; }
8251 static assert(scoped!C0().sizeof % alignment == 0);
8252 static assert(scoped!C1().sizeof % alignment == 0);
8253 static assert(scoped!C2().sizeof % alignment == 0);
8254 static assert(scoped!C3().sizeof % alignment == 0);
8255 static assert(scoped!C7().sizeof % alignment == 0);
8257 enum longAlignment = long.alignof;
8260 long long_; byte byte_ = 4;
8262 this(long _long, ref int i) { long_ = _long; ++i; }
8264 static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; }
8265 static assert(scoped!C1long().sizeof % longAlignment == 0);
8266 static assert(scoped!C2long().sizeof % longAlignment == 0);
8268 void alignmentTest()
8271 auto c1long = scoped!C1long(3, var);
8273 auto c2long = scoped!C2long();
8274 assert(cast(uint)&c1long.long_ % longAlignment == 0);
8275 assert(cast(uint)&c2long.long_ % longAlignment == 0);
8276 assert(c1long.long_ == 3 && c1long.byte_ == 4);
8277 assert(c2long.byte_ == [5, 6] && c2long.long_ == 7);
8282 version (DigitalMars)
8284 void test(size_t size)
8286 import core.stdc.stdlib;
8287 cast(void) alloca(size);
8290 foreach (i; 0 .. 10)
8295 void test(size_t size)()
8300 static foreach (i; 0 .. 11)
8305 // Original https://issues.dlang.org/show_bug.cgi?id=6580 testcase
8308 class C { int i; byte b; }
8310 auto sa = [scoped!C(), scoped!C()];
8311 assert(cast(uint)&sa[0].i % int.alignof == 0);
8312 assert(cast(uint)&sa[1].i % int.alignof == 0); // fails
8317 class A { int x = 1; }
8318 auto a1 = scoped!A();
8320 auto a2 = scoped!A();
8328 class A { int x = 1; this() { x = 2; } }
8329 auto a1 = scoped!A();
8331 auto a2 = scoped!A();
8339 class A { int x = 1; this(int y) { x = y; } ~this() {} }
8340 auto a1 = scoped!A(5);
8342 auto a2 = scoped!A(42);
8350 class A { static bool dead; ~this() { dead = true; } }
8351 class B : A { static bool dead; ~this() { dead = true; } }
8353 auto b = scoped!B();
8355 assert(B.dead, "asdasd");
8356 assert(A.dead, "asdasd");
8359 // https://issues.dlang.org/show_bug.cgi?id=8039 testcase
8363 static struct S { ~this(){ ++dels; } }
8365 static class A { S s; }
8366 dels = 0; { scoped!A(); }
8369 static class B { S[2] s; }
8370 dels = 0; { scoped!B(); }
8373 static struct S2 { S[3] s; }
8374 static class C { S2[2] s; }
8375 dels = 0; { scoped!C(); }
8378 static class D: A { S2[2] s; }
8379 dels = 0; { scoped!D(); }
8380 assert(dels == 1+6);
8385 // https://issues.dlang.org/show_bug.cgi?id=4500
8388 this() { a = this; }
8389 this(int i) { a = this; }
8391 bool check() { return this is a; }
8394 auto a1 = scoped!A();
8397 auto a2 = scoped!A(1);
8410 this() { ++sdtor; assert(sdtor == 1); }
8411 ~this() { assert(sdtor == 1); --sdtor; }
8416 static class ABob : A, Bob
8418 this() { ++sdtor; assert(sdtor == 2); }
8419 ~this() { assert(sdtor == 2); --sdtor; }
8423 scope(exit) assert(A.sdtor == 0);
8424 auto abob = scoped!ABob();
8429 static class A { this(int) {} }
8430 static assert(!__traits(compiles, scoped!A()));
8435 static class A { @property inout(int) foo() inout { return 1; } }
8437 auto a1 = scoped!A();
8438 assert(a1.foo == 1);
8439 static assert(is(typeof(a1.foo) == int));
8441 auto a2 = scoped!(const(A))();
8442 assert(a2.foo == 1);
8443 static assert(is(typeof(a2.foo) == const(int)));
8445 auto a3 = scoped!(immutable(A))();
8446 assert(a3.foo == 1);
8447 static assert(is(typeof(a3.foo) == immutable(int)));
8449 const c1 = scoped!A();
8450 assert(c1.foo == 1);
8451 static assert(is(typeof(c1.foo) == const(int)));
8453 const c2 = scoped!(const(A))();
8454 assert(c2.foo == 1);
8455 static assert(is(typeof(c2.foo) == const(int)));
8457 const c3 = scoped!(immutable(A))();
8458 assert(c3.foo == 1);
8459 static assert(is(typeof(c3.foo) == immutable(int)));
8466 this(int rval) { assert(rval == 1); }
8467 this(ref int lval) { assert(lval == 3); ++lval; }
8470 auto c1 = scoped!C(1);
8472 auto c2 = scoped!C(lval);
8484 alias makeScopedC = scoped!C;
8486 auto a = makeScopedC();
8487 auto b = makeScopedC(1);
8488 auto c = makeScopedC(1, 1);
8490 static assert(is(typeof(a) == typeof(b)));
8491 static assert(is(typeof(b) == typeof(c)));
8495 Defines a simple, self-documenting yes/no flag. This makes it easy for
8496 APIs to define functions accepting flags without resorting to $(D
8497 bool), which is opaque in calls, and without needing to define an
8498 enumerated type separately. Using `Flag!"Name"` instead of $(D
8499 bool) makes the flag's meaning visible in calls. Each yes/no flag has
8500 its own type, which makes confusions and mix-ups impossible.
8504 Code calling `getLine` (usually far away from its definition) can't be
8505 understood without looking at the documentation, even by users familiar with
8508 string getLine(bool keepTerminator)
8511 if (keepTerminator) ...
8515 auto line = getLine(false);
8518 Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong
8519 code compiles and runs with erroneous results.
8521 After replacing the boolean parameter with an instantiation of `Flag`, code
8522 calling `getLine` can be easily read and understood even by people not
8523 fluent with the API:
8526 string getLine(Flag!"keepTerminator" keepTerminator)
8529 if (keepTerminator) ...
8533 auto line = getLine(Yes.keepTerminator);
8536 The structs `Yes` and `No` are provided as shorthand for
8537 `Flag!"Name".yes` and `Flag!"Name".no` and are preferred for brevity and
8538 readability. These convenience structs mean it is usually unnecessary and
8539 counterproductive to create an alias of a `Flag` as a way of avoiding typing
8540 out the full type while specifying the affirmative or negative options.
8542 Passing categorical data by means of unstructured `bool`
8543 parameters is classified under "simple-data coupling" by Steve
8544 McConnell in the $(LUCKY Code Complete) book, along with three other
8545 kinds of coupling. The author argues citing several studies that
8546 coupling has a negative effect on code quality. `Flag` offers a
8547 simple structuring method for passing yes/no flags to APIs.
8549 template Flag(string name) {
8554 When creating a value of type `Flag!"Name"`, use $(D
8555 Flag!"Name".no) for the negative option. When using a value
8556 of type `Flag!"Name"`, compare it against $(D
8557 Flag!"Name".no) or just `false` or `0`. */
8560 /** When creating a value of type `Flag!"Name"`, use $(D
8561 Flag!"Name".yes) for the affirmative option. When using a
8562 value of type `Flag!"Name"`, compare it against $(D
8574 assert(flag == Flag!"abc".no);
8575 assert(flag == No.abc);
8577 if (flag) assert(0);
8583 auto flag = Yes.abc;
8586 assert(flag == Yes.abc);
8587 if (!flag) assert(0);
8588 if (flag) {} else assert(0);
8592 Convenience names that allow using e.g. `Yes.encryption` instead of
8593 `Flag!"encryption".yes` and `No.encryption` instead of $(D
8594 Flag!"encryption".no).
8598 template opDispatch(string name)
8600 enum opDispatch = Flag!name.yes;
8603 //template yes(string name) { enum Flag!name yes = Flag!name.yes; }
8608 template opDispatch(string name)
8610 enum opDispatch = Flag!name.no;
8619 assert(flag == Flag!"abc".no);
8620 assert(flag == No.abc);
8622 if (flag) assert(0);
8628 auto flag = Yes.abc;
8631 assert(flag == Yes.abc);
8632 if (!flag) assert(0);
8633 if (flag) {} else assert(0);
8637 Detect whether an enum is of integral type and has only "flag" values
8638 (i.e. values with a bit count of exactly 1).
8639 Additionally, a zero value is allowed for compatibility with enums including
8642 template isBitFlagEnum(E)
8644 static if (is(E Base == enum) && isIntegral!Base)
8646 enum isBitFlagEnum = (E.min >= 0) &&
8648 static foreach (immutable flag; EnumMembers!E)
8652 if (value != 0) return false;
8659 enum isBitFlagEnum = false;
8664 @safe pure nothrow unittest
8675 static assert(isBitFlagEnum!A);
8678 /// Test an enum with default (consecutive) values
8679 @safe pure nothrow unittest
8689 static assert(!isBitFlagEnum!B);
8692 /// Test an enum with non-integral values
8693 @safe pure nothrow unittest
8701 static assert(!isBitFlagEnum!C);
8705 A typesafe structure for storing combinations of enum values.
8707 This template defines a simple struct to represent bitwise OR combinations of
8708 enum values. It can be used if all the enum values are integral constants with
8709 a bit count of at most 1, or if the `unsafe` parameter is explicitly set to
8711 This is much safer than using the enum itself to store
8712 the OR combination, which can produce surprising effects like this:
8720 // will throw SwitchError
8730 struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe)
8731 if (unsafe || isBitFlagEnum!(E))
8733 @safe @nogc pure nothrow:
8735 enum isBaseEnumType(T) = is(E == T);
8736 alias Base = OriginalType!E;
8738 static struct Negation
8740 @safe @nogc pure nothrow:
8744 // Prevent non-copy construction outside the module.
8759 if (allSatisfy!(isBaseEnumType, T))
8764 bool opCast(B: bool)() const
8769 Base opCast(B)() const
8770 if (isImplicitlyConvertible!(Base, B))
8775 Negation opUnary(string op)() const
8778 return Negation(~mValue);
8781 auto ref opAssign(T...)(T flags)
8782 if (allSatisfy!(isBaseEnumType, T))
8785 foreach (E flag; flags)
8792 auto ref opAssign(E flag)
8798 auto ref opOpAssign(string op: "|")(BitFlags flags)
8800 mValue |= flags.mValue;
8804 auto ref opOpAssign(string op: "&")(BitFlags flags)
8806 mValue &= flags.mValue;
8810 auto ref opOpAssign(string op: "|")(E flag)
8816 auto ref opOpAssign(string op: "&")(E flag)
8822 auto ref opOpAssign(string op: "&")(Negation negatedFlags)
8824 mValue &= negatedFlags.mValue;
8828 auto opBinary(string op)(BitFlags flags) const
8829 if (op == "|" || op == "&")
8831 BitFlags result = this;
8832 result.opOpAssign!op(flags);
8836 auto opBinary(string op)(E flag) const
8837 if (op == "|" || op == "&")
8839 BitFlags result = this;
8840 result.opOpAssign!op(flag);
8844 auto opBinary(string op: "&")(Negation negatedFlags) const
8846 BitFlags result = this;
8847 result.opOpAssign!op(negatedFlags);
8851 auto opBinaryRight(string op)(E flag) const
8852 if (op == "|" || op == "&")
8854 return opBinary!op(flag);
8857 bool opDispatch(string name)() const
8858 if (__traits(hasMember, E, name))
8860 enum e = __traits(getMember, E, name);
8861 return (mValue & e) == e;
8864 void opDispatch(string name)(bool set)
8865 if (__traits(hasMember, E, name))
8867 enum e = __traits(getMember, E, name);
8875 /// Set values with the | operator and test with &
8876 @safe @nogc pure nothrow unittest
8883 // A default constructed BitFlags has no value set
8884 immutable BitFlags!Enum flags_empty;
8885 assert(!flags_empty.A);
8887 // Value can be set with the | operator
8888 immutable flags_A = flags_empty | Enum.A;
8890 // and tested using property access
8893 // or the & operator
8894 assert(flags_A & Enum.A);
8896 assert(Enum.A & flags_A);
8899 /// A default constructed BitFlags has no value set
8900 @safe @nogc pure nothrow unittest
8910 immutable BitFlags!Enum flags_empty;
8911 assert(!(flags_empty & (Enum.A | Enum.B | Enum.C)));
8912 assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C));
8915 // BitFlags can be variadically initialized
8916 @safe @nogc pure nothrow unittest
8918 import std.traits : EnumMembers;
8927 // Values can also be set using property access
8928 BitFlags!Enum flags;
8930 assert(flags & Enum.A);
8932 assert(!(flags & Enum.A));
8934 // BitFlags can be variadically initialized
8935 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
8936 assert(flags_AB.A && flags_AB.B && !flags_AB.C);
8938 // You can use the EnumMembers template to set all flags
8939 immutable BitFlags!Enum flags_all = EnumMembers!Enum;
8940 assert(flags_all.A && flags_all.B && flags_all.C);
8943 /// Binary operations: subtracting and intersecting flags
8944 @safe @nogc pure nothrow unittest
8952 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
8953 immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C);
8955 // Use the ~ operator for subtracting flags
8956 immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A);
8957 assert(!flags_B.A && flags_B.B && !flags_B.C);
8959 // use & between BitFlags for intersection
8960 assert(flags_B == (flags_BC & flags_AB));
8963 /// All the binary operators work in their assignment version
8964 @safe @nogc pure nothrow unittest
8972 BitFlags!Enum flags_empty, temp, flags_AB;
8973 flags_AB = Enum.A | Enum.B;
8976 assert(temp == (flags_empty | flags_AB));
8980 assert(temp == (flags_empty | Enum.B));
8984 assert(temp == (flags_empty & flags_AB));
8988 assert(temp == (flags_empty & Enum.A));
8991 /// Conversion to bool and int
8992 @safe @nogc pure nothrow unittest
9000 BitFlags!Enum flags;
9002 // BitFlags with no value set evaluate to false
9005 // BitFlags with at least one value set evaluate to true
9009 // This can be useful to check intersection between BitFlags
9010 BitFlags!Enum flags_AB = Enum.A | Enum.B;
9011 assert(flags & flags_AB);
9012 assert(flags & Enum.A);
9014 // You can of course get you raw value out of flags
9015 auto value = cast(int) flags;
9016 assert(value == Enum.A);
9019 /// You need to specify the `unsafe` parameter for enums with custom values
9020 @safe @nogc pure nothrow unittest
9029 static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; }));
9030 BitFlags!(UnsafeEnum, Yes.unsafe) flags;
9032 // property access tests for exact match of unsafe enums
9034 assert(!flags.BC); // only B
9036 assert(flags.BC); // both B and C
9038 assert(!flags.BC); // only C
9040 // property access sets all bits of unsafe enum group
9043 assert(!flags.A && flags.B && flags.C);
9046 assert(flags.A && !flags.B && !flags.C);
9049 private enum false_(T) = false;
9053 Replaces all occurrences of `From` into `To`, in one or more types `T`. For
9054 example, `ReplaceType!(int, uint, Tuple!(int, float)[string])` yields
9055 `Tuple!(uint, float)[string]`. The types in which replacement is performed
9056 may be arbitrarily complex, including qualifiers, built-in type constructors
9057 (pointers, arrays, associative arrays, functions, and delegates), and template
9058 instantiations; replacement proceeds transitively through the type definition.
9059 However, member types in `struct`s or `class`es are not replaced because there
9060 are no ways to express the types resulting after replacement.
9062 This is an advanced type manipulation necessary e.g. for replacing the
9063 placeholder type `This` in $(REF Algebraic, std,variant).
9065 Returns: `ReplaceType` aliases itself to the type(s) that result after
9068 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T);
9074 is(ReplaceType!(int, string, int[]) == string[]) &&
9075 is(ReplaceType!(int, string, int[int]) == string[string]) &&
9076 is(ReplaceType!(int, string, const(int)[]) == const(string)[]) &&
9077 is(ReplaceType!(int, string, Tuple!(int[], float))
9078 == Tuple!(string[], float))
9083 Like $(LREF ReplaceType), but does not perform replacement in types for which
9084 `pred` evaluates to `true`.
9086 template ReplaceTypeUnless(alias pred, From, To, T...)
9090 static if (T.length == 1)
9092 static if (pred!(T[0]))
9093 alias ReplaceTypeUnless = T[0];
9094 else static if (is(T[0] == From))
9095 alias ReplaceTypeUnless = To;
9096 else static if (is(T[0] == const(U), U))
9097 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U));
9098 else static if (is(T[0] == immutable(U), U))
9099 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U));
9100 else static if (is(T[0] == shared(U), U))
9101 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U));
9102 else static if (is(T[0] == U*, U))
9104 static if (is(U == function))
9105 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]);
9107 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*;
9109 else static if (is(T[0] == delegate))
9111 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]);
9113 else static if (is(T[0] == function))
9115 static assert(0, "Function types not supported," ~
9116 " use a function pointer type instead of " ~ T[0].stringof);
9118 else static if (is(T[0] == U!V, alias U, V...))
9120 template replaceTemplateArgs(T...)
9122 static if (is(typeof(T[0]))) { // template argument is value or symbol
9123 static if (__traits(compiles, { alias _ = T[0]; }))
9125 alias replaceTemplateArgs = T[0];
9128 enum replaceTemplateArgs = T[0];
9130 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]);
9132 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V));
9134 else static if (is(T[0] == struct))
9135 // don't match with alias this struct below
9136 // https://issues.dlang.org/show_bug.cgi?id=15168
9137 alias ReplaceTypeUnless = T[0];
9138 else static if (is(T[0] == U[], U))
9139 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[];
9140 else static if (is(T[0] == U[n], U, size_t n))
9141 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n];
9142 else static if (is(T[0] == U[V], U, V))
9143 alias ReplaceTypeUnless =
9144 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)];
9146 alias ReplaceTypeUnless = T[0];
9148 else static if (T.length > 1)
9150 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]),
9151 ReplaceTypeUnless!(pred, From, To, T[1 .. $]));
9155 alias ReplaceTypeUnless = AliasSeq!();
9162 import std.traits : isArray;
9165 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) &&
9166 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) &&
9167 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[]))
9168 == Tuple!(string, int[]))
9172 private template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun)
9174 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun);
9175 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun));
9176 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return
9177 // tuple if Parameters!fun.length == 1
9181 enum linkage = functionLinkage!fun;
9182 alias attributes = functionAttributes!fun;
9183 enum variadicStyle = variadicFunctionStyle!fun;
9184 alias storageClasses = ParameterStorageClassTuple!fun;
9188 result ~= "extern(" ~ linkage ~ ") ";
9189 static if (attributes & FunctionAttribute.ref_)
9195 static if (is(fun == delegate))
9196 result ~= " delegate";
9198 result ~= " function";
9201 static foreach (i; 0 .. PX.length)
9205 if (storageClasses[i] & ParameterStorageClass.scope_)
9207 if (storageClasses[i] & ParameterStorageClass.in_)
9209 if (storageClasses[i] & ParameterStorageClass.out_)
9211 if (storageClasses[i] & ParameterStorageClass.ref_)
9213 if (storageClasses[i] & ParameterStorageClass.lazy_)
9215 if (storageClasses[i] & ParameterStorageClass.return_)
9216 result ~= "return ";
9218 result ~= "PX[" ~ i.stringof ~ "]";
9220 static if (variadicStyle == Variadic.typesafe)
9222 else static if (variadicStyle != Variadic.no)
9226 static if (attributes & FunctionAttribute.pure_)
9228 static if (attributes & FunctionAttribute.nothrow_)
9229 result ~= " nothrow";
9230 static if (attributes & FunctionAttribute.property)
9231 result ~= " @property";
9232 static if (attributes & FunctionAttribute.trusted)
9233 result ~= " @trusted";
9234 static if (attributes & FunctionAttribute.safe)
9236 static if (attributes & FunctionAttribute.nogc)
9238 static if (attributes & FunctionAttribute.system)
9239 result ~= " @system";
9240 static if (attributes & FunctionAttribute.const_)
9242 static if (attributes & FunctionAttribute.immutable_)
9243 result ~= " immutable";
9244 static if (attributes & FunctionAttribute.inout_)
9246 static if (attributes & FunctionAttribute.shared_)
9247 result ~= " shared";
9248 static if (attributes & FunctionAttribute.return_)
9249 result ~= " return";
9254 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";");
9259 template Test(Ts...)
9261 static if (Ts.length)
9263 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", "
9264 // ~Ts[1].stringof~", "~Ts[2].stringof~")");
9265 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]),
9266 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", "
9267 ~Ts[2].stringof~") == "
9268 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof);
9269 alias Test = Test!(Ts[4 .. $]);
9271 else alias Test = void;
9274 //import core.stdc.stdio;
9275 alias RefFun1 = ref int function(float, long);
9276 alias RefFun2 = ref float function(float, long);
9277 extern(C) int printf(const char*, ...) nothrow @nogc @system;
9278 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system;
9282 struct S1 { void foo() { x = 1; } }
9283 struct S2 { void bar() { x = 2; } }
9286 int, float, typeof(&func), float delegate(float),
9287 int, float, typeof(&printf), typeof(&floatPrintf),
9288 int, float, int function(out long, ...),
9289 float function(out long, ...),
9290 int, float, int function(ref float, long),
9291 float function(ref float, long),
9292 int, float, int function(ref int, long),
9293 float function(ref float, long),
9294 int, float, int function(out int, long),
9295 float function(out float, long),
9296 int, float, int function(lazy int, long),
9297 float function(lazy float, long),
9298 int, float, int function(out long, ref const int),
9299 float function(out long, ref const float),
9300 int, float, int function(in long, ref const int),
9301 float function(in long, ref const float),
9302 int, float, int function(long, in int),
9303 float function(long, in float),
9305 int, float, int, float,
9306 int, float, const int, const float,
9307 int, float, immutable int, immutable float,
9308 int, float, shared int, shared float,
9309 int, float, int*, float*,
9310 int, float, const(int)*, const(float)*,
9311 int, float, const(int*), const(float*),
9312 const(int)*, float, const(int*), const(float),
9313 int*, float, const(int)*, const(int)*,
9314 int, float, int[], float[],
9315 int, float, int[42], float[42],
9316 int, float, const(int)[42], const(float)[42],
9317 int, float, const(int[42]), const(float[42]),
9318 int, float, int[int], float[float],
9319 int, float, int[double], float[double],
9320 int, float, double[int], double[float],
9321 int, float, int function(float, long), float function(float, long),
9322 int, float, int function(float), float function(float),
9323 int, float, int function(float, int), float function(float, float),
9324 int, float, int delegate(float, long), float delegate(float, long),
9325 int, float, int delegate(float), float delegate(float),
9326 int, float, int delegate(float, int), float delegate(float, float),
9327 int, float, Unique!int, Unique!float,
9328 int, float, Tuple!(float, int), Tuple!(float, float),
9329 int, float, RefFun1, RefFun2,
9331 S1[1][][S1]* function(),
9332 S2[1][][S2]* function(),
9334 int[3] function( int[] arr, int[2] ...) pure @trusted,
9335 string[3] function(string[] arr, string[2] ...) pure @trusted,
9338 // https://issues.dlang.org/show_bug.cgi?id=15168
9339 static struct T1 { string s; alias s this; }
9340 static struct T2 { char[10] s; alias s this; }
9341 static struct T3 { string[string] s; alias s this; }
9342 alias Pass2 = Test!(
9343 ubyte, ubyte, T1, T1,
9344 ubyte, ubyte, T2, T2,
9345 ubyte, ubyte, T3, T3,
9349 // https://issues.dlang.org/show_bug.cgi?id=17116
9352 alias ConstDg = void delegate(float) const;
9353 alias B = void delegate(int) const;
9354 alias A = ReplaceType!(float, int, ConstDg);
9355 static assert(is(B == A));
9358 // https://issues.dlang.org/show_bug.cgi?id=19696
9361 static struct T(U) {}
9362 static struct S { T!int t; alias t this; }
9363 static assert(is(ReplaceType!(float, float, S) == S));
9366 // https://issues.dlang.org/show_bug.cgi?id=19697
9371 static assert(is(ReplaceType!(float, float, C)));
9374 // https://issues.dlang.org/show_bug.cgi?id=16132
9379 static assert(is(ReplaceType!(int, string, C) == C));
9382 // https://issues.dlang.org/show_bug.cgi?id=22325
9385 static struct Foo(alias f) {}
9386 static void bar() {}
9387 alias _ = ReplaceType!(int, int, Foo!bar);
9391 Ternary type with three truth values:
9394 $(LI `Ternary.yes` for `true`)
9395 $(LI `Ternary.no` for `false`)
9396 $(LI `Ternary.unknown` as an unknown state)
9399 Also known as trinary, trivalent, or trilean.
9402 $(HTTP en.wikipedia.org/wiki/Three-valued_logic,
9403 Three Valued Logic on Wikipedia)
9407 @safe @nogc nothrow pure:
9409 private ubyte value = 6;
9410 private static Ternary make(ubyte b)
9418 The possible states of the `Ternary`
9424 enum unknown = make(6);
9427 Construct and assign from a `bool`, receiving `no` for `false` and `yes`
9430 this(bool b) { value = b << 1; }
9433 void opAssign(bool b) { value = b << 1; }
9436 Construct a ternary value from another ternary value
9438 this(const Ternary b) { value = b.value; }
9441 $(TABLE Truth table for logical operations,
9442 $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`))
9443 $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`))
9444 $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`))
9445 $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
9446 $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`))
9447 $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`))
9448 $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
9449 $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
9450 $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
9451 $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`))
9454 Ternary opUnary(string s)() if (s == "~")
9456 return make((386 >> value) & 6);
9460 Ternary opBinary(string s)(Ternary rhs) if (s == "|")
9462 return make((25_512 >> (value + rhs.value)) & 6);
9466 Ternary opBinary(string s)(Ternary rhs) if (s == "&")
9468 return make((26_144 >> (value + rhs.value)) & 6);
9472 Ternary opBinary(string s)(Ternary rhs) if (s == "^")
9474 return make((26_504 >> (value + rhs.value)) & 6);
9478 Ternary opBinary(string s)(bool rhs)
9479 if (s == "|" || s == "&" || s == "^")
9481 return this.opBinary!s(Ternary(rhs));
9486 @safe @nogc nothrow pure
9490 assert(a == Ternary.unknown);
9492 assert(~Ternary.yes == Ternary.no);
9493 assert(~Ternary.no == Ternary.yes);
9494 assert(~Ternary.unknown == Ternary.unknown);
9497 @safe @nogc nothrow pure
9500 alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown;
9501 Ternary[27] truthTableAnd =
9514 Ternary[27] truthTableOr =
9527 Ternary[27] truthTableXor =
9540 for (auto i = 0; i != truthTableAnd.length; i += 3)
9542 assert((truthTableAnd[i] & truthTableAnd[i + 1])
9543 == truthTableAnd[i + 2]);
9544 assert((truthTableOr[i] | truthTableOr[i + 1])
9545 == truthTableOr[i + 2]);
9546 assert((truthTableXor[i] ^ truthTableXor[i + 1])
9547 == truthTableXor[i + 2]);
9551 assert(a == Ternary.unknown);
9552 static assert(!is(typeof({ if (a) {} })));
9553 assert(!is(typeof({ auto b = Ternary(3); })));
9555 assert(a == Ternary.yes);
9557 assert(a == Ternary.no);
9558 a = Ternary.unknown;
9559 assert(a == Ternary.unknown);
9563 assert(~Ternary.yes == Ternary.no);
9564 assert(~Ternary.no == Ternary.yes);
9565 assert(~Ternary.unknown == Ternary.unknown);
9568 @safe @nogc nothrow pure
9571 Ternary a = Ternary(true);
9572 assert(a == Ternary.yes);
9573 assert((a & false) == Ternary.no);
9574 assert((a | false) == Ternary.yes);
9575 assert((a ^ true) == Ternary.no);
9576 assert((a ^ false) == Ternary.yes);
9579 // https://issues.dlang.org/show_bug.cgi?id=22511
9585 @disable this(this);
9586 this (ref return scope inout S rhs) inout
9592 Nullable!S s1 = S(1);
9594 assert(s2.get().b > s1.get().b);