]> git.ipfire.org Git - people/ms/gcc.git/blob - libphobos/src/std/typecons.d
d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[people/ms/gcc.git] / libphobos / src / std / typecons.d
1 // Written in the D programming language.
2
3 /**
4 This module implements a variety of type constructors, i.e., templates
5 that allow construction of new, useful general-purpose types.
6
7 $(SCRIPT inhibitQuickIndex = 1;)
8 $(DIVC quickindex,
9 $(BOOKTABLE,
10 $(TR $(TH Category) $(TH Symbols))
11 $(TR $(TD Tuple) $(TD
12 $(LREF isTuple)
13 $(LREF Tuple)
14 $(LREF tuple)
15 $(LREF reverse)
16 ))
17 $(TR $(TD Flags) $(TD
18 $(LREF BitFlags)
19 $(LREF isBitFlagEnum)
20 $(LREF Flag)
21 $(LREF No)
22 $(LREF Yes)
23 ))
24 $(TR $(TD Memory allocation) $(TD
25 $(LREF SafeRefCounted)
26 $(LREF safeRefCounted)
27 $(LREF RefCountedAutoInitialize)
28 $(LREF scoped)
29 $(LREF Unique)
30 ))
31 $(TR $(TD Code generation) $(TD
32 $(LREF AutoImplement)
33 $(LREF BlackHole)
34 $(LREF generateAssertTrap)
35 $(LREF generateEmptyFunction)
36 $(LREF WhiteHole)
37 ))
38 $(TR $(TD Nullable) $(TD
39 $(LREF Nullable)
40 $(LREF nullable)
41 $(LREF NullableRef)
42 $(LREF nullableRef)
43 ))
44 $(TR $(TD Proxies) $(TD
45 $(LREF Proxy)
46 $(LREF rebindable)
47 $(LREF Rebindable)
48 $(LREF ReplaceType)
49 $(LREF unwrap)
50 $(LREF wrap)
51 ))
52 $(TR $(TD Types) $(TD
53 $(LREF alignForSize)
54 $(LREF Ternary)
55 $(LREF Typedef)
56 $(LREF TypedefType)
57 $(LREF UnqualRef)
58 ))
59 ))
60
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),
66 Don Clugston,
67 Shin Fujishiro,
68 Kenji Hara
69 */
70 module std.typecons;
71
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;
76 import std.traits;
77 import std.internal.attributes : betterC;
78
79 /// Value tuples
80 @safe unittest
81 {
82 alias Coord = Tuple!(int, "x", int, "y", int, "z");
83 Coord c;
84 c[1] = 1; // access by index
85 c.z = 1; // access by given name
86 assert(c == Coord(0, 1, 1));
87
88 // names can be omitted, types can be mixed
89 alias DictEntry = Tuple!(string, int);
90 auto dict = DictEntry("seven", 7);
91
92 // element types can be inferred
93 assert(tuple(2, 3, 4)[1] == 3);
94 // type inference works with names too
95 auto tup = tuple!("x", "y", "z")(2, 3, 4);
96 assert(tup.y == 3);
97 }
98
99 /// Rebindable references to const and immutable objects
100 @safe unittest
101 {
102 class Widget
103 {
104 void foo() const @safe {}
105 }
106 const w1 = new Widget, w2 = new Widget;
107 w1.foo();
108 // w1 = w2 would not work; can't rebind const object
109
110 auto r = Rebindable!(const Widget)(w1);
111 // invoke method as if r were a Widget object
112 r.foo();
113 // rebind r to refer to another object
114 r = w2;
115 }
116
117 /**
118 Encapsulates unique ownership of a resource.
119
120 When a `Unique!T` goes out of scope it will call `destroy`
121 on the resource `T` that it manages, unless it is transferred.
122 One important consequence of `destroy` is that it will call the
123 destructor of the resource `T`. GC-managed references are not
124 guaranteed to be valid during a destructor call, but other members of
125 `T`, such as file handles or pointers to `malloc` memory, will
126 still be valid during the destructor call. This allows the resource
127 `T` to deallocate or clean up any non-GC resources.
128
129 If it is desirable to persist a `Unique!T` outside of its original
130 scope, then it can be transferred. The transfer can be explicit, by
131 calling `release`, or implicit, when returning Unique from a
132 function. The resource `T` can be a polymorphic class object or
133 instance of an interface, in which case Unique behaves polymorphically
134 too.
135
136 If `T` is a value type, then `Unique!T` will be implemented
137 as a reference to a `T`.
138 */
139 struct Unique(T)
140 {
141 /** Represents a reference to `T`. Resolves to `T*` if `T` is a value type. */
142 static if (is(T == class) || is(T == interface))
143 alias RefT = T;
144 else
145 alias RefT = T*;
146
147 public:
148 // Deferred in case we get some language support for checking uniqueness.
149 version (None)
150 /**
151 Allows safe construction of `Unique`. It creates the resource and
152 guarantees unique ownership of it (unless `T` publishes aliases of
153 `this`).
154 Note: Nested structs/classes cannot be created.
155 Params:
156 args = Arguments to pass to `T`'s constructor.
157 ---
158 static class C {}
159 auto u = Unique!(C).create();
160 ---
161 */
162 static Unique!T create(A...)(auto ref A args)
163 if (__traits(compiles, new T(args)))
164 {
165 Unique!T u;
166 u._p = new T(args);
167 return u;
168 }
169
170 /**
171 Constructor that takes an rvalue.
172 It will ensure uniqueness, as long as the rvalue
173 isn't just a view on an lvalue (e.g., a cast).
174 Typical usage:
175 ----
176 Unique!Foo f = new Foo;
177 ----
178 */
179 this(RefT p)
180 {
181 _p = p;
182 }
183 /**
184 Constructor that takes an lvalue. It nulls its source.
185 The nulling will ensure uniqueness as long as there
186 are no previous aliases to the source.
187 */
188 this(ref RefT p)
189 {
190 _p = p;
191 p = null;
192 assert(p is null);
193 }
194 /**
195 Constructor that takes a `Unique` of a type that is convertible to our type.
196
197 Typically used to transfer a `Unique` rvalue of derived type to
198 a `Unique` of base type.
199 Example:
200 ---
201 class C : Object {}
202
203 Unique!C uc = new C;
204 Unique!Object uo = uc.release;
205 ---
206 */
207 this(U)(Unique!U u)
208 if (is(u.RefT:RefT))
209 {
210 _p = u._p;
211 u._p = null;
212 }
213
214 /// Transfer ownership from a `Unique` of a type that is convertible to our type.
215 void opAssign(U)(Unique!U u)
216 if (is(u.RefT:RefT))
217 {
218 // first delete any resource we own
219 destroy(this);
220 _p = u._p;
221 u._p = null;
222 }
223
224 ~this()
225 {
226 if (_p !is null)
227 {
228 static if (is(T == class) || is(T == interface))
229 destroy(_p);
230 else
231 destroy(*_p);
232 _p = null;
233 }
234 }
235
236 /** Returns whether the resource exists. */
237 @property bool isEmpty() const
238 {
239 return _p is null;
240 }
241 /** Transfer ownership to a `Unique` rvalue. Nullifies the current contents.
242 Same as calling std.algorithm.move on it.
243 */
244 Unique release()
245 {
246 import std.algorithm.mutation : move;
247 return this.move;
248 }
249
250 /** Forwards member access to contents. */
251 mixin Proxy!_p;
252
253 /**
254 Postblit operator is undefined to prevent the cloning of `Unique` objects.
255 */
256 @disable this(this);
257
258 private:
259 RefT _p;
260 }
261
262 ///
263 @safe unittest
264 {
265 struct S
266 {
267 int i;
268 this(int i){this.i = i;}
269 }
270 Unique!S produce()
271 {
272 // Construct a unique instance of S on the heap
273 Unique!S ut = new S(5);
274 // Implicit transfer of ownership
275 return ut;
276 }
277 // Borrow a unique resource by ref
278 void increment(ref Unique!S ur)
279 {
280 ur.i++;
281 }
282 void consume(Unique!S u2)
283 {
284 assert(u2.i == 6);
285 // Resource automatically deleted here
286 }
287 Unique!S u1;
288 assert(u1.isEmpty);
289 u1 = produce();
290 assert(u1.i == 5);
291 increment(u1);
292 assert(u1.i == 6);
293 //consume(u1); // Error: u1 is not copyable
294 // Transfer ownership of the resource
295 consume(u1.release);
296 assert(u1.isEmpty);
297 }
298
299 @safe unittest
300 {
301 int i;
302 struct S
303 {
304 ~this()
305 {
306 // check context pointer still exists - dtor also called before GC frees struct
307 if (this.tupleof[0])
308 i++;
309 }
310 }
311 {
312 Unique!S u = new S;
313 }
314 assert(i == 1);
315 }
316
317 @system unittest
318 {
319 // test conversion to base ref
320 int deleted = 0;
321 class C
322 {
323 ~this(){deleted++;}
324 }
325 // constructor conversion
326 Unique!Object u = Unique!C(new C);
327 static assert(!__traits(compiles, {u = new C;}));
328 assert(!u.isEmpty);
329 destroy(u);
330 assert(deleted == 1);
331
332 Unique!C uc = new C;
333 static assert(!__traits(compiles, {Unique!Object uo = uc;}));
334 Unique!Object uo = new C;
335 // opAssign conversion, deleting uo resource first
336 uo = uc.release;
337 assert(uc.isEmpty);
338 assert(!uo.isEmpty);
339 assert(deleted == 2);
340 }
341
342 @system unittest
343 {
344 class Bar
345 {
346 ~this() { debug(Unique) writeln(" Bar destructor"); }
347 int val() const { return 4; }
348 }
349 alias UBar = Unique!(Bar);
350 UBar g(UBar u)
351 {
352 debug(Unique) writeln("inside g");
353 return u.release;
354 }
355 auto ub = UBar(new Bar);
356 assert(!ub.isEmpty);
357 assert(ub.val == 4);
358 static assert(!__traits(compiles, {auto ub3 = g(ub);}));
359 auto ub2 = g(ub.release);
360 assert(ub.isEmpty);
361 assert(!ub2.isEmpty);
362 }
363
364 @system unittest
365 {
366 interface Bar
367 {
368 int val() const;
369 }
370 class BarImpl : Bar
371 {
372 static int count;
373 this()
374 {
375 count++;
376 }
377 ~this()
378 {
379 count--;
380 }
381 int val() const { return 4; }
382 }
383 alias UBar = Unique!Bar;
384 UBar g(UBar u)
385 {
386 debug(Unique) writeln("inside g");
387 return u.release;
388 }
389 void consume(UBar u)
390 {
391 assert(u.val() == 4);
392 // Resource automatically deleted here
393 }
394 auto ub = UBar(new BarImpl);
395 assert(BarImpl.count == 1);
396 assert(!ub.isEmpty);
397 assert(ub.val == 4);
398 static assert(!__traits(compiles, {auto ub3 = g(ub);}));
399 auto ub2 = g(ub.release);
400 assert(ub.isEmpty);
401 assert(!ub2.isEmpty);
402 consume(ub2.release);
403 assert(BarImpl.count == 0);
404 }
405
406 @safe unittest
407 {
408 struct Foo
409 {
410 ~this() { }
411 int val() const { return 3; }
412 @disable this(this);
413 }
414 alias UFoo = Unique!(Foo);
415
416 UFoo f(UFoo u)
417 {
418 return u.release;
419 }
420
421 auto uf = UFoo(new Foo);
422 assert(!uf.isEmpty);
423 assert(uf.val == 3);
424 static assert(!__traits(compiles, {auto uf3 = f(uf);}));
425 auto uf2 = f(uf.release);
426 assert(uf.isEmpty);
427 assert(!uf2.isEmpty);
428 }
429
430 // ensure Unique behaves correctly through const access paths
431 @system unittest
432 {
433 struct Bar {int val;}
434 struct Foo
435 {
436 Unique!Bar bar = new Bar;
437 }
438
439 Foo foo;
440 foo.bar.val = 6;
441 const Foo* ptr = &foo;
442 static assert(is(typeof(ptr) == const(Foo*)));
443 static assert(is(typeof(ptr.bar) == const(Unique!Bar)));
444 static assert(is(typeof(ptr.bar.val) == const(int)));
445 assert(ptr.bar.val == 6);
446 foo.bar.val = 7;
447 assert(ptr.bar.val == 7);
448 }
449
450 // Used in Tuple.toString
451 private template sharedToString(alias field)
452 if (is(typeof(field) == shared))
453 {
454 static immutable sharedToString = typeof(field).stringof;
455 }
456
457 private template sharedToString(alias field)
458 if (!is(typeof(field) == shared))
459 {
460 alias sharedToString = field;
461 }
462
463 private enum bool distinctFieldNames(names...) = __traits(compiles,
464 {
465 static foreach (__name; names)
466 static if (is(typeof(__name) : string))
467 mixin("enum int " ~ __name ~ " = 0;");
468 });
469
470 @safe unittest
471 {
472 static assert(!distinctFieldNames!(string, "abc", string, "abc"));
473 static assert(distinctFieldNames!(string, "abc", int, "abd"));
474 static assert(!distinctFieldNames!(int, "abc", string, "abd", int, "abc"));
475 // https://issues.dlang.org/show_bug.cgi?id=19240
476 static assert(!distinctFieldNames!(int, "int"));
477 }
478
479
480 // Parse (type,name) pairs (FieldSpecs) out of the specified
481 // arguments. Some fields would have name, others not.
482 private template parseSpecs(Specs...)
483 {
484 static if (Specs.length == 0)
485 {
486 alias parseSpecs = AliasSeq!();
487 }
488 else static if (is(Specs[0]))
489 {
490 static if (is(typeof(Specs[1]) : string))
491 {
492 alias parseSpecs =
493 AliasSeq!(FieldSpec!(Specs[0 .. 2]),
494 parseSpecs!(Specs[2 .. $]));
495 }
496 else
497 {
498 alias parseSpecs =
499 AliasSeq!(FieldSpec!(Specs[0]),
500 parseSpecs!(Specs[1 .. $]));
501 }
502 }
503 else
504 {
505 static assert(0, "Attempted to instantiate Tuple with an "
506 ~"invalid argument: "~ Specs[0].stringof);
507 }
508 }
509
510 private template FieldSpec(T, string s = "")
511 {
512 alias Type = T;
513 alias name = s;
514 }
515
516 // Used with staticMap.
517 private alias extractType(alias spec) = spec.Type;
518 private alias extractName(alias spec) = spec.name;
519 private template expandSpec(alias spec)
520 {
521 static if (spec.name.length == 0)
522 alias expandSpec = AliasSeq!(spec.Type);
523 else
524 alias expandSpec = AliasSeq!(spec.Type, spec.name);
525 }
526
527
528 private enum areCompatibleTuples(Tup1, Tup2, string op) =
529 isTuple!(OriginalType!Tup2) && Tup1.Types.length == Tup2.Types.length && is(typeof(
530 (ref Tup1 tup1, ref Tup2 tup2)
531 {
532 static foreach (i; 0 .. Tup1.Types.length)
533 {{
534 auto lhs = typeof(tup1.field[i]).init;
535 auto rhs = typeof(tup2.field[i]).init;
536 static if (op == "=")
537 lhs = rhs;
538 else
539 auto result = mixin("lhs "~op~" rhs");
540 }}
541 }));
542
543 private enum areBuildCompatibleTuples(Tup1, Tup2) =
544 isTuple!Tup2 && Tup1.Types.length == Tup2.Types.length && is(typeof(
545 {
546 static foreach (i; 0 .. Tup1.Types.length)
547 static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i]));
548 }));
549
550 // Returns `true` iff a `T` can be initialized from a `U`.
551 private enum isBuildable(T, U) = is(typeof(
552 {
553 U u = U.init;
554 T t = u;
555 }));
556 // Helper for partial instantiation
557 private template isBuildableFrom(U)
558 {
559 enum isBuildableFrom(T) = isBuildable!(T, U);
560 }
561
562
563 /**
564 _Tuple of values, for example $(D Tuple!(int, string)) is a record that
565 stores an `int` and a `string`. `Tuple` can be used to bundle
566 values together, notably when returning multiple values from a
567 function. If `obj` is a `Tuple`, the individual members are
568 accessible with the syntax `obj[0]` for the first field, `obj[1]`
569 for the second, and so on.
570
571 See_Also: $(LREF tuple).
572
573 Params:
574 Specs = A list of types (and optionally, member names) that the `Tuple` contains.
575 */
576 template Tuple(Specs...)
577 if (distinctFieldNames!(Specs))
578 {
579 import std.meta : staticMap;
580
581 alias fieldSpecs = parseSpecs!Specs;
582
583 // Generates named fields as follows:
584 // alias name_0 = Identity!(field[0]);
585 // alias name_1 = Identity!(field[1]);
586 // :
587 // NOTE: field[k] is an expression (which yields a symbol of a
588 // variable) and can't be aliased directly.
589 enum injectNamedFields = ()
590 {
591 string decl = "";
592 static foreach (i, val; fieldSpecs)
593 {{
594 immutable si = i.stringof;
595 decl ~= "alias _" ~ si ~ " = Identity!(field[" ~ si ~ "]);";
596 if (val.name.length != 0)
597 {
598 decl ~= "alias " ~ val.name ~ " = _" ~ si ~ ";";
599 }
600 }}
601 return decl;
602 };
603
604 // Returns Specs for a subtuple this[from .. to] preserving field
605 // names if any.
606 alias sliceSpecs(size_t from, size_t to) =
607 staticMap!(expandSpec, fieldSpecs[from .. to]);
608
609 struct Tuple
610 {
611 /**
612 * The types of the `Tuple`'s components.
613 */
614 alias Types = staticMap!(extractType, fieldSpecs);
615
616 private alias _Fields = Specs;
617
618 ///
619 static if (Specs.length == 0) @safe unittest
620 {
621 import std.meta : AliasSeq;
622 alias Fields = Tuple!(int, "id", string, float);
623 static assert(is(Fields.Types == AliasSeq!(int, string, float)));
624 }
625
626 /**
627 * The names of the `Tuple`'s components. Unnamed fields have empty names.
628 */
629 alias fieldNames = staticMap!(extractName, fieldSpecs);
630
631 ///
632 static if (Specs.length == 0) @safe unittest
633 {
634 import std.meta : AliasSeq;
635 alias Fields = Tuple!(int, "id", string, float);
636 static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
637 }
638
639 /**
640 * Use `t.expand` for a `Tuple` `t` to expand it into its
641 * components. The result of `expand` acts as if the `Tuple`'s components
642 * were listed as a list of values. (Ordinarily, a `Tuple` acts as a
643 * single value.)
644 */
645 Types expand;
646 mixin(injectNamedFields());
647
648 ///
649 static if (Specs.length == 0) @safe unittest
650 {
651 auto t1 = tuple(1, " hello ", 'a');
652 assert(t1.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`);
653
654 void takeSeveralTypes(int n, string s, bool b)
655 {
656 assert(n == 4 && s == "test" && b == false);
657 }
658
659 auto t2 = tuple(4, "test", false);
660 //t.expand acting as a list of values
661 takeSeveralTypes(t2.expand);
662 }
663
664 static if (is(Specs))
665 {
666 // This is mostly to make t[n] work.
667 alias expand this;
668 }
669 else
670 {
671 @property
672 ref inout(Tuple!Types) _Tuple_super() inout @trusted
673 {
674 static foreach (i; 0 .. Types.length) // Rely on the field layout
675 {
676 static assert(typeof(return).init.tupleof[i].offsetof ==
677 expand[i].offsetof);
678 }
679 return *cast(typeof(return)*) &(field[0]);
680 }
681 // This is mostly to make t[n] work.
682 alias _Tuple_super this;
683 }
684
685 // backwards compatibility
686 alias field = expand;
687
688 /**
689 * Constructor taking one value for each field.
690 *
691 * Params:
692 * values = A list of values that are either the same
693 * types as those given by the `Types` field
694 * of this `Tuple`, or can implicitly convert
695 * to those types. They must be in the same
696 * order as they appear in `Types`.
697 */
698 static if (Types.length > 0)
699 {
700 this(Types values)
701 {
702 field[] = values[];
703 }
704 }
705
706 ///
707 static if (Specs.length == 0) @safe unittest
708 {
709 alias ISD = Tuple!(int, string, double);
710 auto tup = ISD(1, "test", 3.2);
711 assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`);
712 }
713
714 /**
715 * Constructor taking a compatible array.
716 *
717 * Params:
718 * values = A compatible static array to build the `Tuple` from.
719 * Array slices are not supported.
720 */
721 this(U, size_t n)(U[n] values)
722 if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))
723 {
724 static foreach (i; 0 .. Types.length)
725 {
726 field[i] = values[i];
727 }
728 }
729
730 ///
731 static if (Specs.length == 0) @safe unittest
732 {
733 int[2] ints;
734 Tuple!(int, int) t = ints;
735 }
736
737 /**
738 * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible
739 * $(B iff) they are both of the same length, and, for each type `T` on the
740 * left-hand side, the corresponding type `U` on the right-hand side can
741 * implicitly convert to `T`.
742 *
743 * Params:
744 * another = A compatible `Tuple` to build from. Its type must be
745 * compatible with the target `Tuple`'s type.
746 */
747 this(U)(U another)
748 if (areBuildCompatibleTuples!(typeof(this), U))
749 {
750 field[] = another.field[];
751 }
752
753 ///
754 static if (Specs.length == 0) @safe unittest
755 {
756 alias IntVec = Tuple!(int, int, int);
757 alias DubVec = Tuple!(double, double, double);
758
759 IntVec iv = tuple(1, 1, 1);
760
761 //Ok, int can implicitly convert to double
762 DubVec dv = iv;
763 //Error: double cannot implicitly convert to int
764 //IntVec iv2 = dv;
765 }
766
767 /**
768 * Comparison for equality. Two `Tuple`s are considered equal
769 * $(B iff) they fulfill the following criteria:
770 *
771 * $(UL
772 * $(LI Each `Tuple` is the same length.)
773 * $(LI For each type `T` on the left-hand side and each type
774 * `U` on the right-hand side, values of type `T` can be
775 * compared with values of type `U`.)
776 * $(LI For each value `v1` on the left-hand side and each value
777 * `v2` on the right-hand side, the expression `v1 == v2` is
778 * true.))
779 *
780 * Params:
781 * rhs = The `Tuple` to compare against. It must meeting the criteria
782 * for comparison between `Tuple`s.
783 *
784 * Returns:
785 * true if both `Tuple`s are equal, otherwise false.
786 */
787 bool opEquals(R)(R rhs)
788 if (areCompatibleTuples!(typeof(this), R, "=="))
789 {
790 return field[] == rhs.field[];
791 }
792
793 /// ditto
794 bool opEquals(R)(R rhs) const
795 if (areCompatibleTuples!(typeof(this), R, "=="))
796 {
797 return field[] == rhs.field[];
798 }
799
800 /// ditto
801 bool opEquals(R...)(auto ref R rhs)
802 if (R.length > 1 && areCompatibleTuples!(typeof(this), Tuple!R, "=="))
803 {
804 static foreach (i; 0 .. Types.length)
805 if (field[i] != rhs[i])
806 return false;
807
808 return true;
809 }
810
811 ///
812 static if (Specs.length == 0) @safe unittest
813 {
814 Tuple!(int, string) t1 = tuple(1, "test");
815 Tuple!(double, string) t2 = tuple(1.0, "test");
816 //Ok, int can be compared with double and
817 //both have a value of 1
818 assert(t1 == t2);
819 }
820
821 /**
822 * Comparison for ordering.
823 *
824 * Params:
825 * rhs = The `Tuple` to compare against. It must meet the criteria
826 * for comparison between `Tuple`s.
827 *
828 * Returns:
829 * For any values `v1` contained by the left-hand side tuple and any
830 * values `v2` contained by the right-hand side:
831 *
832 * 0 if `v1 == v2` for all members or the following value for the
833 * first position were the mentioned criteria is not satisfied:
834 *
835 * $(UL
836 * $(LI NaN, in case one of the operands is a NaN.)
837 * $(LI A negative number if the expression `v1 < v2` is true.)
838 * $(LI A positive number if the expression `v1 > v2` is true.))
839 */
840 auto opCmp(R)(R rhs)
841 if (areCompatibleTuples!(typeof(this), R, "<"))
842 {
843 static foreach (i; 0 .. Types.length)
844 {
845 if (field[i] != rhs.field[i])
846 {
847 import std.math.traits : isNaN;
848 static if (isFloatingPoint!(Types[i]))
849 {
850 if (isNaN(field[i]))
851 return float.nan;
852 }
853 static if (isFloatingPoint!(typeof(rhs.field[i])))
854 {
855 if (isNaN(rhs.field[i]))
856 return float.nan;
857 }
858 static if (is(typeof(field[i].opCmp(rhs.field[i]))) &&
859 isFloatingPoint!(typeof(field[i].opCmp(rhs.field[i]))))
860 {
861 if (isNaN(field[i].opCmp(rhs.field[i])))
862 return float.nan;
863 }
864
865 return field[i] < rhs.field[i] ? -1 : 1;
866 }
867 }
868 return 0;
869 }
870
871 /// ditto
872 auto opCmp(R)(R rhs) const
873 if (areCompatibleTuples!(typeof(this), R, "<"))
874 {
875 static foreach (i; 0 .. Types.length)
876 {
877 if (field[i] != rhs.field[i])
878 {
879 import std.math.traits : isNaN;
880 static if (isFloatingPoint!(Types[i]))
881 {
882 if (isNaN(field[i]))
883 return float.nan;
884 }
885 static if (isFloatingPoint!(typeof(rhs.field[i])))
886 {
887 if (isNaN(rhs.field[i]))
888 return float.nan;
889 }
890 static if (is(typeof(field[i].opCmp(rhs.field[i]))) &&
891 isFloatingPoint!(typeof(field[i].opCmp(rhs.field[i]))))
892 {
893 if (isNaN(field[i].opCmp(rhs.field[i])))
894 return float.nan;
895 }
896
897 return field[i] < rhs.field[i] ? -1 : 1;
898 }
899 }
900 return 0;
901 }
902
903 /**
904 The first `v1` for which `v1 > v2` is true determines
905 the result. This could lead to unexpected behaviour.
906 */
907 static if (Specs.length == 0) @safe unittest
908 {
909 auto tup1 = tuple(1, 1, 1);
910 auto tup2 = tuple(1, 100, 100);
911 assert(tup1 < tup2);
912
913 //Only the first result matters for comparison
914 tup1[0] = 2;
915 assert(tup1 > tup2);
916 }
917
918 /**
919 Concatenate Tuples.
920 Tuple concatenation is only allowed if all named fields are distinct (no named field of this tuple occurs in `t`
921 and no named field of `t` occurs in this tuple).
922
923 Params:
924 t = The `Tuple` to concatenate with
925
926 Returns: A concatenation of this tuple and `t`
927 */
928 auto opBinary(string op, T)(auto ref T t)
929 if (op == "~" && !(is(T : U[], U) && isTuple!U))
930 {
931 static if (isTuple!T)
932 {
933 static assert(distinctFieldNames!(_Fields, T._Fields),
934 "Cannot concatenate tuples with duplicate fields: " ~ fieldNames.stringof ~
935 " - " ~ T.fieldNames.stringof);
936 return Tuple!(_Fields, T._Fields)(expand, t.expand);
937 }
938 else
939 {
940 return Tuple!(_Fields, T)(expand, t);
941 }
942 }
943
944 /// ditto
945 auto opBinaryRight(string op, T)(auto ref T t)
946 if (op == "~" && !(is(T : U[], U) && isTuple!U))
947 {
948 static if (isTuple!T)
949 {
950 static assert(distinctFieldNames!(_Fields, T._Fields),
951 "Cannot concatenate tuples with duplicate fields: " ~ T.stringof ~
952 " - " ~ fieldNames.fieldNames.stringof);
953 return Tuple!(T._Fields, _Fields)(t.expand, expand);
954 }
955 else
956 {
957 return Tuple!(T, _Fields)(t, expand);
958 }
959 }
960
961 /**
962 * Assignment from another `Tuple`.
963 *
964 * Params:
965 * rhs = The source `Tuple` to assign from. Each element of the
966 * source `Tuple` must be implicitly assignable to each
967 * respective element of the target `Tuple`.
968 */
969 ref Tuple opAssign(R)(auto ref R rhs)
970 if (areCompatibleTuples!(typeof(this), R, "="))
971 {
972 import std.algorithm.mutation : swap;
973
974 static if (is(R : Tuple!Types) && !__traits(isRef, rhs) && isTuple!R)
975 {
976 if (__ctfe)
977 {
978 // Cannot use swap at compile time
979 field[] = rhs.field[];
980 }
981 else
982 {
983 // Use swap-and-destroy to optimize rvalue assignment
984 swap!(Tuple!Types)(this, rhs);
985 }
986 }
987 else
988 {
989 // Do not swap; opAssign should be called on the fields.
990 field[] = rhs.field[];
991 }
992 return this;
993 }
994
995 /**
996 * Renames the elements of a $(LREF Tuple).
997 *
998 * `rename` uses the passed `names` and returns a new
999 * $(LREF Tuple) using these names, with the content
1000 * unchanged.
1001 * If fewer names are passed than there are members
1002 * of the $(LREF Tuple) then those trailing members are unchanged.
1003 * An empty string will remove the name for that member.
1004 * It is an compile-time error to pass more names than
1005 * there are members of the $(LREF Tuple).
1006 */
1007 ref rename(names...)() inout return
1008 if (names.length == 0 || allSatisfy!(isSomeString, typeof(names)))
1009 {
1010 import std.algorithm.comparison : equal;
1011 // to circumvent https://issues.dlang.org/show_bug.cgi?id=16418
1012 static if (names.length == 0 || equal([names], [fieldNames]))
1013 return this;
1014 else
1015 {
1016 enum nT = Types.length;
1017 enum nN = names.length;
1018 static assert(nN <= nT, "Cannot have more names than tuple members");
1019 alias allNames = AliasSeq!(names, fieldNames[nN .. $]);
1020
1021 import std.meta : Alias, aliasSeqOf;
1022
1023 template GetItem(size_t idx)
1024 {
1025 import std.array : empty;
1026 static if (idx < nT)
1027 alias GetItem = Alias!(Types[idx]);
1028 else static if (allNames[idx - nT].empty)
1029 alias GetItem = AliasSeq!();
1030 else
1031 alias GetItem = Alias!(allNames[idx - nT]);
1032 }
1033
1034 import std.range : roundRobin, iota;
1035 alias NewTupleT = Tuple!(staticMap!(GetItem, aliasSeqOf!(
1036 roundRobin(iota(nT), iota(nT, 2*nT)))));
1037 return *(() @trusted => cast(NewTupleT*)&this)();
1038 }
1039 }
1040
1041 ///
1042 static if (Specs.length == 0) @safe unittest
1043 {
1044 auto t0 = tuple(4, "hello");
1045
1046 auto t0Named = t0.rename!("val", "tag");
1047 assert(t0Named.val == 4);
1048 assert(t0Named.tag == "hello");
1049
1050 Tuple!(float, "dat", size_t[2], "pos") t1;
1051 t1.pos = [2, 1];
1052 auto t1Named = t1.rename!"height";
1053 t1Named.height = 3.4f;
1054 assert(t1Named.height == 3.4f);
1055 assert(t1Named.pos == [2, 1]);
1056 t1Named.rename!"altitude".altitude = 5;
1057 assert(t1Named.height == 5);
1058
1059 Tuple!(int, "a", int, int, "c") t2;
1060 t2 = tuple(3,4,5);
1061 auto t2Named = t2.rename!("", "b");
1062 // "a" no longer has a name
1063 static assert(!__traits(hasMember, typeof(t2Named), "a"));
1064 assert(t2Named[0] == 3);
1065 assert(t2Named.b == 4);
1066 assert(t2Named.c == 5);
1067
1068 // not allowed to specify more names than the tuple has members
1069 static assert(!__traits(compiles, t2.rename!("a","b","c","d")));
1070
1071 // use it in a range pipeline
1072 import std.range : iota, zip;
1073 import std.algorithm.iteration : map, sum;
1074 auto res = zip(iota(1, 4), iota(10, 13))
1075 .map!(t => t.rename!("a", "b"))
1076 .map!(t => t.a * t.b)
1077 .sum;
1078 assert(res == 68);
1079
1080 const tup = Tuple!(int, "a", int, "b")(2, 3);
1081 const renamed = tup.rename!("c", "d");
1082 assert(renamed.c + renamed.d == 5);
1083 }
1084
1085 /**
1086 * Overload of $(LREF _rename) that takes an associative array
1087 * `translate` as a template parameter, where the keys are
1088 * either the names or indices of the members to be changed
1089 * and the new names are the corresponding values.
1090 * Every key in `translate` must be the name of a member of the
1091 * $(LREF tuple).
1092 * The same rules for empty strings apply as for the variadic
1093 * template overload of $(LREF _rename).
1094 */
1095 ref rename(alias translate)() inout
1096 if (is(typeof(translate) : V[K], V, K) && isSomeString!V &&
1097 (isSomeString!K || is(K : size_t)))
1098 {
1099 import std.meta : aliasSeqOf;
1100 import std.range : ElementType;
1101 static if (isSomeString!(ElementType!(typeof(translate.keys))))
1102 {
1103 {
1104 import std.conv : to;
1105 import std.algorithm.iteration : filter;
1106 import std.algorithm.searching : canFind;
1107 enum notFound = translate.keys
1108 .filter!(k => fieldNames.canFind(k) == -1);
1109 static assert(notFound.empty, "Cannot find members "
1110 ~ notFound.to!string ~ " in type "
1111 ~ typeof(this).stringof);
1112 }
1113 return this.rename!(aliasSeqOf!(
1114 {
1115 import std.array : empty;
1116 auto names = [fieldNames];
1117 foreach (ref n; names)
1118 if (!n.empty)
1119 if (auto p = n in translate)
1120 n = *p;
1121 return names;
1122 }()));
1123 }
1124 else
1125 {
1126 {
1127 import std.algorithm.iteration : filter;
1128 import std.conv : to;
1129 enum invalid = translate.keys.
1130 filter!(k => k < 0 || k >= this.length);
1131 static assert(invalid.empty, "Indices " ~ invalid.to!string
1132 ~ " are out of bounds for tuple with length "
1133 ~ this.length.to!string);
1134 }
1135 return this.rename!(aliasSeqOf!(
1136 {
1137 auto names = [fieldNames];
1138 foreach (k, v; translate)
1139 names[k] = v;
1140 return names;
1141 }()));
1142 }
1143 }
1144
1145 ///
1146 static if (Specs.length == 0) @safe unittest
1147 {
1148 //replacing names by their current name
1149
1150 Tuple!(float, "dat", size_t[2], "pos") t1;
1151 t1.pos = [2, 1];
1152 auto t1Named = t1.rename!(["dat": "height"]);
1153 t1Named.height = 3.4;
1154 assert(t1Named.pos == [2, 1]);
1155 t1Named.rename!(["height": "altitude"]).altitude = 5;
1156 assert(t1Named.height == 5);
1157
1158 Tuple!(int, "a", int, "b") t2;
1159 t2 = tuple(3, 4);
1160 auto t2Named = t2.rename!(["a": "b", "b": "c"]);
1161 assert(t2Named.b == 3);
1162 assert(t2Named.c == 4);
1163
1164 const t3 = Tuple!(int, "a", int, "b")(3, 4);
1165 const t3Named = t3.rename!(["a": "b", "b": "c"]);
1166 assert(t3Named.b == 3);
1167 assert(t3Named.c == 4);
1168 }
1169
1170 ///
1171 static if (Specs.length == 0) @system unittest
1172 {
1173 //replace names by their position
1174
1175 Tuple!(float, "dat", size_t[2], "pos") t1;
1176 t1.pos = [2, 1];
1177 auto t1Named = t1.rename!([0: "height"]);
1178 t1Named.height = 3.4;
1179 assert(t1Named.pos == [2, 1]);
1180 t1Named.rename!([0: "altitude"]).altitude = 5;
1181 assert(t1Named.height == 5);
1182
1183 Tuple!(int, "a", int, "b", int, "c") t2;
1184 t2 = tuple(3, 4, 5);
1185 auto t2Named = t2.rename!([0: "c", 2: "a"]);
1186 assert(t2Named.a == 5);
1187 assert(t2Named.b == 4);
1188 assert(t2Named.c == 3);
1189 }
1190
1191 static if (Specs.length == 0) @system unittest
1192 {
1193 //check that empty translations work fine
1194 enum string[string] a0 = null;
1195 enum string[int] a1 = null;
1196 Tuple!(float, "a", float, "b") t0;
1197
1198 auto t1 = t0.rename!a0;
1199
1200 t1.a = 3;
1201 t1.b = 4;
1202 auto t2 = t0.rename!a1;
1203 t2.a = 3;
1204 t2.b = 4;
1205 auto t3 = t0.rename;
1206 t3.a = 3;
1207 t3.b = 4;
1208 }
1209
1210 /**
1211 * Takes a slice by-reference of this `Tuple`.
1212 *
1213 * Params:
1214 * from = A `size_t` designating the starting position of the slice.
1215 * to = A `size_t` designating the ending position (exclusive) of the slice.
1216 *
1217 * Returns:
1218 * A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original.
1219 * It has the same types and values as the range `[from, to$(RPAREN)` in
1220 * the original.
1221 */
1222 @property
1223 ref inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout @trusted
1224 if (from <= to && to <= Types.length)
1225 {
1226 static assert(
1227 (typeof(this).alignof % typeof(return).alignof == 0) &&
1228 (expand[from].offsetof % typeof(return).alignof == 0),
1229 "Slicing by reference is impossible because of an alignment mistmatch" ~
1230 " (See https://issues.dlang.org/show_bug.cgi?id=15645).");
1231
1232 return *cast(typeof(return)*) &(field[from]);
1233 }
1234
1235 ///
1236 static if (Specs.length == 0) @safe unittest
1237 {
1238 Tuple!(int, string, float, double) a;
1239 a[1] = "abc";
1240 a[2] = 4.5;
1241 auto s = a.slice!(1, 3);
1242 static assert(is(typeof(s) == Tuple!(string, float)));
1243 assert(s[0] == "abc" && s[1] == 4.5);
1244
1245 // https://issues.dlang.org/show_bug.cgi?id=15645
1246 Tuple!(int, short, bool, double) b;
1247 static assert(!__traits(compiles, b.slice!(2, 4)));
1248 }
1249
1250 /**
1251 Creates a hash of this `Tuple`.
1252
1253 Returns:
1254 A `size_t` representing the hash of this `Tuple`.
1255 */
1256 size_t toHash() const nothrow @safe
1257 {
1258 size_t h = 0;
1259 static foreach (i, T; Types)
1260 {{
1261 static if (__traits(compiles, h = .hashOf(field[i])))
1262 const k = .hashOf(field[i]);
1263 else
1264 {
1265 // Workaround for when .hashOf is not both @safe and nothrow.
1266 static if (is(T : shared U, U) && __traits(compiles, (U* a) nothrow @safe => .hashOf(*a))
1267 && !__traits(hasMember, T, "toHash"))
1268 // BUG: Improperly casts away `shared`!
1269 const k = .hashOf(*(() @trusted => cast(U*) &field[i])());
1270 else
1271 // BUG: Improperly casts away `shared`!
1272 const k = typeid(T).getHash((() @trusted => cast(const void*) &field[i])());
1273 }
1274 static if (i == 0)
1275 h = k;
1276 else
1277 // As in boost::hash_combine
1278 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine
1279 h ^= k + 0x9e3779b9 + (h << 6) + (h >>> 2);
1280 }}
1281 return h;
1282 }
1283
1284 /**
1285 * Converts to string.
1286 *
1287 * Returns:
1288 * The string representation of this `Tuple`.
1289 */
1290 string toString()() const
1291 {
1292 import std.array : appender;
1293 auto app = appender!string();
1294 this.toString((const(char)[] chunk) => app ~= chunk);
1295 return app.data;
1296 }
1297
1298 import std.format.spec : FormatSpec;
1299
1300 /**
1301 * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`.
1302 *
1303 * $(TABLE2 Formats supported by Tuple,
1304 * $(THEAD Format, Description)
1305 * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.))
1306 * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`$(COMMA) so
1307 * it may contain as many formats as the `Tuple` has fields.))
1308 * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format$(COMMA) that is applied
1309 * on all fields of the `Tuple`. The inner format must be compatible to all
1310 * of them.)))
1311 *
1312 * Params:
1313 * sink = A `char` accepting delegate
1314 * fmt = A $(REF FormatSpec, std,format)
1315 */
1316 void toString(DG)(scope DG sink) const
1317 {
1318 auto f = FormatSpec!char();
1319 toString(sink, f);
1320 }
1321
1322 /// ditto
1323 void toString(DG, Char)(scope DG sink, scope const ref FormatSpec!Char fmt) const
1324 {
1325 import std.format : format, FormatException;
1326 import std.format.write : formattedWrite;
1327 import std.range : only;
1328 if (fmt.nested)
1329 {
1330 if (fmt.sep)
1331 {
1332 foreach (i, Type; Types)
1333 {
1334 static if (i > 0)
1335 {
1336 sink(fmt.sep);
1337 }
1338 // TODO: Change this once formattedWrite() works for shared objects.
1339 static if (is(Type == class) && is(Type == shared))
1340 {
1341 sink(Type.stringof);
1342 }
1343 else
1344 {
1345 formattedWrite(sink, fmt.nested, this.field[i]);
1346 }
1347 }
1348 }
1349 else
1350 {
1351 formattedWrite(sink, fmt.nested, staticMap!(sharedToString, this.expand));
1352 }
1353 }
1354 else if (fmt.spec == 's')
1355 {
1356 enum header = Unqual!(typeof(this)).stringof ~ "(",
1357 footer = ")",
1358 separator = ", ";
1359 sink(header);
1360 foreach (i, Type; Types)
1361 {
1362 static if (i > 0)
1363 {
1364 sink(separator);
1365 }
1366 // TODO: Change this once format() works for shared objects.
1367 static if (is(Type == class) && is(Type == shared))
1368 {
1369 sink(Type.stringof);
1370 }
1371 else
1372 {
1373 sink(format!("%(%s%)")(only(field[i])));
1374 }
1375 }
1376 sink(footer);
1377 }
1378 else
1379 {
1380 const spec = fmt.spec;
1381 throw new FormatException(
1382 "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~
1383 Unqual!(typeof(this)).stringof ~ "', not '%" ~ spec ~ "'.");
1384 }
1385 }
1386
1387 ///
1388 static if (Specs.length == 0) @safe unittest
1389 {
1390 import std.format : format;
1391
1392 Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ];
1393
1394 // Default format
1395 assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`);
1396
1397 // One Format for each individual component
1398 assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`);
1399 assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`);
1400
1401 // One Format for all components
1402 assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`);
1403
1404 // Array of Tuples
1405 assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`);
1406 }
1407
1408 ///
1409 static if (Specs.length == 0) @safe unittest
1410 {
1411 import std.exception : assertThrown;
1412 import std.format : format, FormatException;
1413
1414 // Error: %( %) missing.
1415 assertThrown!FormatException(
1416 format("%d, %f", tuple(1, 2.0)) == `1, 2.0`
1417 );
1418
1419 // Error: %( %| %) missing.
1420 assertThrown!FormatException(
1421 format("%d", tuple(1, 2)) == `1, 2`
1422 );
1423
1424 // Error: %d inadequate for double
1425 assertThrown!FormatException(
1426 format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0`
1427 );
1428 }
1429 }
1430 }
1431
1432 ///
1433 @safe unittest
1434 {
1435 Tuple!(int, int) point;
1436 // assign coordinates
1437 point[0] = 5;
1438 point[1] = 6;
1439 // read coordinates
1440 auto x = point[0];
1441 auto y = point[1];
1442 }
1443
1444 /**
1445 `Tuple` members can be named. It is legal to mix named and unnamed
1446 members. The method above is still applicable to all fields.
1447 */
1448 @safe unittest
1449 {
1450 alias Entry = Tuple!(int, "index", string, "value");
1451 Entry e;
1452 e.index = 4;
1453 e.value = "Hello";
1454 assert(e[1] == "Hello");
1455 assert(e[0] == 4);
1456 }
1457
1458 /**
1459 A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed
1460 fields, i.e. each naming imparts a separate type for the `Tuple`. Two
1461 `Tuple`s differing in naming only are still distinct, even though they
1462 might have the same structure.
1463 */
1464 @safe unittest
1465 {
1466 Tuple!(int, "x", int, "y") point1;
1467 Tuple!(int, int) point2;
1468 assert(!is(typeof(point1) == typeof(point2)));
1469 }
1470
1471 /// Use tuples as ranges
1472 @safe unittest
1473 {
1474 import std.algorithm.iteration : sum;
1475 import std.range : only;
1476 auto t = tuple(1, 2);
1477 assert(t.expand.only.sum == 3);
1478 }
1479
1480 // https://issues.dlang.org/show_bug.cgi?id=4582
1481 @safe unittest
1482 {
1483 static assert(!__traits(compiles, Tuple!(string, "id", int, "id")));
1484 static assert(!__traits(compiles, Tuple!(string, "str", int, "i", string, "str", float)));
1485 }
1486
1487 /// Concatenate tuples
1488 @safe unittest
1489 {
1490 import std.meta : AliasSeq;
1491 auto t = tuple(1, "2") ~ tuple(ushort(42), true);
1492 static assert(is(t.Types == AliasSeq!(int, string, ushort, bool)));
1493 assert(t[1] == "2");
1494 assert(t[2] == 42);
1495 assert(t[3] == true);
1496 }
1497
1498 // https://issues.dlang.org/show_bug.cgi?id=14637
1499 // tuple concat
1500 @safe unittest
1501 {
1502 auto t = tuple!"foo"(1.0) ~ tuple!"bar"("3");
1503 static assert(is(t.Types == AliasSeq!(double, string)));
1504 static assert(t.fieldNames == tuple("foo", "bar"));
1505 assert(t.foo == 1.0);
1506 assert(t.bar == "3");
1507 }
1508
1509 // https://issues.dlang.org/show_bug.cgi?id=18824
1510 // tuple concat
1511 @safe unittest
1512 {
1513 alias Type = Tuple!(int, string);
1514 Type[] arr;
1515 auto t = tuple(2, "s");
1516 // Test opBinaryRight
1517 arr = arr ~ t;
1518 // Test opBinary
1519 arr = t ~ arr;
1520 static assert(is(typeof(arr) == Type[]));
1521 immutable Type[] b;
1522 auto c = b ~ t;
1523 static assert(is(typeof(c) == immutable(Type)[]));
1524 }
1525
1526 // tuple concat
1527 @safe unittest
1528 {
1529 auto t = tuple!"foo"(1.0) ~ "3";
1530 static assert(is(t.Types == AliasSeq!(double, string)));
1531 assert(t.foo == 1.0);
1532 assert(t[1]== "3");
1533 }
1534
1535 // tuple concat
1536 @safe unittest
1537 {
1538 auto t = "2" ~ tuple!"foo"(1.0);
1539 static assert(is(t.Types == AliasSeq!(string, double)));
1540 assert(t.foo == 1.0);
1541 assert(t[0]== "2");
1542 }
1543
1544 // tuple concat
1545 @safe unittest
1546 {
1547 auto t = "2" ~ tuple!"foo"(1.0) ~ tuple(42, 3.0f) ~ real(1) ~ "a";
1548 static assert(is(t.Types == AliasSeq!(string, double, int, float, real, string)));
1549 assert(t.foo == 1.0);
1550 assert(t[0] == "2");
1551 assert(t[1] == 1.0);
1552 assert(t[2] == 42);
1553 assert(t[3] == 3.0f);
1554 assert(t[4] == 1.0);
1555 assert(t[5] == "a");
1556 }
1557
1558 // ensure that concatenation of tuples with non-distinct fields is forbidden
1559 @safe unittest
1560 {
1561 static assert(!__traits(compiles,
1562 tuple!("a")(0) ~ tuple!("a")("1")));
1563 static assert(!__traits(compiles,
1564 tuple!("a", "b")(0, 1) ~ tuple!("b", "a")("3", 1)));
1565 static assert(!__traits(compiles,
1566 tuple!("a")(0) ~ tuple!("b", "a")("3", 1)));
1567 static assert(!__traits(compiles,
1568 tuple!("a1", "a")(1.0, 0) ~ tuple!("a2", "a")("3", 0)));
1569 }
1570
1571 // Ensure that Tuple comparison with non-const opEquals works
1572 @safe unittest
1573 {
1574 static struct Bad
1575 {
1576 int a;
1577
1578 bool opEquals(Bad b)
1579 {
1580 return a == b.a;
1581 }
1582 }
1583
1584 auto t = Tuple!(int, Bad, string)(1, Bad(1), "asdf");
1585
1586 //Error: mutable method Bad.opEquals is not callable using a const object
1587 assert(t == AliasSeq!(1, Bad(1), "asdf"));
1588 }
1589
1590 // Ensure Tuple.toHash works
1591 @safe unittest
1592 {
1593 Tuple!(int, int) point;
1594 assert(point.toHash == typeof(point).init.toHash);
1595 assert(tuple(1, 2) != point);
1596 assert(tuple(1, 2) == tuple(1, 2));
1597 point[0] = 1;
1598 assert(tuple(1, 2) != point);
1599 point[1] = 2;
1600 assert(tuple(1, 2) == point);
1601 }
1602
1603 @safe @betterC unittest
1604 {
1605 auto t = tuple(1, 2);
1606 assert(t == tuple(1, 2));
1607 auto t3 = tuple(1, 'd');
1608 }
1609
1610 // https://issues.dlang.org/show_bug.cgi?id=20850
1611 // Assignment to enum tuple
1612 @safe unittest
1613 {
1614 enum T : Tuple!(int*) { a = T(null) }
1615 T t;
1616 t = T.a;
1617 }
1618
1619 // https://issues.dlang.org/show_bug.cgi?id=13663
1620 @safe unittest
1621 {
1622 auto t = tuple(real.nan);
1623 assert(!(t > t));
1624 assert(!(t < t));
1625 assert(!(t == t));
1626 }
1627
1628 @safe unittest
1629 {
1630 struct S
1631 {
1632 float opCmp(S s) { return float.nan; }
1633 bool opEquals(S s) { return false; }
1634 }
1635
1636 auto t = tuple(S());
1637 assert(!(t > t));
1638 assert(!(t < t));
1639 assert(!(t == t));
1640 }
1641
1642 // https://issues.dlang.org/show_bug.cgi?id=8015
1643 @safe unittest
1644 {
1645 struct MyStruct
1646 {
1647 string str;
1648 @property string toStr()
1649 {
1650 return str;
1651 }
1652 alias toStr this;
1653 }
1654
1655 Tuple!(MyStruct) t;
1656 }
1657
1658 /**
1659 Creates a copy of a $(LREF Tuple) with its fields in _reverse order.
1660
1661 Params:
1662 t = The `Tuple` to copy.
1663
1664 Returns:
1665 A new `Tuple`.
1666 */
1667 auto reverse(T)(T t)
1668 if (isTuple!T)
1669 {
1670 import std.meta : Reverse;
1671 // @@@BUG@@@ Cannot be an internal function due to forward reference issues.
1672
1673 // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple
1674 // return tuple(Reverse!(t.expand));
1675
1676 ReverseTupleType!T result;
1677 auto tup = t.expand;
1678 result.expand = Reverse!tup;
1679 return result;
1680 }
1681
1682 ///
1683 @safe unittest
1684 {
1685 auto tup = tuple(1, "2");
1686 assert(tup.reverse == tuple("2", 1));
1687 }
1688
1689 /* Get a Tuple type with the reverse specification of Tuple T. */
1690 private template ReverseTupleType(T)
1691 if (isTuple!T)
1692 {
1693 static if (is(T : Tuple!A, A...))
1694 alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A);
1695 }
1696
1697 /* Reverse the Specs of a Tuple. */
1698 private template ReverseTupleSpecs(T...)
1699 {
1700 static if (T.length > 1)
1701 {
1702 static if (is(typeof(T[$-1]) : string))
1703 {
1704 alias ReverseTupleSpecs = AliasSeq!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2]));
1705 }
1706 else
1707 {
1708 alias ReverseTupleSpecs = AliasSeq!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1]));
1709 }
1710 }
1711 else
1712 {
1713 alias ReverseTupleSpecs = T;
1714 }
1715 }
1716
1717 // ensure that internal Tuple unittests are compiled
1718 @safe unittest
1719 {
1720 Tuple!() t;
1721 }
1722
1723 @safe unittest
1724 {
1725 import std.conv;
1726 {
1727 Tuple!(int, "a", int, "b") nosh;
1728 static assert(nosh.length == 2);
1729 nosh.a = 5;
1730 nosh.b = 6;
1731 assert(nosh.a == 5);
1732 assert(nosh.b == 6);
1733 }
1734 {
1735 Tuple!(short, double) b;
1736 static assert(b.length == 2);
1737 b[1] = 5;
1738 auto a = Tuple!(int, real)(b);
1739 assert(a[0] == 0 && a[1] == 5);
1740 a = Tuple!(int, real)(1, 2);
1741 assert(a[0] == 1 && a[1] == 2);
1742 auto c = Tuple!(int, "a", double, "b")(a);
1743 assert(c[0] == 1 && c[1] == 2);
1744 }
1745 {
1746 Tuple!(int, real) nosh;
1747 nosh[0] = 5;
1748 nosh[1] = 0;
1749 assert(nosh[0] == 5 && nosh[1] == 0);
1750 assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string);
1751 Tuple!(int, int) yessh;
1752 nosh = yessh;
1753 }
1754 {
1755 class A {}
1756 Tuple!(int, shared A) nosh;
1757 nosh[0] = 5;
1758 assert(nosh[0] == 5 && nosh[1] is null);
1759 assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))");
1760 }
1761 {
1762 Tuple!(int, string) t;
1763 t[0] = 10;
1764 t[1] = "str";
1765 assert(t[0] == 10 && t[1] == "str");
1766 assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string);
1767 }
1768 {
1769 Tuple!(int, "a", double, "b") x;
1770 static assert(x.a.offsetof == x[0].offsetof);
1771 static assert(x.b.offsetof == x[1].offsetof);
1772 x.b = 4.5;
1773 x.a = 5;
1774 assert(x[0] == 5 && x[1] == 4.5);
1775 assert(x.a == 5 && x.b == 4.5);
1776 }
1777 // indexing
1778 {
1779 Tuple!(int, real) t;
1780 static assert(is(typeof(t[0]) == int));
1781 static assert(is(typeof(t[1]) == real));
1782 int* p0 = &t[0];
1783 real* p1 = &t[1];
1784 t[0] = 10;
1785 t[1] = -200.0L;
1786 assert(*p0 == t[0]);
1787 assert(*p1 == t[1]);
1788 }
1789 // slicing
1790 {
1791 Tuple!(int, "x", real, "y", double, "z", string) t;
1792 t[0] = 10;
1793 t[1] = 11;
1794 t[2] = 12;
1795 t[3] = "abc";
1796 auto a = t.slice!(0, 3);
1797 assert(a.length == 3);
1798 assert(a.x == t.x);
1799 assert(a.y == t.y);
1800 assert(a.z == t.z);
1801 auto b = t.slice!(2, 4);
1802 assert(b.length == 2);
1803 assert(b.z == t.z);
1804 assert(b[1] == t[3]);
1805 }
1806 // nesting
1807 {
1808 Tuple!(Tuple!(int, real), Tuple!(string, "s")) t;
1809 static assert(is(typeof(t[0]) == Tuple!(int, real)));
1810 static assert(is(typeof(t[1]) == Tuple!(string, "s")));
1811 static assert(is(typeof(t[0][0]) == int));
1812 static assert(is(typeof(t[0][1]) == real));
1813 static assert(is(typeof(t[1].s) == string));
1814 t[0] = tuple(10, 20.0L);
1815 t[1].s = "abc";
1816 assert(t[0][0] == 10);
1817 assert(t[0][1] == 20.0L);
1818 assert(t[1].s == "abc");
1819 }
1820 // non-POD
1821 {
1822 static struct S
1823 {
1824 int count;
1825 this(this) { ++count; }
1826 ~this() { --count; }
1827 void opAssign(S rhs) { count = rhs.count; }
1828 }
1829 Tuple!(S, S) ss;
1830 Tuple!(S, S) ssCopy = ss;
1831 assert(ssCopy[0].count == 1);
1832 assert(ssCopy[1].count == 1);
1833 ssCopy[1] = ssCopy[0];
1834 assert(ssCopy[1].count == 2);
1835 }
1836 // https://issues.dlang.org/show_bug.cgi?id=2800
1837 {
1838 static struct R
1839 {
1840 Tuple!(int, int) _front;
1841 @property ref Tuple!(int, int) front() return { return _front; }
1842 @property bool empty() { return _front[0] >= 10; }
1843 void popFront() { ++_front[0]; }
1844 }
1845 foreach (a; R())
1846 {
1847 static assert(is(typeof(a) == Tuple!(int, int)));
1848 assert(0 <= a[0] && a[0] < 10);
1849 assert(a[1] == 0);
1850 }
1851 }
1852 // Construction with compatible elements
1853 {
1854 auto t1 = Tuple!(int, double)(1, 1);
1855
1856 // https://issues.dlang.org/show_bug.cgi?id=8702
1857 auto t8702a = tuple(tuple(1));
1858 auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1));
1859 }
1860 // Construction with compatible tuple
1861 {
1862 Tuple!(int, int) x;
1863 x[0] = 10;
1864 x[1] = 20;
1865 Tuple!(int, "a", double, "b") y = x;
1866 assert(y.a == 10);
1867 assert(y.b == 20);
1868 // incompatible
1869 static assert(!__traits(compiles, Tuple!(int, int)(y)));
1870 }
1871 // https://issues.dlang.org/show_bug.cgi?id=6275
1872 {
1873 const int x = 1;
1874 auto t1 = tuple(x);
1875 alias T = Tuple!(const(int));
1876 auto t2 = T(1);
1877 }
1878 // https://issues.dlang.org/show_bug.cgi?id=9431
1879 {
1880 alias T = Tuple!(int[1][]);
1881 auto t = T([[10]]);
1882 }
1883 // https://issues.dlang.org/show_bug.cgi?id=7666
1884 {
1885 auto tup = tuple(1, "2");
1886 assert(tup.reverse == tuple("2", 1));
1887 }
1888 {
1889 Tuple!(int, "x", string, "y") tup = tuple(1, "2");
1890 auto rev = tup.reverse;
1891 assert(rev == tuple("2", 1));
1892 assert(rev.x == 1 && rev.y == "2");
1893 }
1894 {
1895 Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup;
1896 tup = tuple('a', 'b', 3, "4", 'c', cast(byte) 0x0D, 0.00);
1897 auto rev = tup.reverse;
1898 assert(rev == tuple(0.00, cast(byte) 0x0D, 'c', "4", 3, 'b', 'a'));
1899 assert(rev.x == 3 && rev.y == "4");
1900 }
1901 }
1902 @safe unittest
1903 {
1904 // opEquals
1905 {
1906 struct Equ1 { bool opEquals(Equ1) { return true; } }
1907 auto tm1 = tuple(Equ1.init);
1908 const tc1 = tuple(Equ1.init);
1909 static assert( is(typeof(tm1 == tm1)));
1910 static assert(!is(typeof(tm1 == tc1)));
1911 static assert(!is(typeof(tc1 == tm1)));
1912 static assert(!is(typeof(tc1 == tc1)));
1913
1914 struct Equ2 { bool opEquals(const Equ2) const { return true; } }
1915 auto tm2 = tuple(Equ2.init);
1916 const tc2 = tuple(Equ2.init);
1917 static assert( is(typeof(tm2 == tm2)));
1918 static assert( is(typeof(tm2 == tc2)));
1919 static assert( is(typeof(tc2 == tm2)));
1920 static assert( is(typeof(tc2 == tc2)));
1921
1922 // https://issues.dlang.org/show_bug.cgi?id=8686
1923 struct Equ3 { bool opEquals(T)(T) { return true; } }
1924 auto tm3 = tuple(Equ3.init);
1925 const tc3 = tuple(Equ3.init);
1926 static assert( is(typeof(tm3 == tm3)));
1927 static assert( is(typeof(tm3 == tc3)));
1928 static assert(!is(typeof(tc3 == tm3)));
1929 static assert(!is(typeof(tc3 == tc3)));
1930
1931 struct Equ4 { bool opEquals(T)(T) const { return true; } }
1932 auto tm4 = tuple(Equ4.init);
1933 const tc4 = tuple(Equ4.init);
1934 static assert( is(typeof(tm4 == tm4)));
1935 static assert( is(typeof(tm4 == tc4)));
1936 static assert( is(typeof(tc4 == tm4)));
1937 static assert( is(typeof(tc4 == tc4)));
1938 }
1939 // opCmp
1940 {
1941 struct Cmp1 { int opCmp(Cmp1) { return 0; } }
1942 auto tm1 = tuple(Cmp1.init);
1943 const tc1 = tuple(Cmp1.init);
1944 static assert( is(typeof(tm1 < tm1)));
1945 static assert(!is(typeof(tm1 < tc1)));
1946 static assert(!is(typeof(tc1 < tm1)));
1947 static assert(!is(typeof(tc1 < tc1)));
1948
1949 struct Cmp2 { int opCmp(const Cmp2) const { return 0; } }
1950 auto tm2 = tuple(Cmp2.init);
1951 const tc2 = tuple(Cmp2.init);
1952 static assert( is(typeof(tm2 < tm2)));
1953 static assert( is(typeof(tm2 < tc2)));
1954 static assert( is(typeof(tc2 < tm2)));
1955 static assert( is(typeof(tc2 < tc2)));
1956
1957 struct Cmp3 { int opCmp(T)(T) { return 0; } }
1958 auto tm3 = tuple(Cmp3.init);
1959 const tc3 = tuple(Cmp3.init);
1960 static assert( is(typeof(tm3 < tm3)));
1961 static assert( is(typeof(tm3 < tc3)));
1962 static assert(!is(typeof(tc3 < tm3)));
1963 static assert(!is(typeof(tc3 < tc3)));
1964
1965 struct Cmp4 { int opCmp(T)(T) const { return 0; } }
1966 auto tm4 = tuple(Cmp4.init);
1967 const tc4 = tuple(Cmp4.init);
1968 static assert( is(typeof(tm4 < tm4)));
1969 static assert( is(typeof(tm4 < tc4)));
1970 static assert( is(typeof(tc4 < tm4)));
1971 static assert( is(typeof(tc4 < tc4)));
1972 }
1973 // https://issues.dlang.org/show_bug.cgi?id=14890
1974 static void test14890(inout int[] dummy)
1975 {
1976 alias V = Tuple!(int, int);
1977
1978 V mv;
1979 const V cv;
1980 immutable V iv;
1981 inout V wv; // OK <- NG
1982 inout const V wcv; // OK <- NG
1983
1984 static foreach (v1; AliasSeq!(mv, cv, iv, wv, wcv))
1985 static foreach (v2; AliasSeq!(mv, cv, iv, wv, wcv))
1986 {
1987 assert(!(v1 < v2));
1988 }
1989 }
1990 {
1991 int[2] ints = [ 1, 2 ];
1992 Tuple!(int, int) t = ints;
1993 assert(t[0] == 1 && t[1] == 2);
1994 Tuple!(long, uint) t2 = ints;
1995 assert(t2[0] == 1 && t2[1] == 2);
1996 }
1997 }
1998 @safe unittest
1999 {
2000 auto t1 = Tuple!(int, "x", string, "y")(1, "a");
2001 assert(t1.x == 1);
2002 assert(t1.y == "a");
2003 void foo(Tuple!(int, string) t2) {}
2004 foo(t1);
2005
2006 Tuple!(int, int)[] arr;
2007 arr ~= tuple(10, 20); // OK
2008 arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK
2009
2010 static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) ==
2011 typeof(Tuple!(int, string ).tupleof)));
2012 }
2013 @safe unittest
2014 {
2015 // https://issues.dlang.org/show_bug.cgi?id=10686
2016 immutable Tuple!(int) t1;
2017 auto r1 = t1[0]; // OK
2018 immutable Tuple!(int, "x") t2;
2019 auto r2 = t2[0]; // error
2020 }
2021 @safe unittest
2022 {
2023 import std.exception : assertCTFEable;
2024
2025 // https://issues.dlang.org/show_bug.cgi?id=10218
2026 assertCTFEable!(
2027 {
2028 auto t = tuple(1);
2029 t = tuple(2); // assignment
2030 });
2031 }
2032 @safe unittest
2033 {
2034 class Foo{}
2035 Tuple!(immutable(Foo)[]) a;
2036 }
2037
2038 @safe unittest
2039 {
2040 //Test non-assignable
2041 static struct S
2042 {
2043 int* p;
2044 }
2045 alias IS = immutable S;
2046 static assert(!isAssignable!IS);
2047
2048 auto s = IS.init;
2049
2050 alias TIS = Tuple!IS;
2051 TIS a = tuple(s);
2052 TIS b = a;
2053
2054 alias TISIS = Tuple!(IS, IS);
2055 TISIS d = tuple(s, s);
2056 IS[2] ss;
2057 TISIS e = TISIS(ss);
2058 }
2059
2060 // https://issues.dlang.org/show_bug.cgi?id=9819
2061 @safe unittest
2062 {
2063 alias T = Tuple!(int, "x", double, "foo");
2064 static assert(T.fieldNames[0] == "x");
2065 static assert(T.fieldNames[1] == "foo");
2066
2067 alias Fields = Tuple!(int, "id", string, float);
2068 static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
2069 }
2070
2071 // https://issues.dlang.org/show_bug.cgi?id=13837
2072 @safe unittest
2073 {
2074 // New behaviour, named arguments.
2075 static assert(is(
2076 typeof(tuple!("x")(1)) == Tuple!(int, "x")));
2077 static assert(is(
2078 typeof(tuple!("x")(1.0)) == Tuple!(double, "x")));
2079 static assert(is(
2080 typeof(tuple!("x")("foo")) == Tuple!(string, "x")));
2081 static assert(is(
2082 typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y")));
2083
2084 auto a = tuple!("a", "b", "c")("1", 2, 3.0f);
2085 static assert(is(typeof(a.a) == string));
2086 static assert(is(typeof(a.b) == int));
2087 static assert(is(typeof(a.c) == float));
2088
2089 // Old behaviour, but with explicit type parameters.
2090 static assert(is(
2091 typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double)));
2092 static assert(is(
2093 typeof(tuple!(const int)(1)) == Tuple!(const int)));
2094 static assert(is(
2095 typeof(tuple()) == Tuple!()));
2096
2097 // Nonsensical behaviour
2098 static assert(!__traits(compiles, tuple!(1)(2)));
2099 static assert(!__traits(compiles, tuple!("x")(1, 2)));
2100 static assert(!__traits(compiles, tuple!("x", "y")(1)));
2101 static assert(!__traits(compiles, tuple!("x")()));
2102 static assert(!__traits(compiles, tuple!("x", int)(2)));
2103 }
2104
2105 @safe unittest
2106 {
2107 class C { override size_t toHash() const nothrow @safe { return 0; } }
2108 Tuple!(Rebindable!(const C)) a;
2109 Tuple!(const C) b;
2110 a = b;
2111 }
2112
2113 @nogc @safe unittest
2114 {
2115 alias T = Tuple!(string, "s");
2116 T x;
2117 x = T.init;
2118 }
2119
2120 @safe unittest
2121 {
2122 import std.format : format, FormatException;
2123 import std.exception : assertThrown;
2124
2125 //enum tupStr = tuple(1, 1.0).toString; // toString is *impure*.
2126 //static assert(tupStr == `Tuple!(int, double)(1, 1)`);
2127 }
2128
2129 // https://issues.dlang.org/show_bug.cgi?id=17803, parte uno
2130 @safe unittest
2131 {
2132 auto a = tuple(3, "foo");
2133 assert(__traits(compiles, { a = (a = a); }));
2134 }
2135 // Ditto
2136 @safe unittest
2137 {
2138 Tuple!(int[]) a, b, c;
2139 a = tuple([0, 1, 2]);
2140 c = b = a;
2141 assert(a[0].length == b[0].length && b[0].length == c[0].length);
2142 assert(a[0].ptr == b[0].ptr && b[0].ptr == c[0].ptr);
2143 }
2144
2145 /**
2146 Constructs a $(LREF Tuple) object instantiated and initialized according to
2147 the given arguments.
2148
2149 Params:
2150 Names = An optional list of strings naming each successive field of the `Tuple`
2151 or a list of types that the elements are being casted to.
2152 For a list of names,
2153 each name matches up with the corresponding field given by `Args`.
2154 A name does not have to be provided for every field, but as
2155 the names must proceed in order, it is not possible to skip
2156 one field and name the next after it.
2157 For a list of types,
2158 there must be exactly as many types as parameters.
2159 */
2160 template tuple(Names...)
2161 {
2162 /**
2163 Params:
2164 args = Values to initialize the `Tuple` with. The `Tuple`'s type will
2165 be inferred from the types of the values given.
2166
2167 Returns:
2168 A new `Tuple` with its type inferred from the arguments given.
2169 */
2170 auto tuple(Args...)(Args args)
2171 {
2172 static if (Names.length == 0)
2173 {
2174 // No specified names, just infer types from Args...
2175 return Tuple!Args(args);
2176 }
2177 else static if (!is(typeof(Names[0]) : string))
2178 {
2179 // Names[0] isn't a string, must be explicit types.
2180 return Tuple!Names(args);
2181 }
2182 else
2183 {
2184 // Names[0] is a string, so must be specifying names.
2185 static assert(Names.length == Args.length,
2186 "Insufficient number of names given.");
2187
2188 // Interleave(a, b).and(c, d) == (a, c, b, d)
2189 // This is to get the interleaving of types and names for Tuple
2190 // e.g. Tuple!(int, "x", string, "y")
2191 template Interleave(A...)
2192 {
2193 template and(B...) if (B.length == 1)
2194 {
2195 alias and = AliasSeq!(A[0], B[0]);
2196 }
2197
2198 template and(B...) if (B.length != 1)
2199 {
2200 alias and = AliasSeq!(A[0], B[0],
2201 Interleave!(A[1..$]).and!(B[1..$]));
2202 }
2203 }
2204 return Tuple!(Interleave!(Args).and!(Names))(args);
2205 }
2206 }
2207 }
2208
2209 ///
2210 @safe unittest
2211 {
2212 auto value = tuple(5, 6.7, "hello");
2213 assert(value[0] == 5);
2214 assert(value[1] == 6.7);
2215 assert(value[2] == "hello");
2216
2217 // Field names can be provided.
2218 auto entry = tuple!("index", "value")(4, "Hello");
2219 assert(entry.index == 4);
2220 assert(entry.value == "Hello");
2221 }
2222
2223 /**
2224 Returns `true` if and only if `T` is an instance of `std.typecons.Tuple`.
2225
2226 Params:
2227 T = The type to check.
2228
2229 Returns:
2230 true if `T` is a `Tuple` type, false otherwise.
2231 */
2232 enum isTuple(T) = __traits(compiles,
2233 {
2234 void f(Specs...)(Tuple!Specs tup) {}
2235 f(T.init);
2236 } );
2237
2238 ///
2239 @safe unittest
2240 {
2241 static assert(isTuple!(Tuple!()));
2242 static assert(isTuple!(Tuple!(int)));
2243 static assert(isTuple!(Tuple!(int, real, string)));
2244 static assert(isTuple!(Tuple!(int, "x", real, "y")));
2245 static assert(isTuple!(Tuple!(int, Tuple!(real), string)));
2246 }
2247
2248 @safe unittest
2249 {
2250 static assert(isTuple!(const Tuple!(int)));
2251 static assert(isTuple!(immutable Tuple!(int)));
2252
2253 static assert(!isTuple!(int));
2254 static assert(!isTuple!(const int));
2255
2256 struct S {}
2257 static assert(!isTuple!(S));
2258 }
2259
2260 // used by both Rebindable and UnqualRef
2261 private mixin template RebindableCommon(T, U, alias This)
2262 if (is(T == class) || is(T == interface) || isAssociativeArray!T)
2263 {
2264 private union
2265 {
2266 T original;
2267 U stripped;
2268 }
2269
2270 void opAssign(return scope T another) pure nothrow @nogc
2271 {
2272 // If `T` defines `opCast` we must infer the safety
2273 static if (hasMember!(T, "opCast"))
2274 {
2275 // This will allow the compiler to infer the safety of `T.opCast!U`
2276 // without generating any runtime cost
2277 if (false) { stripped = cast(U) another; }
2278 }
2279 () @trusted { stripped = cast(U) another; }();
2280 }
2281
2282 void opAssign(typeof(this) another) @trusted pure nothrow @nogc
2283 {
2284 stripped = another.stripped;
2285 }
2286
2287 static if (is(T == const U) && is(T == const shared U))
2288 {
2289 // safely assign immutable to const / const shared
2290 void opAssign(This!(immutable U) another) @trusted pure nothrow @nogc
2291 {
2292 stripped = another.stripped;
2293 }
2294 }
2295
2296 this(T initializer) pure nothrow @nogc
2297 {
2298 // Infer safety from opAssign
2299 opAssign(initializer);
2300 }
2301
2302 @property inout(T) get() @trusted pure nothrow @nogc return scope inout
2303 {
2304 return original;
2305 }
2306
2307 bool opEquals()(auto ref const(typeof(this)) rhs) const
2308 {
2309 // Must forward explicitly because 'stripped' is part of a union.
2310 // The necessary 'toHash' is forwarded to the class via alias this.
2311 return stripped == rhs.stripped;
2312 }
2313
2314 bool opEquals(const(U) rhs) const
2315 {
2316 return stripped == rhs;
2317 }
2318
2319 alias get this;
2320 }
2321
2322 /**
2323 `Rebindable!(T)` is a simple, efficient wrapper that behaves just
2324 like an object of type `T`, except that you can reassign it to
2325 refer to another object. For completeness, `Rebindable!(T)` aliases
2326 itself away to `T` if `T` is a non-const object type.
2327
2328 You may want to use `Rebindable` when you want to have mutable
2329 storage referring to `const` objects, for example an array of
2330 references that must be sorted in place. `Rebindable` does not
2331 break the soundness of D's type system and does not incur any of the
2332 risks usually associated with `cast`.
2333
2334 Params:
2335 T = An object, interface, array slice type, or associative array type.
2336 */
2337 template Rebindable(T)
2338 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2339 {
2340 static if (is(T == const U, U) || is(T == immutable U, U))
2341 {
2342 static if (isDynamicArray!T)
2343 {
2344 import std.range.primitives : ElementEncodingType;
2345 alias Rebindable = const(ElementEncodingType!T)[];
2346 }
2347 else
2348 {
2349 struct Rebindable
2350 {
2351 mixin RebindableCommon!(T, U, Rebindable);
2352 }
2353 }
2354 }
2355 else
2356 {
2357 alias Rebindable = T;
2358 }
2359 }
2360
2361 ///Regular `const` object references cannot be reassigned.
2362 @safe unittest
2363 {
2364 class Widget { int x; int y() @safe const { return x; } }
2365 const a = new Widget;
2366 // Fine
2367 a.y();
2368 // error! can't modify const a
2369 // a.x = 5;
2370 // error! can't modify const a
2371 // a = new Widget;
2372 }
2373
2374 /**
2375 However, `Rebindable!(Widget)` does allow reassignment,
2376 while otherwise behaving exactly like a $(D const Widget).
2377 */
2378 @safe unittest
2379 {
2380 class Widget { int x; int y() const @safe { return x; } }
2381 auto a = Rebindable!(const Widget)(new Widget);
2382 // Fine
2383 a.y();
2384 // error! can't modify const a
2385 // a.x = 5;
2386 // Fine
2387 a = new Widget;
2388 }
2389
2390 // https://issues.dlang.org/show_bug.cgi?id=16054
2391 @safe unittest
2392 {
2393 Rebindable!(immutable Object) r;
2394 static assert(__traits(compiles, r.get()));
2395 static assert(!__traits(compiles, &r.get()));
2396 }
2397
2398 @safe unittest
2399 {
2400 class CustomToHash
2401 {
2402 override size_t toHash() const nothrow @trusted { return 42; }
2403 }
2404 Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash();
2405 assert(a.toHash() == 42, "Rebindable!A should offer toHash()"
2406 ~ " by forwarding to A.toHash().");
2407 }
2408
2409 // https://issues.dlang.org/show_bug.cgi?id=18615
2410 // Rebindable!A should use A.opEqualsa
2411 @system unittest
2412 {
2413 class CustomOpEq
2414 {
2415 int x;
2416 override bool opEquals(Object rhsObj)
2417 {
2418 if (auto rhs = cast(const(CustomOpEq)) rhsObj)
2419 return this.x == rhs.x;
2420 else
2421 return false;
2422 }
2423 }
2424 CustomOpEq a = new CustomOpEq();
2425 CustomOpEq b = new CustomOpEq();
2426 assert(a !is b);
2427 assert(a == b, "a.x == b.x should be true (0 == 0).");
2428
2429 Rebindable!(const(CustomOpEq)) ra = a;
2430 Rebindable!(const(CustomOpEq)) rb = b;
2431 assert(ra !is rb);
2432 assert(ra == rb, "Rebindable should use CustomOpEq's opEquals, not 'is'.");
2433 assert(ra == b, "Rebindable!(someQualifier(A)) should be comparable"
2434 ~ " against const(A) via A.opEquals.");
2435 assert(a == rb, "Rebindable!(someQualifier(A)) should be comparable"
2436 ~ " against const(A) via A.opEquals.");
2437
2438 b.x = 1;
2439 assert(a != b);
2440 assert(ra != b, "Rebindable!(someQualifier(A)) should be comparable"
2441 ~ " against const(A) via A.opEquals.");
2442 assert(a != rb, "Rebindable!(someQualifier(A)) should be comparable"
2443 ~ " against const(A) via A.opEquals.");
2444
2445 Rebindable!(const(Object)) o1 = new Object();
2446 Rebindable!(const(Object)) o2 = new Object();
2447 assert(o1 !is o2);
2448 assert(o1 == o1, "When the class doesn't provide its own opEquals,"
2449 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2450 assert(o1 != o2, "When the class doesn't provide its own opEquals,"
2451 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals.");
2452 assert(o1 != new Object(), "Rebindable!(const(Object)) should be"
2453 ~ " comparable against Object itself and use Object.opEquals.");
2454 }
2455
2456 // https://issues.dlang.org/show_bug.cgi?id=18755
2457 @safe unittest
2458 {
2459 static class Foo
2460 {
2461 auto opCast(T)() @system immutable pure nothrow
2462 {
2463 *(cast(uint*) 0xdeadbeef) = 0xcafebabe;
2464 return T.init;
2465 }
2466 }
2467
2468 static assert(!__traits(compiles, () @safe {
2469 auto r = Rebindable!(immutable Foo)(new Foo);
2470 }));
2471 static assert(__traits(compiles, () @system {
2472 auto r = Rebindable!(immutable Foo)(new Foo);
2473 }));
2474 }
2475
2476 /**
2477 Convenience function for creating a `Rebindable` using automatic type
2478 inference.
2479
2480 Params:
2481 obj = A reference to an object, interface, associative array, or an array slice
2482 to initialize the `Rebindable` with.
2483
2484 Returns:
2485 A newly constructed `Rebindable` initialized with the given reference.
2486 */
2487 Rebindable!T rebindable(T)(T obj)
2488 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2489 {
2490 typeof(return) ret;
2491 ret = obj;
2492 return ret;
2493 }
2494
2495 ///
2496 @system unittest
2497 {
2498 class C
2499 {
2500 int payload;
2501 this(int p) { payload = p; }
2502 }
2503 const c = new C(1);
2504
2505 auto c2 = c.rebindable;
2506 assert(c2.payload == 1);
2507 // passing Rebindable to rebindable
2508 c2 = c2.rebindable;
2509
2510 c2 = new C(2);
2511 assert(c2.payload == 2);
2512
2513 const c3 = c2.get;
2514 assert(c3.payload == 2);
2515 }
2516
2517 /**
2518 This function simply returns the `Rebindable` object passed in. It's useful
2519 in generic programming cases when a given object may be either a regular
2520 `class` or a `Rebindable`.
2521
2522 Params:
2523 obj = An instance of Rebindable!T.
2524
2525 Returns:
2526 `obj` without any modification.
2527 */
2528 Rebindable!T rebindable(T)(Rebindable!T obj)
2529 {
2530 return obj;
2531 }
2532
2533 // TODO: remove me once the rebindable overloads have been joined
2534 ///
2535 @system unittest
2536 {
2537 class C
2538 {
2539 int payload;
2540 this(int p) { payload = p; }
2541 }
2542 const c = new C(1);
2543
2544 auto c2 = c.rebindable;
2545 assert(c2.payload == 1);
2546 // passing Rebindable to rebindable
2547 c2 = c2.rebindable;
2548 assert(c2.payload == 1);
2549 }
2550
2551 @system unittest
2552 {
2553 interface CI { int foo() const; }
2554 class C : CI {
2555 int foo() const { return 42; }
2556 @property int bar() const { return 23; }
2557 }
2558 Rebindable!(C) obj0;
2559 static assert(is(typeof(obj0) == C));
2560
2561 Rebindable!(const(C)) obj1;
2562 static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof);
2563 static assert(is(typeof(obj1.stripped) == C));
2564 obj1 = new C;
2565 assert(obj1.get !is null);
2566 obj1 = new const(C);
2567 assert(obj1.get !is null);
2568
2569 Rebindable!(immutable(C)) obj2;
2570 static assert(is(typeof(obj2.get) == immutable(C)));
2571 static assert(is(typeof(obj2.stripped) == C));
2572 obj2 = new immutable(C);
2573 assert(obj1.get !is null);
2574
2575 // test opDot
2576 assert(obj2.foo() == 42);
2577 assert(obj2.bar == 23);
2578
2579 interface I { final int foo() const { return 42; } }
2580 Rebindable!(I) obj3;
2581 static assert(is(typeof(obj3) == I));
2582
2583 Rebindable!(const I) obj4;
2584 static assert(is(typeof(obj4.get) == const I));
2585 static assert(is(typeof(obj4.stripped) == I));
2586 static assert(is(typeof(obj4.foo()) == int));
2587 obj4 = new class I {};
2588
2589 Rebindable!(immutable C) obj5i;
2590 Rebindable!(const C) obj5c;
2591 obj5c = obj5c;
2592 obj5c = obj5i;
2593 obj5i = obj5i;
2594 static assert(!__traits(compiles, obj5i = obj5c));
2595
2596 // Test the convenience functions.
2597 auto obj5convenience = rebindable(obj5i);
2598 assert(obj5convenience is obj5i);
2599
2600 auto obj6 = rebindable(new immutable(C));
2601 static assert(is(typeof(obj6) == Rebindable!(immutable C)));
2602 assert(obj6.foo() == 42);
2603
2604 auto obj7 = rebindable(new C);
2605 CI interface1 = obj7;
2606 auto interfaceRebind1 = rebindable(interface1);
2607 assert(interfaceRebind1.foo() == 42);
2608
2609 const interface2 = interface1;
2610 auto interfaceRebind2 = rebindable(interface2);
2611 assert(interfaceRebind2.foo() == 42);
2612
2613 auto arr = [1,2,3,4,5];
2614 const arrConst = arr;
2615 assert(rebindable(arr) == arr);
2616 assert(rebindable(arrConst) == arr);
2617
2618 // https://issues.dlang.org/show_bug.cgi?id=7654
2619 immutable(char[]) s7654;
2620 Rebindable!(typeof(s7654)) r7654 = s7654;
2621
2622 static foreach (T; AliasSeq!(char, wchar, char, int))
2623 {
2624 static assert(is(Rebindable!(immutable(T[])) == immutable(T)[]));
2625 static assert(is(Rebindable!(const(T[])) == const(T)[]));
2626 static assert(is(Rebindable!(T[]) == T[]));
2627 }
2628
2629 // https://issues.dlang.org/show_bug.cgi?id=12046
2630 static assert(!__traits(compiles, Rebindable!(int[1])));
2631 static assert(!__traits(compiles, Rebindable!(const int[1])));
2632
2633 // Pull request 3341
2634 Rebindable!(immutable int[int]) pr3341 = [123:345];
2635 assert(pr3341[123] == 345);
2636 immutable int[int] pr3341_aa = [321:543];
2637 pr3341 = pr3341_aa;
2638 assert(pr3341[321] == 543);
2639 assert(rebindable(pr3341_aa)[321] == 543);
2640 }
2641
2642 /**
2643 Similar to `Rebindable!(T)` but strips all qualifiers from the reference as
2644 opposed to just constness / immutability. Primary intended use case is with
2645 shared (having thread-local reference to shared class data)
2646
2647 Params:
2648 T = A class or interface type.
2649 */
2650 template UnqualRef(T)
2651 if (is(T == class) || is(T == interface))
2652 {
2653 static if (is(T == immutable U, U)
2654 || is(T == const shared U, U)
2655 || is(T == const U, U)
2656 || is(T == shared U, U))
2657 {
2658 struct UnqualRef
2659 {
2660 mixin RebindableCommon!(T, U, UnqualRef);
2661 }
2662 }
2663 else
2664 {
2665 alias UnqualRef = T;
2666 }
2667 }
2668
2669 ///
2670 @system unittest
2671 {
2672 class Data {}
2673
2674 static shared(Data) a;
2675 static UnqualRef!(shared Data) b;
2676
2677 import core.thread;
2678
2679 auto thread = new core.thread.Thread({
2680 a = new shared Data();
2681 b = new shared Data();
2682 });
2683
2684 thread.start();
2685 thread.join();
2686
2687 assert(a !is null);
2688 assert(b is null);
2689 }
2690
2691 @safe unittest
2692 {
2693 class C { }
2694 alias T = UnqualRef!(const shared C);
2695 static assert(is(typeof(T.stripped) == C));
2696 }
2697
2698
2699
2700 /**
2701 Order the provided members to minimize size while preserving alignment.
2702 Alignment is not always optimal for 80-bit reals, nor for structs declared
2703 as align(1).
2704
2705 Params:
2706 E = A list of the types to be aligned, representing fields
2707 of an aggregate such as a `struct` or `class`.
2708
2709 names = The names of the fields that are to be aligned.
2710
2711 Returns:
2712 A string to be mixed in to an aggregate, such as a `struct` or `class`.
2713 */
2714 string alignForSize(E...)(const char[][] names...)
2715 {
2716 // Sort all of the members by .alignof.
2717 // BUG: Alignment is not always optimal for align(1) structs
2718 // or 80-bit reals or 64-bit primitives on x86.
2719 // TRICK: Use the fact that .alignof is always a power of 2,
2720 // and maximum 16 on extant systems. Thus, we can perform
2721 // a very limited radix sort.
2722 // Contains the members with .alignof = 64,32,16,8,4,2,1
2723
2724 assert(E.length == names.length,
2725 "alignForSize: There should be as many member names as the types");
2726
2727 string[7] declaration = ["", "", "", "", "", "", ""];
2728
2729 foreach (i, T; E)
2730 {
2731 auto a = T.alignof;
2732 auto k = a >= 64? 0 : a >= 32? 1 : a >= 16? 2 : a >= 8? 3 : a >= 4? 4 : a >= 2? 5 : 6;
2733 declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n";
2734 }
2735
2736 auto s = "";
2737 foreach (decl; declaration)
2738 s ~= decl;
2739 return s;
2740 }
2741
2742 ///
2743 @safe unittest
2744 {
2745 struct Banner {
2746 mixin(alignForSize!(byte[6], double)(["name", "height"]));
2747 }
2748 }
2749
2750 @safe unittest
2751 {
2752 enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w");
2753 struct Foo { int x; }
2754 enum y = alignForSize!(ubyte, Foo, double)("x", "y", "z");
2755
2756 enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
2757 enum passNormalY = y == "double z;\nFoo y;\nubyte x;\n";
2758
2759 enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
2760 enum passAbnormalY = y == "Foo y;\ndouble z;\nubyte x;\n";
2761 // ^ blame https://issues.dlang.org/show_bug.cgi?id=231
2762
2763 static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof);
2764 static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof);
2765 }
2766
2767 // https://issues.dlang.org/show_bug.cgi?id=12914
2768 @safe unittest
2769 {
2770 immutable string[] fieldNames = ["x", "y"];
2771 struct S
2772 {
2773 mixin(alignForSize!(byte, int)(fieldNames));
2774 }
2775 }
2776
2777 /**
2778 Defines a value paired with a distinctive "null" state that denotes
2779 the absence of a value. If default constructed, a $(D
2780 Nullable!T) object starts in the null state. Assigning it renders it
2781 non-null. Calling `nullify` can nullify it again.
2782
2783 Practically `Nullable!T` stores a `T` and a `bool`.
2784
2785 See also:
2786 $(LREF apply), an alternative way to use the payload.
2787 */
2788 struct Nullable(T)
2789 {
2790 private union DontCallDestructorT
2791 {
2792 import std.traits : hasIndirections;
2793 static if (hasIndirections!T)
2794 T payload;
2795 else
2796 T payload = void;
2797 }
2798
2799 private DontCallDestructorT _value = DontCallDestructorT.init;
2800
2801 private bool _isNull = true;
2802
2803 /**
2804 * Constructor initializing `this` with `value`.
2805 *
2806 * Params:
2807 * value = The value to initialize this `Nullable` with.
2808 */
2809 this(inout T value) inout
2810 {
2811 _value.payload = value;
2812 _isNull = false;
2813 }
2814
2815 static if (hasElaborateDestructor!T)
2816 {
2817 ~this()
2818 {
2819 if (!_isNull)
2820 {
2821 destroy(_value.payload);
2822 }
2823 }
2824 }
2825
2826 static if (__traits(hasPostblit, T))
2827 {
2828 this(this)
2829 {
2830 if (!_isNull)
2831 _value.payload.__xpostblit();
2832 }
2833 }
2834 else static if (__traits(hasCopyConstructor, T))
2835 {
2836 this(ref return scope inout Nullable!T rhs) inout
2837 {
2838 _isNull = rhs._isNull;
2839 if (!_isNull)
2840 _value.payload = rhs._value.payload;
2841 else
2842 _value = DontCallDestructorT.init;
2843 }
2844 }
2845
2846 /**
2847 * If they are both null, then they are equal. If one is null and the other
2848 * is not, then they are not equal. If they are both non-null, then they are
2849 * equal if their values are equal.
2850 */
2851 bool opEquals(this This, Rhs)(auto ref Rhs rhs)
2852 if (!is(CommonType!(This, Rhs) == void))
2853 {
2854 static if (is(This == Rhs))
2855 {
2856 if (_isNull)
2857 return rhs._isNull;
2858 if (rhs._isNull)
2859 return false;
2860 return _value.payload == rhs._value.payload;
2861 }
2862 else
2863 {
2864 alias Common = CommonType!(This, Rhs);
2865 return cast(Common) this == cast(Common) rhs;
2866 }
2867 }
2868
2869 /// Ditto
2870 bool opEquals(this This, Rhs)(auto ref Rhs rhs)
2871 if (is(CommonType!(This, Rhs) == void) && is(typeof(this.get == rhs)))
2872 {
2873 return _isNull ? false : rhs == _value.payload;
2874 }
2875
2876 ///
2877 @safe unittest
2878 {
2879 Nullable!int empty;
2880 Nullable!int a = 42;
2881 Nullable!int b = 42;
2882 Nullable!int c = 27;
2883
2884 assert(empty == empty);
2885 assert(empty == Nullable!int.init);
2886 assert(empty != a);
2887 assert(empty != b);
2888 assert(empty != c);
2889
2890 assert(a == b);
2891 assert(a != c);
2892
2893 assert(empty != 42);
2894 assert(a == 42);
2895 assert(c != 42);
2896 }
2897
2898 @safe unittest
2899 {
2900 // Test constness
2901 immutable Nullable!int a = 42;
2902 Nullable!int b = 42;
2903 immutable Nullable!int c = 29;
2904 Nullable!int d = 29;
2905 immutable e = 42;
2906 int f = 29;
2907 assert(a == a);
2908 assert(a == b);
2909 assert(a != c);
2910 assert(a != d);
2911 assert(a == e);
2912 assert(a != f);
2913
2914 // Test rvalue
2915 assert(a == const Nullable!int(42));
2916 assert(a != Nullable!int(29));
2917 }
2918
2919 // https://issues.dlang.org/show_bug.cgi?id=17482
2920 @system unittest
2921 {
2922 import std.variant : Variant;
2923 Nullable!Variant a = Variant(12);
2924 assert(a == 12);
2925 Nullable!Variant e;
2926 assert(e != 12);
2927 }
2928
2929 size_t toHash() const @safe nothrow
2930 {
2931 static if (__traits(compiles, .hashOf(_value.payload)))
2932 return _isNull ? 0 : .hashOf(_value.payload);
2933 else
2934 // Workaround for when .hashOf is not both @safe and nothrow.
2935 return _isNull ? 0 : typeid(T).getHash(&_value.payload);
2936 }
2937
2938 /**
2939 * Gives the string `"Nullable.null"` if `isNull` is `true`. Otherwise, the
2940 * result is equivalent to calling $(REF formattedWrite, std,format) on the
2941 * underlying value.
2942 *
2943 * Params:
2944 * writer = A `char` accepting
2945 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
2946 * fmt = A $(REF FormatSpec, std,format) which is used to represent
2947 * the value if this Nullable is not null
2948 * Returns:
2949 * A `string` if `writer` and `fmt` are not set; `void` otherwise.
2950 */
2951 string toString()
2952 {
2953 import std.array : appender;
2954 auto app = appender!string();
2955 auto spec = singleSpec("%s");
2956 toString(app, spec);
2957 return app.data;
2958 }
2959
2960 /// ditto
2961 string toString() const
2962 {
2963 import std.array : appender;
2964 auto app = appender!string();
2965 auto spec = singleSpec("%s");
2966 toString(app, spec);
2967 return app.data;
2968 }
2969
2970 /// ditto
2971 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt)
2972 if (isOutputRange!(W, char))
2973 {
2974 import std.range.primitives : put;
2975 if (isNull)
2976 put(writer, "Nullable.null");
2977 else
2978 formatValue(writer, _value.payload, fmt);
2979 }
2980
2981 /// ditto
2982 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) const
2983 if (isOutputRange!(W, char))
2984 {
2985 import std.range.primitives : put;
2986 if (isNull)
2987 put(writer, "Nullable.null");
2988 else
2989 formatValue(writer, _value.payload, fmt);
2990 }
2991
2992 /**
2993 * Check if `this` is in the null state.
2994 *
2995 * Returns:
2996 * true $(B iff) `this` is in the null state, otherwise false.
2997 */
2998 @property bool isNull() const @safe pure nothrow
2999 {
3000 return _isNull;
3001 }
3002
3003 ///
3004 @safe unittest
3005 {
3006 Nullable!int ni;
3007 assert(ni.isNull);
3008
3009 ni = 0;
3010 assert(!ni.isNull);
3011 }
3012
3013 // https://issues.dlang.org/show_bug.cgi?id=14940
3014 @safe unittest
3015 {
3016 import std.array : appender;
3017 import std.format.write : formattedWrite;
3018
3019 auto app = appender!string();
3020 Nullable!int a = 1;
3021 formattedWrite(app, "%s", a);
3022 assert(app.data == "1");
3023 }
3024
3025 // https://issues.dlang.org/show_bug.cgi?id=19799
3026 @safe unittest
3027 {
3028 import std.format : format;
3029
3030 const Nullable!string a = const(Nullable!string)();
3031
3032 format!"%s"(a);
3033 }
3034
3035 /**
3036 * Forces `this` to the null state.
3037 */
3038 void nullify()()
3039 {
3040 static if (is(T == class) || is(T == interface))
3041 _value.payload = null;
3042 else
3043 .destroy(_value.payload);
3044 _isNull = true;
3045 }
3046
3047 ///
3048 @safe unittest
3049 {
3050 Nullable!int ni = 0;
3051 assert(!ni.isNull);
3052
3053 ni.nullify();
3054 assert(ni.isNull);
3055 }
3056
3057 /**
3058 * Assigns `value` to the internally-held state. If the assignment
3059 * succeeds, `this` becomes non-null.
3060 *
3061 * Params:
3062 * value = A value of type `T` to assign to this `Nullable`.
3063 */
3064 Nullable opAssign()(T value)
3065 {
3066 import std.algorithm.mutation : moveEmplace, move;
3067
3068 // the lifetime of the value in copy shall be managed by
3069 // this Nullable, so we must avoid calling its destructor.
3070 auto copy = DontCallDestructorT(value);
3071
3072 if (_isNull)
3073 {
3074 // trusted since payload is known to be uninitialized.
3075 () @trusted { moveEmplace(copy.payload, _value.payload); }();
3076 }
3077 else
3078 {
3079 move(copy.payload, _value.payload);
3080 }
3081 _isNull = false;
3082 return this;
3083 }
3084
3085 /**
3086 * If this `Nullable` wraps a type that already has a null value
3087 * (such as a pointer), then assigning the null value to this
3088 * `Nullable` is no different than assigning any other value of
3089 * type `T`, and the resulting code will look very strange. It
3090 * is strongly recommended that this be avoided by instead using
3091 * the version of `Nullable` that takes an additional `nullValue`
3092 * template argument.
3093 */
3094 @safe unittest
3095 {
3096 //Passes
3097 Nullable!(int*) npi;
3098 assert(npi.isNull);
3099
3100 //Passes?!
3101 npi = null;
3102 assert(!npi.isNull);
3103 }
3104
3105 /**
3106 * Gets the value if not null. If `this` is in the null state, and the optional
3107 * parameter `fallback` was provided, it will be returned. Without `fallback`,
3108 * calling `get` with a null state is invalid.
3109 *
3110 * When the fallback type is different from the Nullable type, `get(T)` returns
3111 * the common type.
3112 *
3113 * Params:
3114 * fallback = the value to return in case the `Nullable` is null.
3115 *
3116 * Returns:
3117 * The value held internally by this `Nullable`.
3118 */
3119 @property ref inout(T) get() inout @safe pure nothrow
3120 {
3121 enum message = "Called `get' on null Nullable!" ~ T.stringof ~ ".";
3122 assert(!isNull, message);
3123 return _value.payload;
3124 }
3125
3126 /// ditto
3127 @property inout(T) get()(inout(T) fallback) inout
3128 {
3129 return isNull ? fallback : _value.payload;
3130 }
3131
3132 /// ditto
3133 @property auto get(U)(inout(U) fallback) inout
3134 {
3135 return isNull ? fallback : _value.payload;
3136 }
3137
3138 /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions.
3139 alias empty = isNull;
3140
3141 /// ditto
3142 alias popFront = nullify;
3143
3144 /// ditto
3145 alias popBack = nullify;
3146
3147 /// ditto
3148 @property ref inout(T) front() inout @safe pure nothrow
3149 {
3150 return get();
3151 }
3152
3153 /// ditto
3154 alias back = front;
3155
3156 /// ditto
3157 @property inout(typeof(this)) save() inout
3158 {
3159 return this;
3160 }
3161
3162 /// ditto
3163 inout(typeof(this)) opIndex(size_t[2] dim) inout
3164 in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
3165 {
3166 return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
3167 }
3168 /// ditto
3169 size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
3170 {
3171 return [from, to];
3172 }
3173
3174 /// ditto
3175 @property size_t length() const @safe pure nothrow
3176 {
3177 return !empty;
3178 }
3179
3180 /// ditto
3181 alias opDollar(size_t dim : 0) = length;
3182
3183 /// ditto
3184 ref inout(T) opIndex(size_t index) inout @safe pure nothrow
3185 in (index < length)
3186 {
3187 return get();
3188 }
3189
3190 /**
3191 * Converts `Nullable` to a range. Works even when the contained type is `immutable`.
3192 */
3193 auto opSlice(this This)()
3194 {
3195 static struct NullableRange
3196 {
3197 private This value;
3198
3199 // starts out true if value is null
3200 private bool empty_;
3201
3202 @property bool empty() const @safe pure nothrow
3203 {
3204 return empty_;
3205 }
3206
3207 void popFront() @safe pure nothrow
3208 {
3209 empty_ = true;
3210 }
3211
3212 alias popBack = popFront;
3213
3214 @property ref inout(typeof(value.get())) front() inout @safe pure nothrow
3215 {
3216 return value.get();
3217 }
3218
3219 alias back = front;
3220
3221 @property inout(typeof(this)) save() inout
3222 {
3223 return this;
3224 }
3225
3226 size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
3227 {
3228 return [from, to];
3229 }
3230
3231 @property size_t length() const @safe pure nothrow
3232 {
3233 return !empty;
3234 }
3235
3236 alias opDollar(size_t dim : 0) = length;
3237
3238 ref inout(typeof(value.get())) opIndex(size_t index) inout @safe pure nothrow
3239 in (index < length)
3240 {
3241 return value.get();
3242 }
3243
3244 inout(typeof(this)) opIndex(size_t[2] dim) inout
3245 in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
3246 {
3247 return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
3248 }
3249
3250 auto opIndex() inout
3251 {
3252 return this;
3253 }
3254 }
3255 return NullableRange(this, isNull);
3256 }
3257 }
3258
3259 /// ditto
3260 auto nullable(T)(T t)
3261 {
3262 return Nullable!T(t);
3263 }
3264
3265 ///
3266 @safe unittest
3267 {
3268 struct CustomerRecord
3269 {
3270 string name;
3271 string address;
3272 int customerNum;
3273 }
3274
3275 Nullable!CustomerRecord getByName(string name)
3276 {
3277 //A bunch of hairy stuff
3278
3279 return Nullable!CustomerRecord.init;
3280 }
3281
3282 auto queryResult = getByName("Doe, John");
3283 if (!queryResult.isNull)
3284 {
3285 //Process Mr. Doe's customer record
3286 auto address = queryResult.get.address;
3287 auto customerNum = queryResult.get.customerNum;
3288
3289 //Do some things with this customer's info
3290 }
3291 else
3292 {
3293 //Add the customer to the database
3294 }
3295 }
3296
3297 ///
3298 @system unittest
3299 {
3300 import std.exception : assertThrown;
3301
3302 auto a = 42.nullable;
3303 assert(!a.isNull);
3304 assert(a.get == 42);
3305
3306 a.nullify();
3307 assert(a.isNull);
3308 assertThrown!Throwable(a.get);
3309 }
3310 ///
3311 @safe unittest
3312 {
3313 import std.algorithm.iteration : each, joiner;
3314 Nullable!int a = 42;
3315 Nullable!int b;
3316 // Add each value to an array
3317 int[] arr;
3318 a.each!((n) => arr ~= n);
3319 assert(arr == [42]);
3320 b.each!((n) => arr ~= n);
3321 assert(arr == [42]);
3322 // Take first value from an array of Nullables
3323 Nullable!int[] c = new Nullable!int[](10);
3324 c[7] = Nullable!int(42);
3325 assert(c.joiner.front == 42);
3326 }
3327 @safe unittest
3328 {
3329 auto k = Nullable!int(74);
3330 assert(k == 74);
3331 k.nullify();
3332 assert(k.isNull);
3333 }
3334 @safe unittest
3335 {
3336 static int f(scope const Nullable!int x) {
3337 return x.isNull ? 42 : x.get;
3338 }
3339 Nullable!int a;
3340 assert(f(a) == 42);
3341 a = 8;
3342 assert(f(a) == 8);
3343 a.nullify();
3344 assert(f(a) == 42);
3345 }
3346 @system unittest
3347 {
3348 import std.exception : assertThrown;
3349
3350 static struct S { int x; }
3351 Nullable!S s;
3352 assert(s.isNull);
3353 s = S(6);
3354 assert(s == S(6));
3355 assert(s != S(0));
3356 assert(s.get != S(0));
3357 s.get.x = 9190;
3358 assert(s.get.x == 9190);
3359 s.nullify();
3360 assertThrown!Throwable(s.get.x = 9441);
3361 }
3362 @safe unittest
3363 {
3364 // Ensure Nullable can be used in pure/nothrow/@safe environment.
3365 function() @safe pure nothrow
3366 {
3367 Nullable!int n;
3368 assert(n.isNull);
3369 n = 4;
3370 assert(!n.isNull);
3371 assert(n == 4);
3372 n.nullify();
3373 assert(n.isNull);
3374 }();
3375 }
3376 @system unittest
3377 {
3378 // Ensure Nullable can be used when the value is not pure/nothrow/@safe
3379 static struct S
3380 {
3381 int x;
3382 this(this) @system {}
3383 }
3384
3385 Nullable!S s;
3386 assert(s.isNull);
3387 s = S(5);
3388 assert(!s.isNull);
3389 assert(s.get.x == 5);
3390 s.nullify();
3391 assert(s.isNull);
3392 }
3393
3394 // https://issues.dlang.org/show_bug.cgi?id=9404
3395 @safe unittest
3396 {
3397 alias N = Nullable!int;
3398
3399 void foo(N a)
3400 {
3401 N b;
3402 b = a; // `N b = a;` works fine
3403 }
3404 N n;
3405 foo(n);
3406 }
3407 @safe unittest
3408 {
3409 //Check nullable immutable is constructable
3410 {
3411 auto a1 = Nullable!(immutable int)();
3412 auto a2 = Nullable!(immutable int)(1);
3413 auto i = a2.get;
3414 }
3415 //Check immutable nullable is constructable
3416 {
3417 auto a1 = immutable (Nullable!int)();
3418 auto a2 = immutable (Nullable!int)(1);
3419 auto i = a2.get;
3420 }
3421 }
3422 @safe unittest
3423 {
3424 alias NInt = Nullable!int;
3425
3426 //Construct tests
3427 {
3428 //from other Nullable null
3429 NInt a1;
3430 NInt b1 = a1;
3431 assert(b1.isNull);
3432
3433 //from other Nullable non-null
3434 NInt a2 = NInt(1);
3435 NInt b2 = a2;
3436 assert(b2 == 1);
3437
3438 //Construct from similar nullable
3439 auto a3 = immutable(NInt)();
3440 NInt b3 = a3;
3441 assert(b3.isNull);
3442 }
3443
3444 //Assign tests
3445 {
3446 //from other Nullable null
3447 NInt a1;
3448 NInt b1;
3449 b1 = a1;
3450 assert(b1.isNull);
3451
3452 //from other Nullable non-null
3453 NInt a2 = NInt(1);
3454 NInt b2;
3455 b2 = a2;
3456 assert(b2 == 1);
3457
3458 //Construct from similar nullable
3459 auto a3 = immutable(NInt)();
3460 NInt b3 = a3;
3461 b3 = a3;
3462 assert(b3.isNull);
3463 }
3464 }
3465 @safe unittest
3466 {
3467 //Check nullable is nicelly embedable in a struct
3468 static struct S1
3469 {
3470 Nullable!int ni;
3471 }
3472 static struct S2 //inspired from 9404
3473 {
3474 Nullable!int ni;
3475 this(ref S2 other)
3476 {
3477 ni = other.ni;
3478 }
3479 void opAssign(ref S2 other)
3480 {
3481 ni = other.ni;
3482 }
3483 }
3484 static foreach (S; AliasSeq!(S1, S2))
3485 {{
3486 S a;
3487 S b = a;
3488 S c;
3489 c = a;
3490 }}
3491 }
3492
3493 // https://issues.dlang.org/show_bug.cgi?id=10268
3494 @system unittest
3495 {
3496 import std.json;
3497 JSONValue value = null;
3498 auto na = Nullable!JSONValue(value);
3499
3500 struct S1 { int val; }
3501 struct S2 { int* val; }
3502 struct S3 { immutable int* val; }
3503
3504 {
3505 auto sm = S1(1);
3506 immutable si = immutable S1(1);
3507 auto x1 = Nullable!S1(sm);
3508 auto x2 = immutable Nullable!S1(sm);
3509 auto x3 = Nullable!S1(si);
3510 auto x4 = immutable Nullable!S1(si);
3511 assert(x1.get.val == 1);
3512 assert(x2.get.val == 1);
3513 assert(x3.get.val == 1);
3514 assert(x4.get.val == 1);
3515 }
3516
3517 auto nm = 10;
3518 immutable ni = 10;
3519
3520 {
3521 auto sm = S2(&nm);
3522 immutable si = immutable S2(&ni);
3523 auto x1 = Nullable!S2(sm);
3524 static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); }));
3525 static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); }));
3526 auto x4 = immutable Nullable!S2(si);
3527 assert(*x1.get.val == 10);
3528 assert(*x4.get.val == 10);
3529 }
3530
3531 {
3532 auto sm = S3(&ni);
3533 immutable si = immutable S3(&ni);
3534 auto x1 = Nullable!S3(sm);
3535 auto x2 = immutable Nullable!S3(sm);
3536 auto x3 = Nullable!S3(si);
3537 auto x4 = immutable Nullable!S3(si);
3538 assert(*x1.get.val == 10);
3539 assert(*x2.get.val == 10);
3540 assert(*x3.get.val == 10);
3541 assert(*x4.get.val == 10);
3542 }
3543 }
3544
3545 // https://issues.dlang.org/show_bug.cgi?id=10357
3546 @safe unittest
3547 {
3548 import std.datetime;
3549 Nullable!SysTime time = SysTime(0);
3550 }
3551
3552 // https://issues.dlang.org/show_bug.cgi?id=10915
3553 @system unittest
3554 {
3555 import std.conv : to;
3556 import std.array;
3557
3558 Appender!string buffer;
3559
3560 Nullable!int ni;
3561 assert(ni.to!string() == "Nullable.null");
3562 assert((cast(const) ni).to!string() == "Nullable.null");
3563
3564 struct Test { string s; }
3565 alias NullableTest = Nullable!Test;
3566
3567 NullableTest nt = Test("test");
3568 // test output range version
3569 assert(nt.to!string() == `Test("test")`);
3570 // test appender version
3571 assert(nt.toString() == `Test("test")`);
3572 // test const version
3573 assert((cast(const) nt).toString() == `const(Test)("test")`);
3574
3575 NullableTest ntn = Test("null");
3576 assert(ntn.to!string() == `Test("null")`);
3577
3578 class TestToString
3579 {
3580 double d;
3581
3582 this (double d)
3583 {
3584 this.d = d;
3585 }
3586
3587 override string toString()
3588 {
3589 return d.to!string();
3590 }
3591 }
3592 Nullable!TestToString ntts = new TestToString(2.5);
3593 assert(ntts.to!string() == "2.5");
3594 }
3595
3596 // https://issues.dlang.org/show_bug.cgi?id=14477
3597 @safe unittest
3598 {
3599 static struct DisabledDefaultConstructor
3600 {
3601 @disable this();
3602 this(int i) { }
3603 }
3604 Nullable!DisabledDefaultConstructor var;
3605 var = DisabledDefaultConstructor(5);
3606 var.nullify;
3607 }
3608
3609 // https://issues.dlang.org/show_bug.cgi?id=17440
3610 @system unittest
3611 {
3612 static interface I { }
3613
3614 static class C : I
3615 {
3616 int canary;
3617 ~this()
3618 {
3619 canary = 0x5050DEAD;
3620 }
3621 }
3622 auto c = new C;
3623 c.canary = 0xA71FE;
3624 auto nc = nullable(c);
3625 nc.nullify;
3626 assert(c.canary == 0xA71FE);
3627
3628 I i = c;
3629 auto ni = nullable(i);
3630 ni.nullify;
3631 assert(c.canary == 0xA71FE);
3632 }
3633
3634 // https://issues.dlang.org/show_bug.cgi?id=19037
3635 @safe unittest
3636 {
3637 import std.datetime : SysTime;
3638
3639 struct Test
3640 {
3641 bool b;
3642
3643 nothrow invariant { assert(b == true); }
3644
3645 SysTime _st;
3646
3647 static bool destroyed;
3648
3649 @disable this();
3650 this(bool b) { this.b = b; }
3651 ~this() @safe { destroyed = true; }
3652
3653 // mustn't call opAssign on Test.init in Nullable!Test, because the invariant
3654 // will be called before opAssign on the Test.init that is in Nullable
3655 // and Test.init violates its invariant.
3656 void opAssign(Test rhs) @safe { assert(false); }
3657 }
3658
3659 {
3660 Nullable!Test nt;
3661
3662 nt = Test(true);
3663
3664 // destroy value
3665 Test.destroyed = false;
3666
3667 nt.nullify;
3668
3669 assert(Test.destroyed);
3670
3671 Test.destroyed = false;
3672 }
3673 // don't run destructor on T.init in Nullable on scope exit!
3674 assert(!Test.destroyed);
3675 }
3676 // check that the contained type's destructor is called on assignment
3677 @system unittest
3678 {
3679 struct S
3680 {
3681 // can't be static, since we need a specific value's pointer
3682 bool* destroyedRef;
3683
3684 ~this()
3685 {
3686 if (this.destroyedRef)
3687 {
3688 *this.destroyedRef = true;
3689 }
3690 }
3691 }
3692
3693 Nullable!S ns;
3694
3695 bool destroyed;
3696
3697 ns = S(&destroyed);
3698
3699 // reset from rvalue destruction in Nullable's opAssign
3700 destroyed = false;
3701
3702 // overwrite Nullable
3703 ns = S(null);
3704
3705 // the original S should be destroyed.
3706 assert(destroyed == true);
3707 }
3708 // check that the contained type's destructor is still called when required
3709 @system unittest
3710 {
3711 bool destructorCalled = false;
3712
3713 struct S
3714 {
3715 bool* destroyed;
3716 ~this() { *this.destroyed = true; }
3717 }
3718
3719 {
3720 Nullable!S ns;
3721 }
3722 assert(!destructorCalled);
3723 {
3724 Nullable!S ns = Nullable!S(S(&destructorCalled));
3725
3726 destructorCalled = false; // reset after S was destroyed in the NS constructor
3727 }
3728 assert(destructorCalled);
3729 }
3730
3731 // check that toHash on Nullable is forwarded to the contained type
3732 @system unittest
3733 {
3734 struct S
3735 {
3736 size_t toHash() const @safe pure nothrow { return 5; }
3737 }
3738
3739 Nullable!S s1 = S();
3740 Nullable!S s2 = Nullable!S();
3741
3742 assert(typeid(Nullable!S).getHash(&s1) == 5);
3743 assert(typeid(Nullable!S).getHash(&s2) == 0);
3744 }
3745
3746 // https://issues.dlang.org/show_bug.cgi?id=21704
3747 @safe unittest
3748 {
3749 import std.array : staticArray;
3750
3751 bool destroyed;
3752
3753 struct Probe
3754 {
3755 ~this() { destroyed = true; }
3756 }
3757
3758 {
3759 Nullable!(Probe[1]) test = [Probe()].staticArray;
3760 destroyed = false;
3761 }
3762 assert(destroyed);
3763 }
3764
3765 // https://issues.dlang.org/show_bug.cgi?id=21705
3766 @safe unittest
3767 {
3768 static struct S
3769 {
3770 int n;
3771 bool opEquals(S rhs) { return n == rhs.n; }
3772 }
3773
3774 Nullable!S test1 = S(1), test2 = S(1);
3775 S s = S(1);
3776
3777 assert(test1 == s);
3778 assert(test1 == test2);
3779 }
3780
3781 // https://issues.dlang.org/show_bug.cgi?id=22101
3782 @safe unittest
3783 {
3784 static int impure;
3785
3786 struct S
3787 {
3788 ~this() { impure++; }
3789 }
3790
3791 Nullable!S s;
3792 s.get(S());
3793 }
3794
3795 // https://issues.dlang.org/show_bug.cgi?id=22100
3796 @safe unittest
3797 {
3798 Nullable!int a, b, c;
3799 a = b = c = 5;
3800 a = b = c = nullable(5);
3801 }
3802
3803 // https://issues.dlang.org/show_bug.cgi?id=18374
3804 @safe pure nothrow unittest
3805 {
3806 import std.algorithm.comparison : equal;
3807 import std.range : only, takeNone;
3808 import std.range.primitives : hasAssignableElements, hasLength,
3809 hasLvalueElements, hasSlicing, hasSwappableElements,
3810 isRandomAccessRange;
3811 Nullable!int a = 42;
3812 assert(!a.empty);
3813 assert(a.front == 42);
3814 assert(a.back == 42);
3815 assert(a[0] == 42);
3816 assert(a.equal(only(42)));
3817 assert(a[0 .. $].equal(only(42)));
3818 a[0] = 43;
3819 assert(a.equal(only(43)));
3820 --a[0];
3821 assert(a.equal(only(42)));
3822 Nullable!int b;
3823 assert(b.empty);
3824 assert(b.equal(takeNone(b)));
3825 Nullable!int c = a.save();
3826 assert(!c.empty);
3827 c.popFront();
3828 assert(!a.empty);
3829 assert(c.empty);
3830
3831 assert(isRandomAccessRange!(Nullable!int));
3832 assert(hasLength!(Nullable!int));
3833 assert(hasSlicing!(Nullable!int));
3834 assert(hasAssignableElements!(Nullable!int));
3835 assert(hasSwappableElements!(Nullable!int));
3836 assert(hasLvalueElements!(Nullable!int));
3837 }
3838
3839 // https://issues.dlang.org/show_bug.cgi?id=23640
3840 @safe pure nothrow unittest
3841 {
3842 import std.algorithm.comparison : equal;
3843 import std.range : only;
3844 import std.range.primitives : hasLength, hasSlicing,
3845 isRandomAccessRange;
3846 static immutable struct S { int[] array; }
3847 auto value = S([42]);
3848 alias ImmutableNullable = immutable Nullable!S;
3849 auto a = ImmutableNullable(value)[];
3850 alias Range = typeof(a);
3851 assert(isRandomAccessRange!Range);
3852 assert(hasLength!Range);
3853 assert(hasSlicing!Range);
3854 assert(!a.empty);
3855 assert(a.front == value);
3856 assert(a.back == value);
3857 assert(a[0] == value);
3858 assert(a.equal(only(value)));
3859 assert(a[0 .. $].equal(only(value)));
3860 Range b = a.save();
3861 assert(!b.empty);
3862 b.popFront();
3863 assert(!a.empty);
3864 assert(b.empty);
3865 }
3866
3867 /**
3868 Just like `Nullable!T`, except that the null state is defined as a
3869 particular value. For example, $(D Nullable!(uint, uint.max)) is an
3870 `uint` that sets aside the value `uint.max` to denote a null
3871 state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D
3872 Nullable!T) because it does not need to store an extra `bool`.
3873
3874 Params:
3875 T = The wrapped type for which Nullable provides a null value.
3876
3877 nullValue = The null value which denotes the null state of this
3878 `Nullable`. Must be of type `T`.
3879 */
3880 struct Nullable(T, T nullValue)
3881 {
3882 private T _value = nullValue;
3883
3884 /**
3885 Constructor initializing `this` with `value`.
3886
3887 Params:
3888 value = The value to initialize this `Nullable` with.
3889 */
3890 this(T value)
3891 {
3892 _value = value;
3893 }
3894
3895 template toString()
3896 {
3897 import std.format.spec : FormatSpec;
3898 import std.format.write : formatValue;
3899 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
3900 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt)
3901 {
3902 if (isNull)
3903 {
3904 sink.formatValue("Nullable.null", fmt);
3905 }
3906 else
3907 {
3908 sink.formatValue(_value, fmt);
3909 }
3910 }
3911
3912 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const
3913 {
3914 if (isNull)
3915 {
3916 sink.formatValue("Nullable.null", fmt);
3917 }
3918 else
3919 {
3920 sink.formatValue(_value, fmt);
3921 }
3922 }
3923 }
3924
3925 @system unittest
3926 {
3927 import std.conv : to;
3928
3929 const Nullable!(ulong, 0) x = 1;
3930 assert(x.to!string == "1");
3931 }
3932
3933 /**
3934 Check if `this` is in the null state.
3935
3936 Returns:
3937 true $(B iff) `this` is in the null state, otherwise false.
3938 */
3939 @property bool isNull() const
3940 {
3941 //Need to use 'is' if T is a nullable type and
3942 //nullValue is null, or it's a compiler error
3943 static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null)
3944 {
3945 return _value is nullValue;
3946 }
3947 //Need to use 'is' if T is a float type
3948 //because NaN != NaN
3949 else static if (__traits(isFloating, T) || __traits(compiles, { static assert(!(nullValue == nullValue)); }))
3950 {
3951 return _value is nullValue;
3952 }
3953 else
3954 {
3955 return _value == nullValue;
3956 }
3957 }
3958
3959 ///
3960 @safe unittest
3961 {
3962 Nullable!(int, -1) ni;
3963 //Initialized to "null" state
3964 assert(ni.isNull);
3965
3966 ni = 0;
3967 assert(!ni.isNull);
3968 }
3969
3970 @system unittest
3971 {
3972 assert(typeof(this).init.isNull, typeof(this).stringof ~
3973 ".isNull does not work correctly because " ~ T.stringof ~
3974 " has an == operator that is non-reflexive and could not be" ~
3975 " determined before runtime to be non-reflexive!");
3976 }
3977
3978 // https://issues.dlang.org/show_bug.cgi?id=11135
3979 // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed
3980 version (none) @system unittest
3981 {
3982 static foreach (T; AliasSeq!(float, double, real))
3983 {{
3984 Nullable!(T, T.init) nf;
3985 //Initialized to "null" state
3986 assert(nf.isNull);
3987 assert(nf is typeof(nf).init);
3988
3989 nf = 0;
3990 assert(!nf.isNull);
3991
3992 nf.nullify();
3993 assert(nf.isNull);
3994 }}
3995 }
3996
3997 /**
3998 Forces `this` to the null state.
3999 */
4000 void nullify()()
4001 {
4002 _value = nullValue;
4003 }
4004
4005 ///
4006 @safe unittest
4007 {
4008 Nullable!(int, -1) ni = 0;
4009 assert(!ni.isNull);
4010
4011 ni = -1;
4012 assert(ni.isNull);
4013 }
4014
4015 /**
4016 Assigns `value` to the internally-held state. If the assignment
4017 succeeds, `this` becomes non-null. No null checks are made. Note
4018 that the assignment may leave `this` in the null state.
4019
4020 Params:
4021 value = A value of type `T` to assign to this `Nullable`.
4022 If it is `nullvalue`, then the internal state of
4023 this `Nullable` will be set to null.
4024 */
4025 void opAssign()(T value)
4026 {
4027 import std.algorithm.mutation : swap;
4028
4029 swap(value, _value);
4030 }
4031
4032 /**
4033 If this `Nullable` wraps a type that already has a null value
4034 (such as a pointer), and that null value is not given for
4035 `nullValue`, then assigning the null value to this `Nullable`
4036 is no different than assigning any other value of type `T`,
4037 and the resulting code will look very strange. It is strongly
4038 recommended that this be avoided by using `T`'s "built in"
4039 null value for `nullValue`.
4040 */
4041 @system unittest
4042 {
4043 //Passes
4044 enum nullVal = cast(int*) 0xCAFEBABE;
4045 Nullable!(int*, nullVal) npi;
4046 assert(npi.isNull);
4047
4048 //Passes?!
4049 npi = null;
4050 assert(!npi.isNull);
4051 }
4052
4053 /**
4054 Gets the value. `this` must not be in the null state.
4055 This function is also called for the implicit conversion to `T`.
4056
4057 Preconditions: `isNull` must be `false`.
4058 Returns:
4059 The value held internally by this `Nullable`.
4060 */
4061 @property ref inout(T) get() inout
4062 {
4063 //@@@6169@@@: We avoid any call that might evaluate nullValue's %s,
4064 //Because it might messup get's purity and safety inference.
4065 enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue).";
4066 assert(!isNull, message);
4067 return _value;
4068 }
4069
4070 ///
4071 @system unittest
4072 {
4073 import std.exception : assertThrown, assertNotThrown;
4074
4075 Nullable!(int, -1) ni;
4076 //`get` is implicitly called. Will throw
4077 //an error in non-release mode
4078 assertThrown!Throwable(ni == 0);
4079
4080 ni = 0;
4081 assertNotThrown!Throwable(ni == 0);
4082 }
4083
4084 /**
4085 Implicitly converts to `T`.
4086 `this` must not be in the null state.
4087 */
4088 alias get this;
4089 }
4090
4091 /// ditto
4092 auto nullable(alias nullValue, T)(T t)
4093 if (is (typeof(nullValue) == T))
4094 {
4095 return Nullable!(T, nullValue)(t);
4096 }
4097
4098 ///
4099 @safe unittest
4100 {
4101 Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle)
4102 {
4103 //Find the needle, returning -1 if not found
4104
4105 return Nullable!(size_t, size_t.max).init;
4106 }
4107
4108 void sendLunchInvite(string name)
4109 {
4110 }
4111
4112 //It's safer than C...
4113 auto coworkers = ["Jane", "Jim", "Marry", "Fred"];
4114 auto pos = indexOf(coworkers, "Bob");
4115 if (!pos.isNull)
4116 {
4117 //Send Bob an invitation to lunch
4118 sendLunchInvite(coworkers[pos]);
4119 }
4120 else
4121 {
4122 //Bob not found; report the error
4123 }
4124
4125 //And there's no overhead
4126 static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof);
4127 }
4128
4129 ///
4130 @system unittest
4131 {
4132 import std.exception : assertThrown;
4133
4134 Nullable!(int, int.min) a;
4135 assert(a.isNull);
4136 assertThrown!Throwable(a.get);
4137 a = 5;
4138 assert(!a.isNull);
4139 assert(a == 5);
4140 static assert(a.sizeof == int.sizeof);
4141 }
4142
4143 ///
4144 @safe unittest
4145 {
4146 auto a = nullable!(int.min)(8);
4147 assert(a == 8);
4148 a.nullify();
4149 assert(a.isNull);
4150 }
4151
4152 @nogc nothrow pure @safe unittest
4153 {
4154 // https://issues.dlang.org/show_bug.cgi?id=19226
4155 // fully handle non-self-equal nullValue
4156 static struct Fraction
4157 {
4158 int denominator;
4159 bool isNaN() const
4160 {
4161 return denominator == 0;
4162 }
4163 bool opEquals(const Fraction rhs) const
4164 {
4165 return !isNaN && denominator == rhs.denominator;
4166 }
4167 }
4168 alias N = Nullable!(Fraction, Fraction.init);
4169 assert(N.init.isNull);
4170 }
4171
4172 @safe unittest
4173 {
4174 static int f(scope const Nullable!(int, int.min) x) {
4175 return x.isNull ? 42 : x.get;
4176 }
4177 Nullable!(int, int.min) a;
4178 assert(f(a) == 42);
4179 a = 8;
4180 assert(f(a) == 8);
4181 a.nullify();
4182 assert(f(a) == 42);
4183 }
4184 @safe unittest
4185 {
4186 // Ensure Nullable can be used in pure/nothrow/@safe environment.
4187 function() @safe pure nothrow
4188 {
4189 Nullable!(int, int.min) n;
4190 assert(n.isNull);
4191 n = 4;
4192 assert(!n.isNull);
4193 assert(n == 4);
4194 n.nullify();
4195 assert(n.isNull);
4196 }();
4197 }
4198 @system unittest
4199 {
4200 // Ensure Nullable can be used when the value is not pure/nothrow/@system
4201 static struct S
4202 {
4203 int x;
4204 bool opEquals(const S s) const @system { return s.x == x; }
4205 }
4206
4207 Nullable!(S, S(711)) s;
4208 assert(s.isNull);
4209 s = S(5);
4210 assert(!s.isNull);
4211 assert(s.x == 5);
4212 s.nullify();
4213 assert(s.isNull);
4214 }
4215 @safe unittest
4216 {
4217 //Check nullable is nicelly embedable in a struct
4218 static struct S1
4219 {
4220 Nullable!(int, 0) ni;
4221 }
4222 static struct S2 //inspired from 9404
4223 {
4224 Nullable!(int, 0) ni;
4225 this(S2 other)
4226 {
4227 ni = other.ni;
4228 }
4229 void opAssign(S2 other)
4230 {
4231 ni = other.ni;
4232 }
4233 }
4234 static foreach (S; AliasSeq!(S1, S2))
4235 {{
4236 S a;
4237 S b = a;
4238 S c;
4239 c = a;
4240 }}
4241 }
4242 @system unittest
4243 {
4244 import std.conv : to;
4245
4246 // https://issues.dlang.org/show_bug.cgi?id=10915
4247 Nullable!(int, 1) ni = 1;
4248 assert(ni.to!string() == "Nullable.null");
4249
4250 struct Test { string s; }
4251 alias NullableTest = Nullable!(Test, Test("null"));
4252
4253 NullableTest nt = Test("test");
4254 assert(nt.to!string() == `Test("test")`);
4255
4256 NullableTest ntn = Test("null");
4257 assert(ntn.to!string() == "Nullable.null");
4258
4259 class TestToString
4260 {
4261 double d;
4262
4263 this(double d)
4264 {
4265 this.d = d;
4266 }
4267
4268 override string toString()
4269 {
4270 return d.to!string();
4271 }
4272 }
4273 alias NullableTestToString = Nullable!(TestToString, null);
4274
4275 NullableTestToString ntts = new TestToString(2.5);
4276 assert(ntts.to!string() == "2.5");
4277 }
4278
4279 // apply
4280 /**
4281 Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull.
4282
4283 When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`,
4284 pass it to the function you provide and wrap the result in another `Nullable` (if necessary).
4285 If the `Nullable` is null, `apply` will return null itself.
4286
4287 Params:
4288 t = a `Nullable`
4289 fun = a function operating on the content of the nullable
4290
4291 Returns:
4292 `fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`.
4293
4294 See also:
4295 $(HTTPS en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad)
4296 */
4297 template apply(alias fun)
4298 {
4299 import std.functional : unaryFun;
4300
4301 auto apply(T)(auto ref T t)
4302 if (isInstanceOf!(Nullable, T))
4303 {
4304 alias FunType = typeof(unaryFun!fun(T.init.get));
4305
4306 enum MustWrapReturn = !isInstanceOf!(Nullable, FunType);
4307
4308 static if (MustWrapReturn)
4309 {
4310 alias ReturnType = Nullable!FunType;
4311 }
4312 else
4313 {
4314 alias ReturnType = FunType;
4315 }
4316
4317 if (!t.isNull)
4318 {
4319 static if (MustWrapReturn)
4320 {
4321 return unaryFun!fun(t.get).nullable;
4322 }
4323 else
4324 {
4325 return unaryFun!fun(t.get);
4326 }
4327 }
4328 else
4329 {
4330 return ReturnType.init;
4331 }
4332 }
4333 }
4334
4335 ///
4336 nothrow pure @nogc @safe unittest
4337 {
4338 alias toFloat = i => cast(float) i;
4339
4340 Nullable!int sample;
4341
4342 // apply(null) results in a null `Nullable` of the function's return type.
4343 Nullable!float f = sample.apply!toFloat;
4344 assert(sample.isNull && f.isNull);
4345
4346 sample = 3;
4347
4348 // apply(non-null) calls the function and wraps the result in a `Nullable`.
4349 f = sample.apply!toFloat;
4350 assert(!sample.isNull && !f.isNull);
4351 assert(f.get == 3.0f);
4352 }
4353
4354 ///
4355 nothrow pure @nogc @safe unittest
4356 {
4357 alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init;
4358
4359 Nullable!int sample;
4360
4361 // when the function already returns a `Nullable`, that `Nullable` is not wrapped.
4362 auto result = sample.apply!greaterThree;
4363 assert(sample.isNull && result.isNull);
4364
4365 // The function may decide to return a null `Nullable`.
4366 sample = 3;
4367 result = sample.apply!greaterThree;
4368 assert(!sample.isNull && result.isNull);
4369
4370 // Or it may return a value already wrapped in a `Nullable`.
4371 sample = 4;
4372 result = sample.apply!greaterThree;
4373 assert(!sample.isNull && !result.isNull);
4374 assert(result.get == 4);
4375 }
4376
4377 // test that Nullable.get(default) can merge types
4378 @safe @nogc nothrow pure
4379 unittest
4380 {
4381 Nullable!ubyte sample = Nullable!ubyte();
4382
4383 // Test that get(U) returns the common type of the Nullable type and the parameter type.
4384 assert(sample.get(1000) == 1000);
4385 }
4386
4387 // Workaround for https://issues.dlang.org/show_bug.cgi?id=20670
4388 @safe @nogc nothrow pure
4389 unittest
4390 {
4391 immutable struct S { }
4392
4393 S[] array = Nullable!(S[])().get(S[].init);
4394 }
4395
4396 // regression test for https://issues.dlang.org/show_bug.cgi?id=21199
4397 @safe @nogc nothrow pure
4398 unittest
4399 {
4400 struct S { int i; }
4401 assert(S(5).nullable.apply!"a.i" == 5);
4402 }
4403
4404 // regression test for https://issues.dlang.org/show_bug.cgi?id=22176
4405 @safe @nogc nothrow pure
4406 unittest
4407 {
4408 struct S
4409 {
4410 int i;
4411 invariant(i != 0);
4412
4413 // Nullable shouldn't cause S to generate an
4414 // opAssign that would check the invariant.
4415 Nullable!int j;
4416 }
4417 S s;
4418 s = S(5);
4419 }
4420
4421 /**
4422 Just like `Nullable!T`, except that the object refers to a value
4423 sitting elsewhere in memory. This makes assignments overwrite the
4424 initially assigned value. Internally `NullableRef!T` only stores a
4425 pointer to `T` (i.e., $(D Nullable!T.sizeof == (T*).sizeof)).
4426 */
4427 struct NullableRef(T)
4428 {
4429 private T* _value;
4430
4431 /**
4432 Constructor binding `this` to `value`.
4433
4434 Params:
4435 value = The value to bind to.
4436 */
4437 this(T* value) @safe pure nothrow
4438 {
4439 _value = value;
4440 }
4441
4442 template toString()
4443 {
4444 import std.format.spec : FormatSpec;
4445 import std.format.write : formatValue;
4446 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737.
4447 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt)
4448 {
4449 if (isNull)
4450 {
4451 sink.formatValue("Nullable.null", fmt);
4452 }
4453 else
4454 {
4455 sink.formatValue(*_value, fmt);
4456 }
4457 }
4458
4459 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const
4460 {
4461 if (isNull)
4462 {
4463 sink.formatValue("Nullable.null", fmt);
4464 }
4465 else
4466 {
4467 sink.formatValue(*_value, fmt);
4468 }
4469 }
4470 }
4471
4472 @system unittest
4473 {
4474 import std.conv : to;
4475
4476 const NullableRef!(ulong) x = new ulong(1);
4477 assert(x.to!string == "1");
4478 }
4479
4480 /**
4481 Binds the internal state to `value`.
4482
4483 Params:
4484 value = A pointer to a value of type `T` to bind this `NullableRef` to.
4485 */
4486 void bind(T* value) @safe pure nothrow
4487 {
4488 _value = value;
4489 }
4490
4491 ///
4492 @safe unittest
4493 {
4494 NullableRef!int nr = new int(42);
4495 assert(nr == 42);
4496
4497 int* n = new int(1);
4498 nr.bind(n);
4499 assert(nr == 1);
4500 }
4501
4502 /**
4503 Returns `true` if and only if `this` is in the null state.
4504
4505 Returns:
4506 true if `this` is in the null state, otherwise false.
4507 */
4508 @property bool isNull() const @safe pure nothrow
4509 {
4510 return _value is null;
4511 }
4512
4513 ///
4514 @safe unittest
4515 {
4516 NullableRef!int nr;
4517 assert(nr.isNull);
4518
4519 int* n = new int(42);
4520 nr.bind(n);
4521 assert(!nr.isNull && nr == 42);
4522 }
4523
4524 /**
4525 Forces `this` to the null state.
4526 */
4527 void nullify() @safe pure nothrow
4528 {
4529 _value = null;
4530 }
4531
4532 ///
4533 @safe unittest
4534 {
4535 NullableRef!int nr = new int(42);
4536 assert(!nr.isNull);
4537
4538 nr.nullify();
4539 assert(nr.isNull);
4540 }
4541
4542 /**
4543 Assigns `value` to the internally-held state.
4544
4545 Params:
4546 value = A value of type `T` to assign to this `NullableRef`.
4547 If the internal state of this `NullableRef` has not
4548 been initialized, an error will be thrown in
4549 non-release mode.
4550 */
4551 void opAssign()(T value)
4552 if (isAssignable!T) //@@@9416@@@
4553 {
4554 enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ ".";
4555 assert(!isNull, message);
4556 *_value = value;
4557 }
4558
4559 ///
4560 @system unittest
4561 {
4562 import std.exception : assertThrown, assertNotThrown;
4563
4564 NullableRef!int nr;
4565 assert(nr.isNull);
4566 assertThrown!Throwable(nr = 42);
4567
4568 nr.bind(new int(0));
4569 assert(!nr.isNull);
4570 assertNotThrown!Throwable(nr = 42);
4571 assert(nr == 42);
4572 }
4573
4574 /**
4575 Gets the value. `this` must not be in the null state.
4576 This function is also called for the implicit conversion to `T`.
4577 */
4578 @property ref inout(T) get() inout @safe pure nothrow
4579 {
4580 enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ ".";
4581 assert(!isNull, message);
4582 return *_value;
4583 }
4584
4585 ///
4586 @system unittest
4587 {
4588 import std.exception : assertThrown, assertNotThrown;
4589
4590 NullableRef!int nr;
4591 //`get` is implicitly called. Will throw
4592 //an error in non-release mode
4593 assertThrown!Throwable(nr == 0);
4594
4595 nr.bind(new int(0));
4596 assertNotThrown!Throwable(nr == 0);
4597 }
4598
4599 /**
4600 Implicitly converts to `T`.
4601 `this` must not be in the null state.
4602 */
4603 alias get this;
4604 }
4605
4606 /// ditto
4607 auto nullableRef(T)(T* t)
4608 {
4609 return NullableRef!T(t);
4610 }
4611
4612 ///
4613 @system unittest
4614 {
4615 import std.exception : assertThrown;
4616
4617 int x = 5, y = 7;
4618 auto a = nullableRef(&x);
4619 assert(!a.isNull);
4620 assert(a == 5);
4621 assert(x == 5);
4622 a = 42;
4623 assert(x == 42);
4624 assert(!a.isNull);
4625 assert(a == 42);
4626 a.nullify();
4627 assert(x == 42);
4628 assert(a.isNull);
4629 assertThrown!Throwable(a.get);
4630 assertThrown!Throwable(a = 71);
4631 a.bind(&y);
4632 assert(a == 7);
4633 y = 135;
4634 assert(a == 135);
4635 }
4636 @system unittest
4637 {
4638 static int f(scope const NullableRef!int x) {
4639 return x.isNull ? 42 : x.get;
4640 }
4641 int x = 5;
4642 auto a = nullableRef(&x);
4643 assert(f(a) == 5);
4644 a.nullify();
4645 assert(f(a) == 42);
4646 }
4647 @safe unittest
4648 {
4649 // Ensure NullableRef can be used in pure/nothrow/@safe environment.
4650 function() @safe pure nothrow
4651 {
4652 auto storage = new int;
4653 *storage = 19902;
4654 NullableRef!int n;
4655 assert(n.isNull);
4656 n.bind(storage);
4657 assert(!n.isNull);
4658 assert(n == 19902);
4659 n = 2294;
4660 assert(n == 2294);
4661 assert(*storage == 2294);
4662 n.nullify();
4663 assert(n.isNull);
4664 }();
4665 }
4666 @system unittest
4667 {
4668 // Ensure NullableRef can be used when the value is not pure/nothrow/@safe
4669 static struct S
4670 {
4671 int x;
4672 this(this) @system {}
4673 bool opEquals(const S s) const @system { return s.x == x; }
4674 }
4675
4676 auto storage = S(5);
4677
4678 NullableRef!S s;
4679 assert(s.isNull);
4680 s.bind(&storage);
4681 assert(!s.isNull);
4682 assert(s.x == 5);
4683 s.nullify();
4684 assert(s.isNull);
4685 }
4686 @safe unittest
4687 {
4688 //Check nullable is nicelly embedable in a struct
4689 static struct S1
4690 {
4691 NullableRef!int ni;
4692 }
4693 static struct S2 //inspired from 9404
4694 {
4695 NullableRef!int ni;
4696 this(S2 other)
4697 {
4698 ni = other.ni;
4699 }
4700 void opAssign(S2 other)
4701 {
4702 ni = other.ni;
4703 }
4704 }
4705 static foreach (S; AliasSeq!(S1, S2))
4706 {{
4707 S a;
4708 S b = a;
4709 S c;
4710 c = a;
4711 }}
4712 }
4713
4714 // https://issues.dlang.org/show_bug.cgi?id=10915
4715 @system unittest
4716 {
4717 import std.conv : to;
4718
4719 NullableRef!int nri;
4720 assert(nri.to!string() == "Nullable.null");
4721
4722 struct Test
4723 {
4724 string s;
4725 }
4726 NullableRef!Test nt = new Test("test");
4727 assert(nt.to!string() == `Test("test")`);
4728
4729 class TestToString
4730 {
4731 double d;
4732
4733 this(double d)
4734 {
4735 this.d = d;
4736 }
4737
4738 override string toString()
4739 {
4740 return d.to!string();
4741 }
4742 }
4743 TestToString tts = new TestToString(2.5);
4744 NullableRef!TestToString ntts = &tts;
4745 assert(ntts.to!string() == "2.5");
4746 }
4747
4748
4749 /**
4750 `BlackHole!Base` is a subclass of `Base` which automatically implements
4751 all abstract member functions in `Base` as do-nothing functions. Each
4752 auto-implemented function just returns the default value of the return type
4753 without doing anything.
4754
4755 The name came from
4756 $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole)
4757 Perl module by Sean M. Burke.
4758
4759 Params:
4760 Base = A non-final class for `BlackHole` to inherit from.
4761
4762 See_Also:
4763 $(LREF AutoImplement), $(LREF generateEmptyFunction)
4764 */
4765 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction);
4766
4767 ///
4768 @system unittest
4769 {
4770 import std.math.traits : isNaN;
4771
4772 static abstract class C
4773 {
4774 int m_value;
4775 this(int v) { m_value = v; }
4776 int value() @property { return m_value; }
4777
4778 abstract real realValue() @property;
4779 abstract void doSomething();
4780 }
4781
4782 auto c = new BlackHole!C(42);
4783 assert(c.value == 42);
4784
4785 // Returns real.init which is NaN
4786 assert(c.realValue.isNaN);
4787 // Abstract functions are implemented as do-nothing
4788 c.doSomething();
4789 }
4790
4791 @system unittest
4792 {
4793 import std.math.traits : isNaN;
4794
4795 // return default
4796 {
4797 interface I_1 { real test(); }
4798 auto o = new BlackHole!I_1;
4799 assert(o.test().isNaN()); // NaN
4800 }
4801 // doc example
4802 {
4803 static class C
4804 {
4805 int m_value;
4806 this(int v) { m_value = v; }
4807 int value() @property { return m_value; }
4808
4809 abstract real realValue() @property;
4810 abstract void doSomething();
4811 }
4812
4813 auto c = new BlackHole!C(42);
4814 assert(c.value == 42);
4815
4816 assert(c.realValue.isNaN); // NaN
4817 c.doSomething();
4818 }
4819
4820 // https://issues.dlang.org/show_bug.cgi?id=12058
4821 interface Foo
4822 {
4823 inout(Object) foo() inout;
4824 }
4825 BlackHole!Foo o;
4826 }
4827
4828 nothrow pure @nogc @safe unittest
4829 {
4830 static interface I
4831 {
4832 I foo() nothrow pure @nogc @safe return scope;
4833 }
4834
4835 scope cb = new BlackHole!I();
4836 cb.foo();
4837 }
4838
4839
4840 /**
4841 `WhiteHole!Base` is a subclass of `Base` which automatically implements
4842 all abstract member functions as functions that always fail. These functions
4843 simply throw an `Error` and never return. `Whitehole` is useful for
4844 trapping the use of class member functions that haven't been implemented.
4845
4846 The name came from
4847 $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole)
4848 Perl module by Michael G Schwern.
4849
4850 Params:
4851 Base = A non-final class for `WhiteHole` to inherit from.
4852
4853 See_Also:
4854 $(LREF AutoImplement), $(LREF generateAssertTrap)
4855 */
4856 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction);
4857
4858 ///
4859 @system unittest
4860 {
4861 import std.exception : assertThrown;
4862
4863 static class C
4864 {
4865 abstract void notYetImplemented();
4866 }
4867
4868 auto c = new WhiteHole!C;
4869 assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error
4870 }
4871
4872 // https://issues.dlang.org/show_bug.cgi?id=20232
4873 nothrow pure @safe unittest
4874 {
4875 static interface I
4876 {
4877 I foo() nothrow pure @safe return scope;
4878 }
4879
4880 if (0) // Just checking attribute interference
4881 {
4882 scope cw = new WhiteHole!I();
4883 cw.foo();
4884 }
4885 }
4886
4887 // / ditto
4888 class NotImplementedError : Error
4889 {
4890 this(string method) nothrow pure @safe
4891 {
4892 super(method ~ " is not implemented");
4893 }
4894 }
4895
4896 @system unittest
4897 {
4898 import std.exception : assertThrown;
4899 // nothrow
4900 {
4901 interface I_1
4902 {
4903 void foo();
4904 void bar() nothrow;
4905 }
4906 auto o = new WhiteHole!I_1;
4907 assertThrown!NotImplementedError(o.foo());
4908 assertThrown!NotImplementedError(o.bar());
4909 }
4910 // doc example
4911 {
4912 static class C
4913 {
4914 abstract void notYetImplemented();
4915 }
4916
4917 auto c = new WhiteHole!C;
4918 try
4919 {
4920 c.notYetImplemented();
4921 assert(0);
4922 }
4923 catch (Error e) {}
4924 }
4925 }
4926
4927
4928 /**
4929 `AutoImplement` automatically implements (by default) all abstract member
4930 functions in the class or interface `Base` in specified way.
4931
4932 The second version of `AutoImplement` automatically implements
4933 `Interface`, while deriving from `BaseClass`.
4934
4935 Params:
4936 how = template which specifies _how functions will be implemented/overridden.
4937
4938 Two arguments are passed to `how`: the type `Base` and an alias
4939 to an implemented function. Then `how` must return an implemented
4940 function body as a string.
4941
4942 The generated function body can use these keywords:
4943 $(UL
4944 $(LI `a0`, `a1`, &hellip;: arguments passed to the function;)
4945 $(LI `args`: a tuple of the arguments;)
4946 $(LI `self`: an alias to the function itself;)
4947 $(LI `parent`: an alias to the overridden function (if any).)
4948 )
4949
4950 You may want to use templated property functions (instead of Implicit
4951 Template Properties) to generate complex functions:
4952 --------------------
4953 // Prints log messages for each call to overridden functions.
4954 string generateLogger(C, alias fun)() @property
4955 {
4956 import std.traits;
4957 enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
4958 string stmt;
4959
4960 stmt ~= q{ struct Importer { import std.stdio; } };
4961 stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
4962 static if (!__traits(isAbstractFunction, fun))
4963 {
4964 static if (is(ReturnType!fun == void))
4965 stmt ~= q{ parent(args); };
4966 else
4967 stmt ~= q{
4968 auto r = parent(args);
4969 Importer.writeln("--> ", r);
4970 return r;
4971 };
4972 }
4973 return stmt;
4974 }
4975 --------------------
4976
4977 what = template which determines _what functions should be
4978 implemented/overridden.
4979
4980 An argument is passed to `what`: an alias to a non-final member
4981 function in `Base`. Then `what` must return a boolean value.
4982 Return `true` to indicate that the passed function should be
4983 implemented/overridden.
4984
4985 --------------------
4986 // Sees if fun returns something.
4987 enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
4988 --------------------
4989
4990
4991 Note:
4992
4993 Generated code is inserted in the scope of `std.typecons` module. Thus,
4994 any useful functions outside `std.typecons` cannot be used in the generated
4995 code. To workaround this problem, you may `import` necessary things in a
4996 local struct, as done in the `generateLogger()` template in the above
4997 example.
4998
4999
5000 BUGS:
5001
5002 $(UL
5003 $(LI Variadic arguments to constructors are not forwarded to super.)
5004 $(LI Deep interface inheritance causes compile error with messages like
5005 "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar
5006 does not override any function". [$(BUGZILLA 2525)] )
5007 $(LI The `parent` keyword is actually a delegate to the super class'
5008 corresponding member function. [$(BUGZILLA 2540)] )
5009 $(LI Using alias template parameter in `how` and/or `what` may cause
5010 strange compile error. Use template tuple parameter instead to workaround
5011 this problem. [$(BUGZILLA 4217)] )
5012 )
5013 */
5014 class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base
5015 if (!is(how == class))
5016 {
5017 private alias autoImplement_helper_ =
5018 AutoImplement_Helper!("autoImplement_helper_", "Base", Base, typeof(this), how, what);
5019 mixin(autoImplement_helper_.code);
5020 }
5021
5022 /// ditto
5023 class AutoImplement(
5024 Interface, BaseClass, alias how,
5025 alias what = isAbstractFunction) : BaseClass, Interface
5026 if (is(Interface == interface) && is(BaseClass == class))
5027 {
5028 private alias autoImplement_helper_ = AutoImplement_Helper!(
5029 "autoImplement_helper_", "Interface", Interface, typeof(this), how, what);
5030 mixin(autoImplement_helper_.code);
5031 }
5032
5033 ///
5034 @system unittest
5035 {
5036 interface PackageSupplier
5037 {
5038 int foo();
5039 int bar();
5040 }
5041
5042 static abstract class AbstractFallbackPackageSupplier : PackageSupplier
5043 {
5044 protected PackageSupplier default_, fallback;
5045
5046 this(PackageSupplier default_, PackageSupplier fallback)
5047 {
5048 this.default_ = default_;
5049 this.fallback = fallback;
5050 }
5051
5052 abstract int foo();
5053 abstract int bar();
5054 }
5055
5056 template fallback(T, alias func)
5057 {
5058 import std.format : format;
5059 // for all implemented methods:
5060 // - try default first
5061 // - only on a failure run & return fallback
5062 enum fallback = q{
5063 try
5064 {
5065 return default_.%1$s(args);
5066 }
5067 catch (Exception)
5068 {
5069 return fallback.%1$s(args);
5070 }
5071 }.format(__traits(identifier, func));
5072 }
5073
5074 // combines two classes and use the second one as fallback
5075 alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback);
5076
5077 class FailingPackageSupplier : PackageSupplier
5078 {
5079 int foo(){ throw new Exception("failure"); }
5080 int bar(){ return 2;}
5081 }
5082
5083 class BackupPackageSupplier : PackageSupplier
5084 {
5085 int foo(){ return -1; }
5086 int bar(){ return -1;}
5087 }
5088
5089 auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier());
5090
5091 assert(registry.foo() == -1);
5092 assert(registry.bar() == 2);
5093 }
5094
5095 /*
5096 * Code-generating stuffs are encupsulated in this helper template so that
5097 * namespace pollution, which can cause name confliction with Base's public
5098 * members, should be minimized.
5099 */
5100 private template AutoImplement_Helper(string myName, string baseName,
5101 Base, Self, alias generateMethodBody, alias cherrypickMethod)
5102 {
5103 private static:
5104 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5105 // Internal stuffs
5106 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5107
5108 // Returns function overload sets in the class C, filtered with pred.
5109 template enumerateOverloads(C, alias pred)
5110 {
5111 template Impl(names...)
5112 {
5113 import std.meta : Filter;
5114 static if (names.length > 0)
5115 {
5116 alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0]));
5117 alias next = Impl!(names[1 .. $]);
5118
5119 static if (methods.length > 0)
5120 alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next);
5121 else
5122 alias Impl = next;
5123 }
5124 else
5125 alias Impl = AliasSeq!();
5126 }
5127
5128 alias enumerateOverloads = Impl!(__traits(allMembers, C));
5129 }
5130
5131 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5132 // Target functions
5133 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5134
5135 // Add a non-final check to the cherrypickMethod.
5136 enum bool canonicalPicker(fun.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) =
5137 !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun);
5138
5139 /*
5140 * A tuple of overload sets, each item of which consists of functions to be
5141 * implemented by the generated code.
5142 */
5143 alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker);
5144
5145 /*
5146 * Super class of this AutoImplement instance
5147 */
5148 alias Super = BaseTypeTuple!(Self)[0];
5149 static assert(is(Super == class));
5150 static assert(is(Base == interface) || is(Super == Base));
5151
5152 /*
5153 * A tuple of the super class' constructors. Used for forwarding
5154 * constructor calls.
5155 */
5156 static if (__traits(hasMember, Super, "__ctor"))
5157 alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Super, "__ctor"));
5158 else
5159 alias ctorOverloadSet = OverloadSet!("__ctor"); // empty
5160
5161
5162 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5163 // Type information
5164 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5165
5166 /*
5167 * The generated code will be mixed into AutoImplement, which will be
5168 * instantiated in this module's scope. Thus, any user-defined types are
5169 * out of scope and cannot be used directly (i.e. by their names).
5170 *
5171 * We will use FuncInfo instances for accessing return types and parameter
5172 * types of the implemented functions. The instances will be populated to
5173 * the AutoImplement's scope in a certain way; see the populate() below.
5174 */
5175
5176 // Returns the preferred identifier for the FuncInfo instance for the i-th
5177 // overloaded function with the name.
5178 template INTERNAL_FUNCINFO_ID(string name, size_t i)
5179 {
5180 import std.format : format;
5181
5182 enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i);
5183 }
5184
5185 /*
5186 * Insert FuncInfo instances about all the target functions here. This
5187 * enables the generated code to access type information via, for example,
5188 * "autoImplement_helper_.F_foo_1".
5189 */
5190 template populate(overloads...)
5191 {
5192 static if (overloads.length > 0)
5193 {
5194 mixin populate!(overloads[0].name, overloads[0].contents);
5195 mixin populate!(overloads[1 .. $]);
5196 }
5197 }
5198 template populate(string name, methods...)
5199 {
5200 static if (methods.length > 0)
5201 {
5202 mixin populate!(name, methods[0 .. $ - 1]);
5203 //
5204 alias target = methods[$ - 1];
5205 enum ith = methods.length - 1;
5206 mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;");
5207 }
5208 }
5209
5210 public mixin populate!(targetOverloadSets);
5211 public mixin populate!( ctorOverloadSet );
5212
5213
5214 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5215 // Code-generating policies
5216 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5217
5218 /* Common policy configurations for generating constructors and methods. */
5219 template CommonGeneratingPolicy()
5220 {
5221 // base class identifier which generated code should use
5222 enum string BASE_CLASS_ID = baseName;
5223
5224 // FuncInfo instance identifier which generated code should use
5225 template FUNCINFO_ID(string name, size_t i)
5226 {
5227 enum string FUNCINFO_ID =
5228 myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i);
5229 }
5230 }
5231
5232 /* Policy configurations for generating constructors. */
5233 template ConstructorGeneratingPolicy()
5234 {
5235 mixin CommonGeneratingPolicy;
5236
5237 /* Generates constructor body. Just forward to the base class' one. */
5238 string generateFunctionBody(ctor.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
5239 {
5240 enum varstyle = variadicFunctionStyle!(typeof(&ctor[0]));
5241
5242 static if (varstyle & (Variadic.c | Variadic.d))
5243 {
5244 // the argptr-forwarding problem
5245 //pragma(msg, "Warning: AutoImplement!(", Base, ") ",
5246 // "ignored variadic arguments to the constructor ",
5247 // FunctionTypeOf!(typeof(&ctor[0])) );
5248 }
5249 return "super(args);";
5250 }
5251 }
5252
5253 /* Policy configurations for genearting target methods. */
5254 template MethodGeneratingPolicy()
5255 {
5256 mixin CommonGeneratingPolicy;
5257
5258 /* Geneartes method body. */
5259 string generateFunctionBody(func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property
5260 {
5261 return generateMethodBody!(Base, func); // given
5262 }
5263 }
5264
5265
5266 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5267 // Generated code
5268 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5269
5270 alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!());
5271 alias MethodGenerator = MemberFunctionGenerator!(MethodGeneratingPolicy!());
5272
5273 public enum string code =
5274 ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~
5275 MethodGenerator.generateCode!(targetOverloadSets);
5276
5277 debug (SHOW_GENERATED_CODE)
5278 {
5279 pragma(msg, "-------------------- < ", Base, " >");
5280 pragma(msg, code);
5281 pragma(msg, "--------------------");
5282 }
5283 }
5284
5285 //debug = SHOW_GENERATED_CODE;
5286 @system unittest
5287 {
5288 import core.vararg;
5289 // no function to implement
5290 {
5291 interface I_1 {}
5292 auto o = new BlackHole!I_1;
5293 }
5294 // parameters
5295 {
5296 interface I_3 { void test(int, in int, out int, ref int, lazy int); }
5297 auto o = new BlackHole!I_3;
5298 }
5299 // use of user-defined type
5300 {
5301 struct S {}
5302 interface I_4 { S test(); }
5303 auto o = new BlackHole!I_4;
5304 }
5305 // overloads
5306 {
5307 interface I_5
5308 {
5309 void test(string);
5310 real test(real);
5311 int test();
5312 }
5313 auto o = new BlackHole!I_5;
5314 }
5315 // constructor forwarding
5316 {
5317 static class C_6
5318 {
5319 this(int n) { assert(n == 42); }
5320 this(string s) { assert(s == "Deeee"); }
5321 this(...) {}
5322 }
5323 auto o1 = new BlackHole!C_6(42);
5324 auto o2 = new BlackHole!C_6("Deeee");
5325 auto o3 = new BlackHole!C_6(1, 2, 3, 4);
5326 }
5327 // attributes
5328 {
5329 interface I_7
5330 {
5331 ref int test_ref();
5332 int test_pure() pure;
5333 int test_nothrow() nothrow;
5334 int test_property() @property;
5335 int test_safe() @safe;
5336 int test_trusted() @trusted;
5337 int test_system() @system;
5338 int test_pure_nothrow() pure nothrow;
5339 }
5340 auto o = new BlackHole!I_7;
5341 }
5342 // storage classes
5343 {
5344 interface I_8
5345 {
5346 void test_const() const;
5347 void test_immutable() immutable;
5348 void test_shared() shared;
5349 void test_shared_const() shared const;
5350 }
5351 auto o = new BlackHole!I_8;
5352 }
5353 // use baseclass
5354 {
5355 static class C_9
5356 {
5357 private string foo_;
5358
5359 this(string s) {
5360 foo_ = s;
5361 }
5362
5363 protected string boilerplate() @property
5364 {
5365 return "Boilerplate stuff.";
5366 }
5367
5368 public string foo() @property
5369 {
5370 return foo_;
5371 }
5372 }
5373
5374 interface I_10
5375 {
5376 string testMethod(size_t);
5377 }
5378
5379 static string generateTestMethod(C, alias fun)() @property
5380 {
5381 return "return this.boilerplate[0 .. a0];";
5382 }
5383
5384 auto o = new AutoImplement!(I_10, C_9, generateTestMethod)("Testing");
5385 assert(o.testMethod(11) == "Boilerplate");
5386 assert(o.foo == "Testing");
5387 }
5388 /+ // deep inheritance
5389 {
5390 // https://issues.dlang.org/show_bug.cgi?id=2525
5391 // https://issues.dlang.org/show_bug.cgi?id=3525
5392 // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic()
5393 interface I { void foo(); }
5394 interface J : I {}
5395 interface K : J {}
5396 static abstract class C_9 : K {}
5397 auto o = new BlackHole!C_9;
5398 }+/
5399 // test `parent` alias
5400 {
5401 interface I_11
5402 {
5403 void simple(int) @safe;
5404 int anotherSimple(string);
5405 int overloaded(int);
5406 /+ XXX [BUG 19715]
5407 void overloaded(string) @safe;
5408 +/
5409 }
5410
5411 static class C_11
5412 {
5413 import std.traits : Parameters, ReturnType;
5414 import std.meta : Alias;
5415
5416 protected ReturnType!fn _impl(alias fn)(Parameters!fn)
5417 if (is(Alias!(__traits(parent, fn)) == interface))
5418 {
5419 static if (!is(typeof(return) == void))
5420 return typeof(return).init;
5421 }
5422 }
5423
5424 template tpl(I, alias fn)
5425 if (is(I == interface) && __traits(isSame, __traits(parent, fn), I))
5426 {
5427 enum string tpl = q{
5428 enum bool haveReturn = !is(typeof(return) == void);
5429
5430 static if (is(typeof(return) == void))
5431 _impl!parent(args);
5432 else
5433 return _impl!parent(args);
5434 };
5435 }
5436
5437 auto o = new AutoImplement!(I_11, C_11, tpl);
5438 }
5439 }
5440
5441 // https://issues.dlang.org/show_bug.cgi?id=17177
5442 // AutoImplement fails on function overload sets with
5443 // "cannot infer type from overloaded function symbol"
5444 @system unittest
5445 {
5446 static class Issue17177
5447 {
5448 private string n_;
5449
5450 public {
5451 Issue17177 overloaded(string n)
5452 {
5453 this.n_ = n;
5454
5455 return this;
5456 }
5457
5458 string overloaded()
5459 {
5460 return this.n_;
5461 }
5462 }
5463 }
5464
5465 static string how(C, alias fun)()
5466 {
5467 static if (!is(ReturnType!fun == void))
5468 {
5469 return q{
5470 return parent(args);
5471 };
5472 }
5473 else
5474 {
5475 return q{
5476 parent(args);
5477 };
5478 }
5479 }
5480
5481 import std.meta : templateNot;
5482 alias Implementation = AutoImplement!(Issue17177, how, templateNot!isFinalFunction);
5483 }
5484
5485 version (StdUnittest)
5486 {
5487 // https://issues.dlang.org/show_bug.cgi?id=10647
5488 // Add prefix "issue10647_" as a workaround for
5489 // https://issues.dlang.org/show_bug.cgi?id=1238
5490 private string issue10647_generateDoNothing(C, alias fun)() @property
5491 {
5492 string stmt;
5493
5494 static if (is(ReturnType!fun == void))
5495 stmt ~= "";
5496 else
5497 {
5498 string returnType = ReturnType!fun.stringof;
5499 stmt ~= "return "~returnType~".init;";
5500 }
5501 return stmt;
5502 }
5503
5504 private template issue10647_isAlwaysTrue(alias fun)
5505 {
5506 enum issue10647_isAlwaysTrue = true;
5507 }
5508
5509 // Do nothing template
5510 private template issue10647_DoNothing(Base)
5511 {
5512 alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue);
5513 }
5514
5515 // A class to be overridden
5516 private class issue10647_Foo{
5517 void bar(int a) { }
5518 }
5519 }
5520
5521 @system unittest
5522 {
5523 auto foo = new issue10647_DoNothing!issue10647_Foo();
5524 foo.bar(13);
5525 }
5526
5527 /*
5528 Used by MemberFunctionGenerator.
5529 */
5530 package template OverloadSet(string nam, T...)
5531 {
5532 enum string name = nam;
5533 alias contents = T;
5534 }
5535
5536 /*
5537 Used by MemberFunctionGenerator.
5538 */
5539 package template FuncInfo(alias func)
5540 if (is(typeof(&func)))
5541 {
5542 alias RT = ReturnType!(typeof(&func));
5543 alias PT = Parameters!(typeof(&func));
5544 }
5545 package template FuncInfo(Func)
5546 {
5547 alias RT = ReturnType!Func;
5548 alias PT = Parameters!Func;
5549 }
5550
5551 /*
5552 General-purpose member function generator.
5553 --------------------
5554 template GeneratingPolicy()
5555 {
5556 // [optional] the name of the class where functions are derived
5557 enum string BASE_CLASS_ID;
5558
5559 // [optional] define this if you have only function types
5560 enum bool WITHOUT_SYMBOL;
5561
5562 // [optional] Returns preferred identifier for i-th parameter.
5563 template PARAMETER_VARIABLE_ID(size_t i);
5564
5565 // Returns the identifier of the FuncInfo instance for the i-th overload
5566 // of the specified name. The identifier must be accessible in the scope
5567 // where generated code is mixed.
5568 template FUNCINFO_ID(string name, size_t i);
5569
5570 // Returns implemented function body as a string. When WITHOUT_SYMBOL is
5571 // defined, the latter is used.
5572 template generateFunctionBody(alias func);
5573 template generateFunctionBody(string name, FuncType);
5574 }
5575 --------------------
5576 */
5577 package template MemberFunctionGenerator(alias Policy)
5578 {
5579 private static:
5580 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5581 // Internal stuffs
5582 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5583 import std.format;
5584 alias format = std.format.format;
5585
5586 enum CONSTRUCTOR_NAME = "__ctor";
5587
5588 // true if functions are derived from a base class
5589 enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID");
5590
5591 // true if functions are specified as types, not symbols
5592 enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL");
5593
5594 // preferred identifier for i-th parameter variable
5595 static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID"))
5596 {
5597 alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID;
5598 }
5599 else
5600 {
5601 enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i);
5602 // default: a0, a1, ...
5603 }
5604
5605 // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach.
5606 template CountUp(size_t n)
5607 {
5608 static if (n > 0)
5609 alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1);
5610 else
5611 alias CountUp = AliasSeq!();
5612 }
5613
5614
5615 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5616 // Code generator
5617 //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
5618
5619 /*
5620 * Runs through all the target overload sets and generates D code which
5621 * implements all the functions in the overload sets.
5622 */
5623 public string generateCode(overloads...)() @property
5624 {
5625 string code = "";
5626
5627 // run through all the overload sets
5628 foreach (i_; CountUp!(0 + overloads.length)) // workaround
5629 {
5630 enum i = 0 + i_; // workaround
5631 alias oset = overloads[i];
5632
5633 code ~= generateCodeForOverloadSet!(oset);
5634
5635 static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME)
5636 {
5637 // The generated function declarations may hide existing ones
5638 // in the base class (cf. HiddenFuncError), so we put an alias
5639 // declaration here to reveal possible hidden functions.
5640 code ~= format("alias %s = %s.%s;\n",
5641 oset.name,
5642 // super: https://issues.dlang.org/show_bug.cgi?id=2540
5643 Policy.BASE_CLASS_ID,
5644 oset.name);
5645 }
5646 }
5647 return code;
5648 }
5649
5650 // handle each overload set
5651 string generateCodeForOverloadSet(alias oset)() @property
5652 {
5653 string code = "";
5654
5655 foreach (i_; CountUp!(0 + oset.contents.length)) // workaround
5656 {
5657 enum i = 0 + i_; // workaround
5658 code ~= generateFunction!(
5659 Policy.FUNCINFO_ID!(oset.name, i), oset.name,
5660 oset.contents[i]) ~ "\n";
5661 }
5662 return code;
5663 }
5664
5665 /*
5666 * Returns D code which implements the function func. This function
5667 * actually generates only the declarator part; the function body part is
5668 * generated by the functionGenerator() policy.
5669 */
5670 public string generateFunction(
5671 string myFuncInfo, string name, func... )() @property
5672 {
5673 import std.format : format;
5674
5675 enum isCtor = (name == CONSTRUCTOR_NAME);
5676
5677 string code; // the result
5678
5679 auto paramsRes = generateParameters!(myFuncInfo, func)();
5680 code ~= paramsRes.imports;
5681
5682 /*** Function Declarator ***/
5683 {
5684 alias Func = FunctionTypeOf!(func);
5685 alias FA = FunctionAttribute;
5686 enum atts = functionAttributes!(func);
5687 enum realName = isCtor ? "this" : name;
5688
5689 // FIXME?? Make it so that these aren't CTFE funcs any more, since
5690 // Format is deprecated, and format works at compile time?
5691 /* Made them CTFE funcs just for the sake of Format!(...) */
5692
5693 // return type with optional "ref"
5694 static string make_returnType()
5695 {
5696 string rtype = "";
5697
5698 if (!isCtor)
5699 {
5700 if (atts & FA.ref_) rtype ~= "ref ";
5701 rtype ~= myFuncInfo ~ ".RT";
5702 }
5703 return rtype;
5704 }
5705 enum returnType = make_returnType();
5706
5707 // function attributes attached after declaration
5708 static string make_postAtts()
5709 {
5710 string poatts = "";
5711 if (atts & FA.pure_ ) poatts ~= " pure";
5712 if (atts & FA.nothrow_) poatts ~= " nothrow";
5713 if (atts & FA.property) poatts ~= " @property";
5714 if (atts & FA.safe ) poatts ~= " @safe";
5715 if (atts & FA.trusted ) poatts ~= " @trusted";
5716 if (atts & FA.scope_ ) poatts ~= " scope";
5717 if (atts & FA.return_ ) poatts ~= " return";
5718 return poatts;
5719 }
5720 enum postAtts = make_postAtts();
5721
5722 // function storage class
5723 static string make_storageClass()
5724 {
5725 string postc = "";
5726 if (is(Func == shared)) postc ~= " shared";
5727 if (is(Func == const)) postc ~= " const";
5728 if (is(Func == inout)) postc ~= " inout";
5729 if (is(Func == immutable)) postc ~= " immutable";
5730 return postc;
5731 }
5732 enum storageClass = make_storageClass();
5733
5734 //
5735 if (__traits(isVirtualMethod, func))
5736 code ~= "override ";
5737 code ~= format("extern(%s) %s %s(%s) %s %s\n",
5738 functionLinkage!(func),
5739 returnType,
5740 realName,
5741 paramsRes.params,
5742 postAtts, storageClass );
5743 }
5744
5745 /*** Function Body ***/
5746 code ~= "{\n";
5747 {
5748 enum nparams = Parameters!(func).length;
5749
5750 /* Declare keywords: args, self and parent. */
5751 string preamble;
5752
5753 preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n";
5754 if (!isCtor)
5755 {
5756 preamble ~= "alias self = " ~ name ~ ";\n";
5757 static if (WITH_BASE_CLASS)
5758 preamble ~= `alias parent = __traits(getMember, ` ~ Policy.BASE_CLASS_ID ~ `, "` ~ name ~ `");`;
5759 }
5760
5761 // Function body
5762 static if (WITHOUT_SYMBOL)
5763 enum fbody = Policy.generateFunctionBody!(name, func);
5764 else
5765 enum fbody = Policy.generateFunctionBody!(func);
5766
5767 code ~= preamble;
5768 code ~= fbody;
5769 }
5770 code ~= "}";
5771
5772 return code;
5773 }
5774
5775 /*
5776 * Returns D code which declares function parameters,
5777 * and optionally any imports (e.g. core.vararg)
5778 * "ref int a0, real a1, ..."
5779 */
5780 static struct GenParams { string imports, params; }
5781 GenParams generateParameters(string myFuncInfo, func...)()
5782 {
5783 alias STC = ParameterStorageClass;
5784 alias stcs = ParameterStorageClassTuple!(func);
5785 enum nparams = stcs.length;
5786
5787 string imports = ""; // any imports required
5788 string params = ""; // parameters
5789
5790 foreach (i, stc; stcs)
5791 {
5792 if (i > 0) params ~= ", ";
5793
5794 // Parameter storage classes.
5795 if (stc & STC.scope_) params ~= "scope ";
5796 if (stc & STC.in_) params ~= "in ";
5797 if (stc & STC.out_ ) params ~= "out ";
5798 if (stc & STC.ref_ ) params ~= "ref ";
5799 if (stc & STC.lazy_ ) params ~= "lazy ";
5800
5801 // Take parameter type from the FuncInfo.
5802 params ~= format("%s.PT[%s]", myFuncInfo, i);
5803
5804 // Declare a parameter variable.
5805 params ~= " " ~ PARAMETER_VARIABLE_ID!(i);
5806 }
5807
5808 // Add some ellipsis part if needed.
5809 auto style = variadicFunctionStyle!(func);
5810 final switch (style)
5811 {
5812 case Variadic.no:
5813 break;
5814
5815 case Variadic.c, Variadic.d:
5816 imports ~= "import core.vararg;\n";
5817 // (...) or (a, b, ...)
5818 params ~= (nparams == 0) ? "..." : ", ...";
5819 break;
5820
5821 case Variadic.typesafe:
5822 params ~= " ...";
5823 break;
5824 }
5825
5826 return typeof(return)(imports, params);
5827 }
5828
5829 // Returns D code which enumerates n parameter variables using comma as the
5830 // separator. "a0, a1, a2, a3"
5831 string enumerateParameters(size_t n)() @property
5832 {
5833 string params = "";
5834
5835 foreach (i_; CountUp!(n))
5836 {
5837 enum i = 0 + i_; // workaround
5838 if (i > 0) params ~= ", ";
5839 params ~= PARAMETER_VARIABLE_ID!(i);
5840 }
5841 return params;
5842 }
5843 }
5844
5845
5846 /**
5847 Predefined how-policies for `AutoImplement`. These templates are also used by
5848 `BlackHole` and `WhiteHole`, respectively.
5849 */
5850 template generateEmptyFunction(C, func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)
5851 {
5852 static if (is(ReturnType!(func) == void))
5853 enum string generateEmptyFunction = q{
5854 };
5855 else static if (functionAttributes!(func) & FunctionAttribute.ref_)
5856 enum string generateEmptyFunction = q{
5857 static typeof(return) dummy;
5858 return dummy;
5859 };
5860 else
5861 enum string generateEmptyFunction = q{
5862 return typeof(return).init;
5863 };
5864 }
5865
5866 ///
5867 @system unittest
5868 {
5869 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction);
5870
5871 interface I
5872 {
5873 int foo();
5874 string bar();
5875 }
5876
5877 auto i = new BlackHole!I();
5878 // generateEmptyFunction returns the default value of the return type without doing anything
5879 assert(i.foo == 0);
5880 assert(i.bar is null);
5881 }
5882
5883 /// ditto
5884 template generateAssertTrap(C, func...)
5885 {
5886 enum string generateAssertTrap =
5887 `throw new NotImplementedError("` ~ C.stringof ~ "."
5888 ~ __traits(identifier, func) ~ `");`;
5889 }
5890
5891 ///
5892 @system unittest
5893 {
5894 import std.exception : assertThrown;
5895
5896 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap);
5897
5898 interface I
5899 {
5900 int foo();
5901 string bar();
5902 }
5903
5904 auto i = new WhiteHole!I();
5905 // generateAssertTrap throws an exception for every unimplemented function of the interface
5906 assertThrown!NotImplementedError(i.foo);
5907 assertThrown!NotImplementedError(i.bar);
5908 }
5909
5910 private
5911 {
5912 pragma(mangle, "_d_toObject")
5913 extern(C) pure nothrow Object typecons_d_toObject(void* p);
5914 }
5915
5916 /*
5917 * Avoids opCast operator overloading.
5918 */
5919 private template dynamicCast(T)
5920 if (is(T == class) || is(T == interface))
5921 {
5922 @trusted
5923 T dynamicCast(S)(inout S source)
5924 if (is(S == class) || is(S == interface))
5925 {
5926 static if (is(Unqual!S : Unqual!T))
5927 {
5928 import std.traits : QualifierOf;
5929 alias Qual = QualifierOf!S; // SharedOf or MutableOf
5930 alias TmpT = Qual!(Unqual!T);
5931 inout(TmpT) tmp = source; // bypass opCast by implicit conversion
5932 return *cast(T*)(&tmp); // + variable pointer cast + dereference
5933 }
5934 else
5935 {
5936 return cast(T) typecons_d_toObject(*cast(void**)(&source));
5937 }
5938 }
5939 }
5940
5941 @system unittest
5942 {
5943 class C { @disable void opCast(T)(); }
5944 auto c = new C;
5945 static assert(!__traits(compiles, cast(Object) c));
5946 auto o = dynamicCast!Object(c);
5947 assert(c is o);
5948
5949 interface I { @disable void opCast(T)(); Object instance(); }
5950 interface J { @disable void opCast(T)(); Object instance(); }
5951 class D : I, J { Object instance() { return this; } }
5952 I i = new D();
5953 static assert(!__traits(compiles, cast(J) i));
5954 J j = dynamicCast!J(i);
5955 assert(i.instance() is j.instance());
5956 }
5957
5958 /**
5959 Supports structural based typesafe conversion.
5960
5961 If `Source` has structural conformance with the `interface` `Targets`,
5962 wrap creates an internal wrapper class which inherits `Targets` and
5963 wraps the `src` object, then returns it.
5964
5965 `unwrap` can be used to extract objects which have been wrapped by `wrap`.
5966 */
5967 template wrap(Targets...)
5968 if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
5969 {
5970 import std.meta : staticMap;
5971
5972 // strict upcast
5973 auto wrap(Source)(inout Source src) @trusted pure nothrow
5974 if (Targets.length == 1 && is(Source : Targets[0]))
5975 {
5976 alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]);
5977 return dynamicCast!(inout T)(src);
5978 }
5979 // structural upcast
5980 template wrap(Source)
5981 if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets))
5982 {
5983 auto wrap(inout Source src)
5984 {
5985 static assert(hasRequireMethods!(),
5986 "Source "~Source.stringof~
5987 " does not have structural conformance to "~
5988 Targets.stringof);
5989
5990 alias T = Select!(is(Source == shared), shared Impl, Impl);
5991 return new inout T(src);
5992 }
5993
5994 template FuncInfo(string s, F)
5995 {
5996 enum name = s;
5997 alias type = F;
5998 }
5999
6000 // https://issues.dlang.org/show_bug.cgi?id=12064: Remove NVI members
6001 template OnlyVirtual(members...)
6002 {
6003 enum notFinal(alias T) = !__traits(isFinalFunction, T);
6004 import std.meta : Filter;
6005 alias OnlyVirtual = Filter!(notFinal, members);
6006 }
6007
6008 // Concat all Targets function members into one tuple
6009 template Concat(size_t i = 0)
6010 {
6011 static if (i >= Targets.length)
6012 alias Concat = AliasSeq!();
6013 else
6014 {
6015 alias Concat = AliasSeq!(OnlyVirtual!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1)));
6016 }
6017 }
6018
6019 // Remove duplicated functions based on the identifier name and function type covariance
6020 template Uniq(members...)
6021 {
6022 static if (members.length == 0)
6023 alias Uniq = AliasSeq!();
6024 else
6025 {
6026 alias func = members[0];
6027 enum name = __traits(identifier, func);
6028 alias type = FunctionTypeOf!func;
6029 template check(size_t i, mem...)
6030 {
6031 static if (i >= mem.length)
6032 enum ptrdiff_t check = -1;
6033 else
6034 {
6035 enum ptrdiff_t check =
6036 __traits(identifier, func) == __traits(identifier, mem[i]) &&
6037 !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void)
6038 ? i : check!(i + 1, mem);
6039 }
6040 }
6041 enum ptrdiff_t x = 1 + check!(0, members[1 .. $]);
6042 static if (x >= 1)
6043 {
6044 alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x]));
6045 alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]);
6046
6047 static if (remain.length >= 1 && remain[0].name == name &&
6048 !is(DerivedFunctionType!(typex, remain[0].type) == void))
6049 {
6050 alias F = DerivedFunctionType!(typex, remain[0].type);
6051 alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]);
6052 }
6053 else
6054 alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain);
6055 }
6056 else
6057 {
6058 alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $]));
6059 }
6060 }
6061 }
6062 alias TargetMembers = Uniq!(Concat!()); // list of FuncInfo
6063 alias SourceMembers = GetOverloadedMethods!Source; // list of function symbols
6064
6065 // Check whether all of SourceMembers satisfy covariance target in TargetMembers
6066 template hasRequireMethods(size_t i = 0)
6067 {
6068 static if (i >= TargetMembers.length)
6069 enum hasRequireMethods = true;
6070 else
6071 {
6072 enum hasRequireMethods =
6073 findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 &&
6074 hasRequireMethods!(i + 1);
6075 }
6076 }
6077
6078 // Internal wrapper class
6079 final class Impl : Structural, Targets
6080 {
6081 private:
6082 Source _wrap_source;
6083
6084 this( inout Source s) inout @safe pure nothrow { _wrap_source = s; }
6085 this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; }
6086
6087 // BUG: making private should work with NVI.
6088 protected final inout(Object) _wrap_getSource() inout @trusted
6089 {
6090 return dynamicCast!(inout Object)(_wrap_source);
6091 }
6092
6093 import std.conv : to;
6094 import core.lifetime : forward;
6095 template generateFun(size_t i)
6096 {
6097 enum name = TargetMembers[i].name;
6098 enum fa = functionAttributes!(TargetMembers[i].type);
6099 static @property stc()
6100 {
6101 string r;
6102 if (fa & FunctionAttribute.property) r ~= "@property ";
6103 if (fa & FunctionAttribute.ref_) r ~= "ref ";
6104 if (fa & FunctionAttribute.pure_) r ~= "pure ";
6105 if (fa & FunctionAttribute.nothrow_) r ~= "nothrow ";
6106 if (fa & FunctionAttribute.trusted) r ~= "@trusted ";
6107 if (fa & FunctionAttribute.safe) r ~= "@safe ";
6108 return r;
6109 }
6110 static @property mod()
6111 {
6112 alias type = AliasSeq!(TargetMembers[i].type)[0];
6113 string r;
6114 static if (is(type == immutable)) r ~= " immutable";
6115 else
6116 {
6117 static if (is(type == shared)) r ~= " shared";
6118 static if (is(type == const)) r ~= " const";
6119 else static if (is(type == inout)) r ~= " inout";
6120 //else --> mutable
6121 }
6122 return r;
6123 }
6124 enum n = to!string(i);
6125 static if (fa & FunctionAttribute.property)
6126 {
6127 static if (Parameters!(TargetMembers[i].type).length == 0)
6128 enum fbody = "_wrap_source."~name;
6129 else
6130 enum fbody = "_wrap_source."~name~" = forward!args";
6131 }
6132 else
6133 {
6134 enum fbody = "_wrap_source."~name~"(forward!args)";
6135 }
6136 enum generateFun =
6137 "override "~stc~"ReturnType!(TargetMembers["~n~"].type) "
6138 ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~
6139 "{ return "~fbody~"; }";
6140 }
6141
6142 public:
6143 static foreach (i; 0 .. TargetMembers.length)
6144 mixin(generateFun!i);
6145 }
6146 }
6147 }
6148 /// ditto
6149 template wrap(Targets...)
6150 if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets))
6151 {
6152 import std.meta : staticMap;
6153
6154 alias wrap = .wrap!(staticMap!(Unqual, Targets));
6155 }
6156
6157 /// ditto
6158 template unwrap(Target)
6159 if (isMutable!Target)
6160 {
6161 // strict downcast
6162 auto unwrap(Source)(inout Source src) @trusted pure nothrow
6163 if (is(Target : Source))
6164 {
6165 alias T = Select!(is(Source == shared), shared Target, Target);
6166 return dynamicCast!(inout T)(src);
6167 }
6168 // structural downcast
6169 auto unwrap(Source)(inout Source src) @trusted pure nothrow
6170 if (!is(Target : Source))
6171 {
6172 alias T = Select!(is(Source == shared), shared Target, Target);
6173 Object o = dynamicCast!(Object)(src); // remove qualifier
6174 do
6175 {
6176 if (auto a = dynamicCast!(Structural)(o))
6177 {
6178 if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource()))
6179 return d;
6180 }
6181 else if (auto d = dynamicCast!(inout T)(o))
6182 return d;
6183 else
6184 break;
6185 } while (o);
6186 return null;
6187 }
6188 }
6189
6190 /// ditto
6191 template unwrap(Target)
6192 if (!isMutable!Target)
6193 {
6194 alias unwrap = .unwrap!(Unqual!Target);
6195 }
6196
6197 ///
6198 @system unittest
6199 {
6200 interface Quack
6201 {
6202 int quack();
6203 @property int height();
6204 }
6205 interface Flyer
6206 {
6207 @property int height();
6208 }
6209 class Duck : Quack
6210 {
6211 int quack() { return 1; }
6212 @property int height() { return 10; }
6213 }
6214 class Human
6215 {
6216 int quack() { return 2; }
6217 @property int height() { return 20; }
6218 }
6219
6220 Duck d1 = new Duck();
6221 Human h1 = new Human();
6222
6223 interface Refleshable
6224 {
6225 int reflesh();
6226 }
6227
6228 // does not have structural conformance
6229 static assert(!__traits(compiles, d1.wrap!Refleshable));
6230 static assert(!__traits(compiles, h1.wrap!Refleshable));
6231
6232 // strict upcast
6233 Quack qd = d1.wrap!Quack;
6234 assert(qd is d1);
6235 assert(qd.quack() == 1); // calls Duck.quack
6236 // strict downcast
6237 Duck d2 = qd.unwrap!Duck;
6238 assert(d2 is d1);
6239
6240 // structural upcast
6241 Quack qh = h1.wrap!Quack;
6242 assert(qh.quack() == 2); // calls Human.quack
6243 // structural downcast
6244 Human h2 = qh.unwrap!Human;
6245 assert(h2 is h1);
6246
6247 // structural upcast (two steps)
6248 Quack qx = h1.wrap!Quack; // Human -> Quack
6249 Flyer fx = qx.wrap!Flyer; // Quack -> Flyer
6250 assert(fx.height == 20); // calls Human.height
6251 // structural downcast (two steps)
6252 Quack qy = fx.unwrap!Quack; // Flyer -> Quack
6253 Human hy = qy.unwrap!Human; // Quack -> Human
6254 assert(hy is h1);
6255 // structural downcast (one step)
6256 Human hz = fx.unwrap!Human; // Flyer -> Human
6257 assert(hz is h1);
6258 }
6259
6260 ///
6261 @system unittest
6262 {
6263 import std.traits : FunctionAttribute, functionAttributes;
6264 interface A { int run(); }
6265 interface B { int stop(); @property int status(); }
6266 class X
6267 {
6268 int run() { return 1; }
6269 int stop() { return 2; }
6270 @property int status() { return 3; }
6271 }
6272
6273 auto x = new X();
6274 auto ab = x.wrap!(A, B);
6275 A a = ab;
6276 B b = ab;
6277 assert(a.run() == 1);
6278 assert(b.stop() == 2);
6279 assert(b.status == 3);
6280 static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
6281 }
6282
6283 // Internal class to support dynamic cross-casting
6284 private interface Structural
6285 {
6286 inout(Object) _wrap_getSource() inout @safe pure nothrow;
6287 }
6288
6289 @system unittest
6290 {
6291 class A
6292 {
6293 int draw() { return 1; }
6294 int draw(int v) { return v; }
6295
6296 int draw() const { return 2; }
6297 int draw() shared { return 3; }
6298 int draw() shared const { return 4; }
6299 int draw() immutable { return 5; }
6300 }
6301 interface Drawable
6302 {
6303 int draw();
6304 int draw() const;
6305 int draw() shared;
6306 int draw() shared const;
6307 int draw() immutable;
6308 }
6309 interface Drawable2
6310 {
6311 int draw(int v);
6312 }
6313
6314 auto ma = new A();
6315 auto sa = new shared A();
6316 auto ia = new immutable A();
6317 {
6318 Drawable md = ma.wrap!Drawable;
6319 const Drawable cd = ma.wrap!Drawable;
6320 shared Drawable sd = sa.wrap!Drawable;
6321 shared const Drawable scd = sa.wrap!Drawable;
6322 immutable Drawable id = ia.wrap!Drawable;
6323 assert( md.draw() == 1);
6324 assert( cd.draw() == 2);
6325 assert( sd.draw() == 3);
6326 assert(scd.draw() == 4);
6327 assert( id.draw() == 5);
6328 }
6329 {
6330 Drawable2 d = ma.wrap!Drawable2;
6331 static assert(!__traits(compiles, d.draw()));
6332 assert(d.draw(10) == 10);
6333 }
6334 }
6335
6336 // https://issues.dlang.org/show_bug.cgi?id=10377
6337 @system unittest
6338 {
6339 import std.range, std.algorithm;
6340
6341 interface MyInputRange(T)
6342 {
6343 @property T front();
6344 void popFront();
6345 @property bool empty();
6346 }
6347
6348 //auto o = iota(0,10,1).inputRangeObject();
6349 //pragma(msg, __traits(allMembers, typeof(o)));
6350 auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)();
6351 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
6352 }
6353
6354 // https://issues.dlang.org/show_bug.cgi?id=10536
6355 @system unittest
6356 {
6357 interface Interface
6358 {
6359 int foo();
6360 }
6361 class Pluggable
6362 {
6363 int foo() { return 1; }
6364 @disable void opCast(T, this X)(); // !
6365 }
6366
6367 Interface i = new Pluggable().wrap!Interface;
6368 assert(i.foo() == 1);
6369 }
6370 @system unittest
6371 {
6372 // Enhancement 10538
6373 interface Interface
6374 {
6375 int foo();
6376 int bar(int);
6377 }
6378 class Pluggable
6379 {
6380 int opDispatch(string name, A...)(A args) { return 100; }
6381 }
6382
6383 Interface i = wrap!Interface(new Pluggable());
6384 assert(i.foo() == 100);
6385 assert(i.bar(10) == 100);
6386 }
6387
6388 // https://issues.dlang.org/show_bug.cgi?id=12064
6389 @system unittest
6390 {
6391 interface I
6392 {
6393 int foo();
6394 final int nvi1(){return foo();}
6395 }
6396
6397 interface J
6398 {
6399 int bar();
6400 final int nvi2(){return bar();}
6401 }
6402
6403 class Baz
6404 {
6405 int foo() { return 42;}
6406 int bar() { return 12064;}
6407 }
6408
6409 auto baz = new Baz();
6410 auto foobar = baz.wrap!(I, J)();
6411 assert(foobar.nvi1 == 42);
6412 assert(foobar.nvi2 == 12064);
6413 }
6414
6415 // Make a tuple of non-static function symbols
6416 package template GetOverloadedMethods(T)
6417 {
6418 import std.meta : Filter;
6419
6420 alias allMembers = __traits(allMembers, T);
6421 template follows(size_t i = 0)
6422 {
6423 static if (i >= allMembers.length)
6424 {
6425 alias follows = AliasSeq!();
6426 }
6427 else static if (!__traits(compiles, mixin("T."~allMembers[i])))
6428 {
6429 alias follows = follows!(i + 1);
6430 }
6431 else
6432 {
6433 enum name = allMembers[i];
6434
6435 template isMethod(alias f)
6436 {
6437 static if (is(typeof(&f) F == F*) && is(F == function))
6438 enum isMethod = !__traits(isStaticFunction, f);
6439 else
6440 enum isMethod = false;
6441 }
6442 alias follows = AliasSeq!(
6443 Filter!(isMethod, __traits(getOverloads, T, name)),
6444 follows!(i + 1));
6445 }
6446 }
6447 alias GetOverloadedMethods = follows!();
6448 }
6449 // find a function from Fs that has same identifier and covariant type with f
6450 private template findCovariantFunction(alias finfo, Source, Fs...)
6451 {
6452 template check(size_t i = 0)
6453 {
6454 static if (i >= Fs.length)
6455 enum ptrdiff_t check = -1;
6456 else
6457 {
6458 enum ptrdiff_t check =
6459 (finfo.name == __traits(identifier, Fs[i])) &&
6460 isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type)
6461 ? i : check!(i + 1);
6462 }
6463 }
6464 enum x = check!();
6465 static if (x == -1 && is(typeof(Source.opDispatch)))
6466 {
6467 alias Params = Parameters!(finfo.type);
6468 enum ptrdiff_t findCovariantFunction =
6469 is(typeof(( Source).init.opDispatch!(finfo.name)(Params.init))) ||
6470 is(typeof(( const Source).init.opDispatch!(finfo.name)(Params.init))) ||
6471 is(typeof(( immutable Source).init.opDispatch!(finfo.name)(Params.init))) ||
6472 is(typeof(( shared Source).init.opDispatch!(finfo.name)(Params.init))) ||
6473 is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init)))
6474 ? ptrdiff_t.max : -1;
6475 }
6476 else
6477 enum ptrdiff_t findCovariantFunction = x;
6478 }
6479
6480 private enum TypeModifier
6481 {
6482 mutable = 0, // type is mutable
6483 const_ = 1, // type is const
6484 immutable_ = 2, // type is immutable
6485 shared_ = 4, // type is shared
6486 inout_ = 8, // type is wild
6487 }
6488 private template TypeMod(T)
6489 {
6490 static if (is(T == immutable))
6491 {
6492 enum mod1 = TypeModifier.immutable_;
6493 enum mod2 = 0;
6494 }
6495 else
6496 {
6497 enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0;
6498 static if (is(T == const))
6499 enum mod2 = TypeModifier.const_;
6500 else static if (is(T == inout))
6501 enum mod2 = TypeModifier.inout_;
6502 else
6503 enum mod2 = TypeModifier.mutable;
6504 }
6505 enum TypeMod = cast(TypeModifier)(mod1 | mod2);
6506 }
6507
6508 @system unittest
6509 {
6510 template UnittestFuncInfo(alias f)
6511 {
6512 enum name = __traits(identifier, f);
6513 alias type = FunctionTypeOf!f;
6514 }
6515
6516 class A
6517 {
6518 int draw() { return 1; }
6519 @property int value() { return 2; }
6520 final int run() { return 3; }
6521 }
6522 alias methods = GetOverloadedMethods!A;
6523
6524 alias int F1();
6525 alias @property int F2();
6526 alias string F3();
6527 alias nothrow @trusted uint F4();
6528 alias int F5(Object);
6529 alias bool F6(Object);
6530 static assert(methods.length == 3 + 4);
6531 static assert(__traits(identifier, methods[0]) == "draw" && is(typeof(&methods[0]) == F1*));
6532 static assert(__traits(identifier, methods[1]) == "value" && is(typeof(&methods[1]) == F2*));
6533 static assert(__traits(identifier, methods[2]) == "run" && is(typeof(&methods[2]) == F1*));
6534
6535 int draw();
6536 @property int value();
6537 void opEquals();
6538 int nomatch();
6539 static assert(findCovariantFunction!(UnittestFuncInfo!draw, A, methods) == 0);
6540 static assert(findCovariantFunction!(UnittestFuncInfo!value, A, methods) == 1);
6541 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1);
6542 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, A, methods) == -1);
6543
6544 // considering opDispatch
6545 class B
6546 {
6547 void opDispatch(string name, A...)(A) {}
6548 }
6549 alias methodsB = GetOverloadedMethods!B;
6550 static assert(findCovariantFunction!(UnittestFuncInfo!draw, B, methodsB) == ptrdiff_t.max);
6551 static assert(findCovariantFunction!(UnittestFuncInfo!value, B, methodsB) == ptrdiff_t.max);
6552 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max);
6553 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, B, methodsB) == ptrdiff_t.max);
6554 }
6555
6556 package template DerivedFunctionType(T...)
6557 {
6558 static if (!T.length)
6559 {
6560 alias DerivedFunctionType = void;
6561 }
6562 else static if (T.length == 1)
6563 {
6564 static if (is(T[0] == function))
6565 {
6566 alias DerivedFunctionType = T[0];
6567 }
6568 else
6569 {
6570 alias DerivedFunctionType = void;
6571 }
6572 }
6573 else static if (is(T[0] P0 == function) && is(T[1] P1 == function))
6574 {
6575 alias FA = FunctionAttribute;
6576
6577 alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0;
6578 alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1;
6579 enum FA0 = functionAttributes!F0;
6580 enum FA1 = functionAttributes!F1;
6581
6582 template CheckParams(size_t i = 0)
6583 {
6584 static if (i >= P0.length)
6585 enum CheckParams = true;
6586 else
6587 {
6588 enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) &&
6589 CheckParams!(i + 1);
6590 }
6591 }
6592 static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) &&
6593 P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 &&
6594 variadicFunctionStyle!F0 == variadicFunctionStyle!F1 &&
6595 functionLinkage!F0 == functionLinkage!F1 &&
6596 ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0)
6597 {
6598 alias R = Select!(is(R0 : R1), R0, R1);
6599 alias FX = FunctionTypeOf!(R function(P0));
6600 // @system is default
6601 alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system);
6602 alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]);
6603 }
6604 else
6605 alias DerivedFunctionType = void;
6606 }
6607 else
6608 alias DerivedFunctionType = void;
6609 }
6610 @safe unittest
6611 {
6612 // attribute covariance
6613 alias int F1();
6614 static assert(is(DerivedFunctionType!(F1, F1) == F1));
6615 alias int F2() pure nothrow;
6616 static assert(is(DerivedFunctionType!(F1, F2) == F2));
6617 alias int F3() @safe;
6618 alias int F23() @safe pure nothrow;
6619 static assert(is(DerivedFunctionType!(F2, F3) == F23));
6620
6621 // return type covariance
6622 alias long F4();
6623 static assert(is(DerivedFunctionType!(F1, F4) == void));
6624 class C {}
6625 class D : C {}
6626 alias C F5();
6627 alias D F6();
6628 static assert(is(DerivedFunctionType!(F5, F6) == F6));
6629 alias typeof(null) F7();
6630 alias int[] F8();
6631 alias int* F9();
6632 static assert(is(DerivedFunctionType!(F5, F7) == F7));
6633 static assert(is(DerivedFunctionType!(F7, F8) == void));
6634 static assert(is(DerivedFunctionType!(F7, F9) == F7));
6635
6636 // variadic type equality
6637 alias int F10(int);
6638 alias int F11(int...);
6639 alias int F12(int, ...);
6640 static assert(is(DerivedFunctionType!(F10, F11) == void));
6641 static assert(is(DerivedFunctionType!(F10, F12) == void));
6642 static assert(is(DerivedFunctionType!(F11, F12) == void));
6643
6644 // linkage equality
6645 alias extern(C) int F13(int);
6646 alias extern(D) int F14(int);
6647 alias extern(Windows) int F15(int);
6648 static assert(is(DerivedFunctionType!(F13, F14) == void));
6649 static assert(is(DerivedFunctionType!(F13, F15) == void));
6650 static assert(is(DerivedFunctionType!(F14, F15) == void));
6651
6652 // ref & @property equality
6653 alias int F16(int);
6654 alias ref int F17(int);
6655 alias @property int F18(int);
6656 static assert(is(DerivedFunctionType!(F16, F17) == void));
6657 static assert(is(DerivedFunctionType!(F16, F18) == void));
6658 static assert(is(DerivedFunctionType!(F17, F18) == void));
6659 }
6660
6661 package template Bind(alias Template, args1...)
6662 {
6663 alias Bind(args2...) = Template!(args1, args2);
6664 }
6665
6666
6667 /**
6668 Options regarding auto-initialization of a `SafeRefCounted` object (see
6669 the definition of `SafeRefCounted` below).
6670 */
6671 enum RefCountedAutoInitialize
6672 {
6673 /// Do not auto-initialize the object
6674 no,
6675 /// Auto-initialize the object
6676 yes,
6677 }
6678
6679 ///
6680 @system unittest
6681 {
6682 import core.exception : AssertError;
6683 import std.exception : assertThrown;
6684
6685 struct Foo
6686 {
6687 int a = 42;
6688 }
6689
6690 SafeRefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto;
6691 SafeRefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto;
6692
6693 assert(rcAuto.refCountedPayload.a == 42);
6694
6695 assertThrown!AssertError(rcNoAuto.refCountedPayload);
6696 rcNoAuto.refCountedStore.ensureInitialized;
6697 assert(rcNoAuto.refCountedPayload.a == 42);
6698 }
6699
6700 // Same the above but for old RefCounted and not documented
6701 @system unittest
6702 {
6703 import core.exception : AssertError;
6704 import std.exception : assertThrown;
6705
6706 struct Foo
6707 {
6708 int a = 42;
6709 }
6710
6711 RefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto;
6712 RefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto;
6713
6714 assert(rcAuto.refCountedPayload.a == 42);
6715
6716 assertThrown!AssertError(rcNoAuto.refCountedPayload);
6717 rcNoAuto.refCountedStore.ensureInitialized;
6718 assert(rcNoAuto.refCountedPayload.a == 42);
6719 }
6720
6721 /**
6722 Defines a reference-counted object containing a `T` value as
6723 payload.
6724
6725 An instance of `SafeRefCounted` is a reference to a structure,
6726 which is referred to as the $(I store), or $(I storage implementation
6727 struct) in this documentation. The store contains a reference count
6728 and the `T` payload. `SafeRefCounted` uses `malloc` to allocate
6729 the store. As instances of `SafeRefCounted` are copied or go out of
6730 scope, they will automatically increment or decrement the reference
6731 count. When the reference count goes down to zero, `SafeRefCounted`
6732 will call `destroy` against the payload and call `free` to
6733 deallocate the store. If the `T` payload contains any references
6734 to GC-allocated memory, then `SafeRefCounted` will add it to the GC memory
6735 that is scanned for pointers, and remove it from GC scanning before
6736 `free` is called on the store.
6737
6738 One important consequence of `destroy` is that it will call the
6739 destructor of the `T` payload. GC-managed references are not
6740 guaranteed to be valid during a destructor call, but other members of
6741 `T`, such as file handles or pointers to `malloc` memory, will
6742 still be valid during the destructor call. This allows the `T` to
6743 deallocate or clean up any non-GC resources immediately after the
6744 reference count has reached zero.
6745
6746 Without -preview=dip1000, `SafeRefCounted` is unsafe and should be
6747 used with care. No references to the payload should be escaped outside
6748 the `SafeRefCounted` object.
6749
6750 With -preview=dip1000, `SafeRefCounted` is safe if it's payload is accessed only
6751 with the $(LREF borrow) function. Scope semantics can also prevent accidental
6752 escaping of `refCountedPayload`, but it's still up to the user to not destroy
6753 the last counted reference while the payload is in use. Due to that,
6754 `refCountedPayload` remains accessible only in `@system` code.
6755
6756 The `autoInit` option makes the object ensure the store is
6757 automatically initialized. Leaving $(D autoInit ==
6758 RefCountedAutoInitialize.yes) (the default option) is convenient but
6759 has the cost of a test whenever the payload is accessed. If $(D
6760 autoInit == RefCountedAutoInitialize.no), user code must call either
6761 `refCountedStore.isInitialized` or `refCountedStore.ensureInitialized`
6762 before attempting to access the payload. Not doing so results in null
6763 pointer dereference.
6764
6765 If `T.this()` is annotated with `@disable` then `autoInit` must be
6766 `RefCountedAutoInitialize.no` in order to compile.
6767
6768 See_Also:
6769 $(LREF RefCounted)
6770 */
6771 struct SafeRefCounted(T, RefCountedAutoInitialize autoInit =
6772 RefCountedAutoInitialize.yes)
6773 if (!is(T == class) && !(is(T == interface)))
6774 {
6775 version (D_BetterC)
6776 {
6777 private enum enableGCScan = false;
6778 }
6779 else
6780 {
6781 private enum enableGCScan = hasIndirections!T;
6782 }
6783
6784 extern(C) private pure nothrow @nogc static
6785 {
6786 pragma(mangle, "free") void pureFree( void *ptr );
6787 static if (enableGCScan)
6788 import core.memory : GC;
6789 }
6790
6791 pragma(inline, true) private void checkInit()()
6792 if (autoInit == RefCountedAutoInitialize.yes)
6793 {
6794 _refCounted.ensureInitialized();
6795 }
6796
6797 pragma(inline, true) private void checkInit()() inout
6798 if (autoInit == RefCountedAutoInitialize.no)
6799 {
6800 assert(_refCounted.isInitialized,
6801 "Attempted to use an uninitialized payload.");
6802 }
6803
6804 /// `SafeRefCounted` storage implementation.
6805 struct RefCountedStore
6806 {
6807 private struct Impl
6808 {
6809 T _payload;
6810 size_t _count;
6811 }
6812
6813 private Impl* _store;
6814
6815 private void initialize(A...)(auto ref A args)
6816 {
6817 import core.lifetime : emplace, forward;
6818
6819 allocateStore();
6820 version (D_Exceptions) scope(failure) () @trusted { deallocateStore(); }();
6821 emplace(&_store._payload, forward!args);
6822 _store._count = 1;
6823 }
6824
6825 private void move(ref T source) nothrow pure
6826 {
6827 import std.algorithm.mutation : moveEmplace;
6828
6829 allocateStore();
6830 () @trusted { moveEmplace(source, _store._payload); }();
6831 _store._count = 1;
6832 }
6833
6834 // 'nothrow': can only generate an Error
6835 private void allocateStore() nothrow pure
6836 {
6837 static if (enableGCScan)
6838 {
6839 import std.internal.memory : enforceCalloc;
6840 auto ptr = enforceCalloc(1, Impl.sizeof);
6841 _store = () @trusted { return cast(Impl*) ptr; }();
6842 () @trusted { GC.addRange(&_store._payload, T.sizeof); }();
6843 }
6844 else
6845 {
6846 import std.internal.memory : enforceMalloc;
6847 auto ptr = enforceMalloc(Impl.sizeof);
6848 _store = () @trusted { return cast(Impl*) ptr; }();
6849 }
6850 }
6851
6852 private void deallocateStore() nothrow pure
6853 {
6854 static if (enableGCScan)
6855 {
6856 GC.removeRange(&this._store._payload);
6857 }
6858 pureFree(_store);
6859 _store = null;
6860 }
6861
6862 /**
6863 Returns `true` if and only if the underlying store has been
6864 allocated and initialized.
6865 */
6866 @property nothrow @safe pure @nogc
6867 bool isInitialized() const
6868 {
6869 return _store !is null;
6870 }
6871
6872 /**
6873 Returns underlying reference count if it is allocated and initialized
6874 (a positive integer), and `0` otherwise.
6875 */
6876 @property nothrow @safe pure @nogc
6877 size_t refCount() const
6878 {
6879 return isInitialized ? _store._count : 0;
6880 }
6881
6882 /**
6883 Makes sure the payload was properly initialized. Such a
6884 call is typically inserted before using the payload.
6885
6886 This function is unavailable if `T.this()` is annotated with
6887 `@disable`.
6888 */
6889 @safe pure nothrow
6890 void ensureInitialized()()
6891 {
6892 // By checking for `@disable this()` and failing early we can
6893 // produce a clearer error message.
6894 static assert(__traits(compiles, { static T t; }),
6895 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~
6896 "` because `" ~ fullyQualifiedName!T ~
6897 ".this()` is annotated with `@disable`.");
6898 if (!isInitialized) initialize();
6899 }
6900
6901 }
6902 RefCountedStore _refCounted;
6903
6904 /// Returns storage implementation struct.
6905 @property nothrow @safe
6906 ref inout(RefCountedStore) refCountedStore() inout
6907 {
6908 return _refCounted;
6909 }
6910
6911 /**
6912 Constructor that initializes the payload.
6913
6914 Postcondition: `refCountedStore.isInitialized`
6915 */
6916 this(A...)(auto ref A args) if (A.length > 0)
6917 out
6918 {
6919 assert(refCountedStore.isInitialized);
6920 }
6921 do
6922 {
6923 import core.lifetime : forward;
6924 _refCounted.initialize(forward!args);
6925 }
6926
6927 /// Ditto
6928 this(return scope T val)
6929 {
6930 _refCounted.move(val);
6931 }
6932
6933 /**
6934 Constructor that tracks the reference count appropriately. If $(D
6935 !refCountedStore.isInitialized), does nothing.
6936 */
6937 this(this) @safe pure nothrow @nogc
6938 {
6939 if (!_refCounted.isInitialized) return;
6940 ++_refCounted._store._count;
6941 }
6942
6943 /**
6944 Destructor that tracks the reference count appropriately. If $(D
6945 !refCountedStore.isInitialized), does nothing. When the reference count goes
6946 down to zero, calls `destroy` agaist the payload and calls `free`
6947 to deallocate the corresponding resource.
6948 */
6949 ~this()
6950 {
6951 import std.traits : dip1000Enabled;
6952
6953 // This prevents the same reference from decrementing the count twice.
6954 scope(exit) _refCounted = _refCounted.init;
6955
6956 if (!_refCounted.isInitialized) return;
6957 assert(_refCounted._store._count > 0);
6958 if (--_refCounted._store._count) return;
6959 // Done, destroy and deallocate
6960 .destroy(_refCounted._store._payload);
6961
6962 static if (dip1000Enabled)
6963 {
6964 () @trusted { _refCounted.deallocateStore(); }();
6965 }
6966 else _refCounted.deallocateStore();
6967 }
6968
6969 /**
6970 Assignment operators.
6971
6972 Note: You may not assign a new payload to an uninitialized SafeRefCounted, if
6973 auto initialization is off. Assigning another counted reference is still okay.
6974 */
6975 void opAssign(typeof(this) rhs)
6976 {
6977 import std.algorithm.mutation : swap;
6978
6979 swap(_refCounted._store, rhs._refCounted._store);
6980 }
6981
6982 /// Ditto
6983 void opAssign(T rhs)
6984 {
6985 import std.algorithm.mutation : move;
6986
6987 checkInit();
6988 move(rhs, _refCounted._store._payload);
6989 }
6990
6991 //version to have a single properly ddoc'ed function (w/ correct sig)
6992 version (StdDdoc)
6993 {
6994 /**
6995 Returns a reference to the payload. If (autoInit ==
6996 RefCountedAutoInitialize.yes), calls $(D
6997 refCountedStore.ensureInitialized). Otherwise, just issues $(D
6998 assert(refCountedStore.isInitialized)). Used with $(D alias
6999 refCountedPayload this;), so callers can just use the `SafeRefCounted`
7000 object as a `T`.
7001
7002 $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
7003 So if $(D autoInit == RefCountedAutoInitialize.no)
7004 or called for a constant or immutable object, then
7005 `refCountedPayload` will also be qualified as nothrow
7006 (but will still assert if not initialized).
7007 */
7008 @property @system
7009 ref T refCountedPayload() return;
7010
7011 /// ditto
7012 @property nothrow @system pure @nogc
7013 ref inout(T) refCountedPayload() inout return;
7014 }
7015 else
7016 {
7017 static if (autoInit == RefCountedAutoInitialize.yes)
7018 {
7019 //Can't use inout here because of potential mutation
7020 @property @system
7021 ref T refCountedPayload() return
7022 {
7023 checkInit();
7024 return _refCounted._store._payload;
7025 }
7026 }
7027 else
7028 {
7029 @property nothrow @system pure @nogc
7030 ref inout(T) refCountedPayload() inout return
7031 {
7032 checkInit();
7033 return _refCounted._store._payload;
7034 }
7035 }
7036 }
7037
7038 /**
7039 Returns a reference to the payload. If (autoInit ==
7040 RefCountedAutoInitialize.yes), calls $(D
7041 refCountedStore.ensureInitialized). Otherwise, just issues $(D
7042 assert(refCountedStore.isInitialized)).
7043 */
7044 alias refCountedPayload this;
7045
7046 static if (is(T == struct) && !is(typeof((ref T t) => t.toString())))
7047 {
7048 string toString(this This)()
7049 {
7050 import std.conv : to;
7051
7052 static if (autoInit)
7053 return to!string(refCountedPayload);
7054 else
7055 {
7056 if (!_refCounted.isInitialized)
7057 return This.stringof ~ "(RefCountedStore(null))";
7058 else
7059 return to!string(_refCounted._store._payload);
7060 }
7061 }
7062 }
7063 }
7064
7065 ///
7066 @betterC pure @system nothrow @nogc unittest
7067 {
7068 // A pair of an `int` and a `size_t` - the latter being the
7069 // reference count - will be dynamically allocated
7070 auto rc1 = SafeRefCounted!int(5);
7071 assert(rc1 == 5);
7072 // No more allocation, add just one extra reference count
7073 auto rc2 = rc1;
7074 // Reference semantics
7075 rc2 = 42;
7076 assert(rc1 == 42);
7077 // the pair will be freed when rc1 and rc2 go out of scope
7078 }
7079
7080 // This test can't be betterC because the test extractor won't see the private
7081 // `initialize` method accessed here
7082 pure @safe nothrow @nogc unittest
7083 {
7084 auto rc1 = SafeRefCounted!(int, RefCountedAutoInitialize.no)(5);
7085 rc1._refCounted.initialize();
7086 }
7087
7088 pure @system unittest
7089 {
7090 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7091 {
7092 MyRefCounted!int* p;
7093 {
7094 auto rc1 = MyRefCounted!int(5);
7095 p = &rc1;
7096 assert(rc1 == 5);
7097 assert(rc1._refCounted._store._count == 1);
7098 auto rc2 = rc1;
7099 assert(rc1._refCounted._store._count == 2);
7100 // Reference semantics
7101 rc2 = 42;
7102 assert(rc1 == 42);
7103 rc2 = rc2;
7104 assert(rc2._refCounted._store._count == 2);
7105 rc1 = rc2;
7106 assert(rc1._refCounted._store._count == 2);
7107 }
7108 assert(p._refCounted._store == null);
7109
7110 // [Safe]RefCounted as a member
7111 struct A
7112 {
7113 MyRefCounted!int x;
7114 this(int y)
7115 {
7116 x._refCounted.initialize(y);
7117 }
7118 A copy()
7119 {
7120 auto another = this;
7121 return another;
7122 }
7123 }
7124 auto a = A(4);
7125 auto b = a.copy();
7126 assert(a.x._refCounted._store._count == 2,
7127 "https://issues.dlang.org/show_bug.cgi?id=4356 still unfixed");
7128 }
7129 }
7130
7131 @betterC pure @safe nothrow @nogc unittest
7132 {
7133 import std.algorithm.mutation : swap;
7134
7135 SafeRefCounted!int p1, p2;
7136 swap(p1, p2);
7137 }
7138
7139 // Same as above but for old RefCounted and not @safe
7140 @betterC pure @system nothrow @nogc unittest
7141 {
7142 import std.algorithm.mutation : swap;
7143
7144 RefCounted!int p1, p2;
7145 swap(p1, p2);
7146 }
7147
7148 // https://issues.dlang.org/show_bug.cgi?id=6606
7149 @betterC @safe pure nothrow @nogc unittest
7150 {
7151 union U {
7152 size_t i;
7153 void* p;
7154 }
7155
7156 struct S {
7157 U u;
7158 }
7159
7160 alias SRC = SafeRefCounted!S;
7161 }
7162
7163 // Same as above but for old RefCounted and not @safe
7164 @betterC @system pure nothrow @nogc unittest
7165 {
7166 union U {
7167 size_t i;
7168 void* p;
7169 }
7170
7171 struct S {
7172 U u;
7173 }
7174
7175 alias SRC = RefCounted!S;
7176 }
7177
7178 // https://issues.dlang.org/show_bug.cgi?id=6436
7179 @betterC @system pure unittest
7180 {
7181 import std.meta : AliasSeq;
7182 struct S
7183 {
7184 this(int rval) { assert(rval == 1); }
7185 this(ref int lval) { assert(lval == 3); ++lval; }
7186 }
7187
7188 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7189 {
7190 auto s1 = MyRefCounted!S(1);
7191 int lval = 3;
7192 auto s2 = MyRefCounted!S(lval);
7193 assert(lval == 4);
7194 }
7195 }
7196
7197 // gc_addRange coverage
7198 @betterC @safe pure unittest
7199 {
7200 struct S { int* p; }
7201
7202 auto s = SafeRefCounted!S(null);
7203 }
7204
7205 // Same as above but for old RefCounted and not @safe
7206 @betterC @system pure unittest
7207 {
7208 struct S { int* p; }
7209
7210 auto s = RefCounted!S(null);
7211 }
7212
7213 @betterC @system pure nothrow @nogc unittest
7214 {
7215 import std.meta : AliasSeq;
7216 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7217 {
7218 MyRefCounted!int a;
7219 a = 5; //This should not assert
7220 assert(a == 5);
7221
7222 MyRefCounted!int b;
7223 b = a; //This should not assert either
7224 assert(b == 5);
7225
7226 MyRefCounted!(int*) c;
7227 }
7228 }
7229
7230 // https://issues.dlang.org/show_bug.cgi?id=21638
7231 @betterC @system pure nothrow @nogc unittest
7232 {
7233 import std.meta : AliasSeq;
7234 static struct NoDefaultCtor
7235 {
7236 @disable this();
7237 this(int x) @nogc nothrow pure { this.x = x; }
7238 int x;
7239 }
7240
7241 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted))
7242 {
7243 auto rc = MyRefCounted!(NoDefaultCtor, RefCountedAutoInitialize.no)(5);
7244 assert(rc.x == 5);
7245 }
7246 }
7247
7248 // https://issues.dlang.org/show_bug.cgi?id=20502
7249 @system unittest
7250 {
7251 alias Types = AliasSeq!(SafeRefCounted, RefCounted);
7252 alias funcs = AliasSeq!(safeRefCounted, refCounted);
7253 static foreach (aliasI; 0 .. 2)
7254 {{
7255 alias MyRefCounted = Types[aliasI];
7256 alias myRefCounted = funcs[aliasI];
7257 import std.conv : to;
7258
7259 // Check that string conversion is transparent for refcounted
7260 // structs that do not have either toString or alias this.
7261 static struct A { Object a; }
7262 auto a = A(new Object());
7263 auto r = myRefCounted(a);
7264 assert(to!string(r) == to!string(a));
7265 assert(to!string(cast(const) r) == to!string(cast(const) a));
7266 // Check that string conversion is still transparent for refcounted
7267 // structs that have alias this.
7268 static struct B { int b; alias b this; }
7269 static struct C { B b; alias b this; }
7270 assert(to!string(myRefCounted(C(B(123)))) == to!string(C(B(123))));
7271 // https://issues.dlang.org/show_bug.cgi?id=22093
7272 // Check that uninitialized refcounted structs that previously could be
7273 // converted to strings still can be.
7274 alias R = typeof(r);
7275 R r2;
7276 cast(void) (((const ref R a) => to!string(a))(r2));
7277 cast(void) to!string(MyRefCounted!(A, RefCountedAutoInitialize.no).init);
7278 }}
7279 }
7280
7281 // We tried to make `refCountedPayload` `@safe` in
7282 // https://github.com/dlang/phobos/pull/8368 . It proved impossible, but it may
7283 // be possible in the future. This test checks for false `@safe` issues we
7284 // encountered.
7285 @safe unittest
7286 {
7287 struct Container
7288 {
7289 int[] data;
7290 }
7291
7292 int[] getArr1 (scope Container local)
7293 {
7294 // allowed because the argument is inferred as return scope.
7295 return local.data;
7296 }
7297
7298 int[] getArr2 (scope Container local)
7299 {
7300 SafeRefCounted!Container rc = local;
7301 // Escapes a reference to expired reference counted struct
7302 // don't do this!
7303 return rc.refCountedPayload().data;
7304 }
7305
7306 int destroyFirstAndUseLater()
7307 {
7308 auto rc = SafeRefCounted!int(123);
7309 int* ptr = &rc.refCountedPayload();
7310 destroy(rc);
7311 return *ptr;
7312 }
7313
7314 // This is here mainly to test that safety gets inferred correctly for the
7315 // next tests
7316 static assert(isSafe!getArr1);
7317 // https://github.com/dlang/phobos/pull/8101#issuecomment-843017282
7318 // This got apparently fixed automatically by compiler updates.
7319 static assert(!isSafe!getArr2);
7320 // As of writing, this is the issue that is still preventing payload access
7321 // from being `@safe`
7322 static assert(!isSafe!destroyFirstAndUseLater);
7323 }
7324
7325 /**
7326 Borrows the payload of $(LREF SafeRefCounted) for use in `fun`. Inferred as `@safe`
7327 if `fun` is `@safe` and does not escape a reference to the payload.
7328 The reference count will be incremented for the duration of the operation,
7329 so destroying the last reference will not leave dangling references in
7330 `fun`.
7331
7332 Params:
7333 fun = A callable accepting the payload either by value or by reference.
7334 refCount = The counted reference to the payload.
7335 Returns:
7336 The return value of `fun`, if any. `ref` in the return value will be
7337 forwarded.
7338 Issues:
7339 For yet unknown reason, code that uses this function with UFCS syntax
7340 will not be inferred as `@safe`. It will still compile if the code is
7341 explicitly marked `@safe` and nothing in `fun` prevents that.
7342 */
7343 template borrow(alias fun)
7344 {
7345 import std.functional : unaryFun;
7346
7347 auto ref borrow(RC)(RC refCount) if
7348 (
7349 isInstanceOf!(SafeRefCounted, RC)
7350 && is(typeof(unaryFun!fun(refCount.refCountedPayload)))
7351 )
7352 {
7353 refCount.checkInit();
7354
7355 // If `fun` escapes a reference to the payload, it will be inferred
7356 // as unsafe due to the scope storage class here.
7357 scope plPtr = &refCount._refCounted._store._payload;
7358 return unaryFun!fun(*plPtr);
7359
7360 // We destroy our copy of the reference here, automatically destroying
7361 // the payload if `fun` destroyed the last reference outside.
7362 }
7363 }
7364
7365 /// This example can be marked `@safe` with `-preview=dip1000`.
7366 @safe pure nothrow unittest
7367 {
7368 auto rcInt = safeRefCounted(5);
7369 assert(rcInt.borrow!(theInt => theInt) == 5);
7370 auto sameInt = rcInt;
7371 assert(sameInt.borrow!"a" == 5);
7372
7373 // using `ref` in the function
7374 auto arr = [0, 1, 2, 3, 4, 5, 6];
7375 sameInt.borrow!(ref (x) => arr[x]) = 10;
7376 assert(arr == [0, 1, 2, 3, 4, 10, 6]);
7377
7378 // modifying the payload via an alias
7379 sameInt.borrow!"a*=2";
7380 assert(rcInt.borrow!"a" == 10);
7381 }
7382
7383 // Some memory safety penetration testing.
7384 @system unittest
7385 {
7386 int* globalPtr;
7387 int torpedoesFired = 0;
7388 struct Destroyer { ~this() @safe { torpedoesFired++; } }
7389
7390 alias RcInt = typeof(safeRefCounted(0));
7391 auto standardUsage(RcInt arg)
7392 {
7393 return borrow!((ref x) => x)(arg);
7394 }
7395 ref harmlessRefReturn(RcInt arg)
7396 {
7397 return borrow!(ref (ref x) => *globalPtr = x)(arg);
7398 }
7399 ref problematicRefReturn(RcInt arg)
7400 {
7401 return borrow!(ref (ref x) => x)(arg);
7402 }
7403 auto sideChannelEscape(RcInt arg)
7404 {
7405 return borrow!((ref x)
7406 {
7407 globalPtr = &x;
7408 return x;
7409 })(arg);
7410 }
7411 auto destroyDuringApply()
7412 {
7413 auto rc = safeRefCounted(Destroyer());
7414 return borrow!((ref x)
7415 {
7416 // Destroys the last reference to the payload, decrementing it's
7417 // reference count.
7418 rc.__dtor();
7419 // Destroy again! rc should be set to it's init value so that this
7420 // won't decrement the reference count of the original payload.
7421 rc.__dtor();
7422 // The internal reference count increment done for duration of
7423 // `apply` should make sure that the payload destructor is not yet
7424 // run, and this value thus not incremented.
7425 return torpedoesFired;
7426 })(rc);
7427 }
7428
7429 // First, let's verify the dangerous functions really do what they are
7430 // supposed to do.
7431 auto testRc = safeRefCounted(42);
7432 assert(sideChannelEscape(testRc) == 42);
7433 assert(&problematicRefReturn(testRc) == globalPtr);
7434
7435 // Now, are the @safe attributes inferred correctly?
7436 assert(isSafe!standardUsage);
7437 assert(isSafe!harmlessRefReturn);
7438 assert(!isSafe!problematicRefReturn);
7439 assert(!isSafe!sideChannelEscape);
7440 assert(isSafe!destroyDuringApply);
7441
7442 // Finally, we test protection against early destruction during `apply`.
7443 auto torpedoesUpToReturn = destroyDuringApply();
7444 assert(torpedoesFired == torpedoesUpToReturn + 1);
7445 }
7446
7447 /**
7448 * Initializes a `SafeRefCounted` with `val`. The template parameter
7449 * `T` of `SafeRefCounted` is inferred from `val`.
7450 * This function can be used to move non-copyable values to the heap.
7451 * It also disables the `autoInit` option of `SafeRefCounted`.
7452 *
7453 * Params:
7454 * val = The value to be reference counted
7455 * Returns:
7456 * An initialized `SafeRefCounted` containing `val`.
7457 * See_Also:
7458 * $(LREF refCounted)
7459 * $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared)
7460 */
7461 SafeRefCounted!(T, RefCountedAutoInitialize.no) safeRefCounted(T)(T val)
7462 {
7463 typeof(return) res;
7464 res._refCounted.move(val);
7465 return res;
7466 }
7467
7468 ///
7469 @system unittest
7470 {
7471 static struct File
7472 {
7473 static size_t nDestroyed;
7474 string name;
7475 @disable this(this); // not copyable
7476 ~this() { name = null; ++nDestroyed; }
7477 }
7478
7479 auto file = File("name");
7480 assert(file.name == "name");
7481 // file cannot be copied and has unique ownership
7482 static assert(!__traits(compiles, {auto file2 = file;}));
7483
7484 assert(File.nDestroyed == 0);
7485
7486 // make the file ref counted to share ownership
7487 // Note:
7488 // We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted.
7489 // This allows us to see (after the scope) what happens after all handles have been destroyed.
7490 {
7491 // We move the content of `file` to a separate (and heap-allocated) `File` object,
7492 // managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles").
7493 // This "moving":
7494 // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`);
7495 // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`).
7496 // It appears that writing `name = null;` in the destructor is redundant,
7497 // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator),
7498 // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor.
7499 import std.algorithm.mutation : move;
7500 auto rcFile = safeRefCounted(move(file));
7501 assert(rcFile.name == "name");
7502 assert(File.nDestroyed == 1);
7503 assert(file.name == null);
7504
7505 // We create another `SafeRefCounted!File` handle to the same separate `File` object.
7506 // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified).
7507 auto rcFile2 = rcFile;
7508 assert(rcFile.refCountedStore.refCount == 2);
7509 assert(File.nDestroyed == 1);
7510 }
7511 // The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed
7512 // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`)
7513 // (=> `File.nDestroyed` is incremented again, from 1 to 2):
7514 assert(File.nDestroyed == 2);
7515 }
7516
7517 /**
7518 Creates a proxy for the value `a` that will forward all operations
7519 while disabling implicit conversions. The aliased item `a` must be
7520 an $(B lvalue). This is useful for creating a new type from the
7521 "base" type (though this is $(B not) a subtype-supertype
7522 relationship; the new type is not related to the old type in any way,
7523 by design).
7524
7525 The new type supports all operations that the underlying type does,
7526 including all operators such as `+`, `--`, `<`, `[]`, etc.
7527
7528 Params:
7529 a = The value to act as a proxy for all operations. It must
7530 be an lvalue.
7531 */
7532 mixin template Proxy(alias a)
7533 {
7534 private alias ValueType = typeof({ return a; }());
7535
7536 /* Determine if 'T.a' can referenced via a const(T).
7537 * Use T* as the parameter because 'scope' inference needs a fully
7538 * analyzed T, which doesn't work when accessibleFrom() is used in a
7539 * 'static if' in the definition of Proxy or T.
7540 */
7541 private enum bool accessibleFrom(T) =
7542 is(typeof((T* self){ cast(void) mixin("(*self)."~__traits(identifier, a)); }));
7543
7544 static if (is(typeof(this) == class))
7545 {
7546 override bool opEquals(Object o)
7547 {
7548 if (auto b = cast(typeof(this))o)
7549 {
7550 return a == mixin("b."~__traits(identifier, a));
7551 }
7552 return false;
7553 }
7554
7555 bool opEquals(T)(T b)
7556 if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
7557 {
7558 static if (is(typeof(a.opEquals(b))))
7559 return a.opEquals(b);
7560 else static if (is(typeof(b.opEquals(a))))
7561 return b.opEquals(a);
7562 else
7563 return a == b;
7564 }
7565
7566 override int opCmp(Object o)
7567 {
7568 if (auto b = cast(typeof(this))o)
7569 {
7570 return a < mixin("b."~__traits(identifier, a)) ? -1
7571 : a > mixin("b."~__traits(identifier, a)) ? +1 : 0;
7572 }
7573 static if (is(ValueType == class))
7574 return a.opCmp(o);
7575 else
7576 throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString);
7577 }
7578
7579 int opCmp(T)(auto ref const T b)
7580 if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
7581 {
7582 static if (is(typeof(a.opCmp(b))))
7583 return a.opCmp(b);
7584 else static if (is(typeof(b.opCmp(a))))
7585 return -b.opCmp(a);
7586 else
7587 return a < b ? -1 : a > b ? +1 : 0;
7588 }
7589
7590 static if (accessibleFrom!(const typeof(this)))
7591 {
7592 override size_t toHash() const nothrow @safe
7593 {
7594 static if (__traits(compiles, .hashOf(a)))
7595 return .hashOf(a);
7596 else
7597 // Workaround for when .hashOf is not both @safe and nothrow.
7598 {
7599 static if (is(typeof(&a) == ValueType*))
7600 alias v = a;
7601 else
7602 auto v = a; // if a is (property) function
7603 // BUG: Improperly casts away `shared`!
7604 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)());
7605 }
7606 }
7607 }
7608 }
7609 else
7610 {
7611 auto ref opEquals(this X, B)(auto ref B b)
7612 {
7613 static if (is(immutable B == immutable typeof(this)))
7614 {
7615 return a == mixin("b."~__traits(identifier, a));
7616 }
7617 else
7618 return a == b;
7619 }
7620
7621 auto ref opCmp(this X, B)(auto ref B b)
7622 {
7623 static if (is(typeof(a.opCmp(b))))
7624 return a.opCmp(b);
7625 else static if (is(typeof(b.opCmp(a))))
7626 return -b.opCmp(a);
7627 else static if (isFloatingPoint!ValueType || isFloatingPoint!B)
7628 return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan;
7629 else
7630 return a < b ? -1 : (a > b);
7631 }
7632
7633 static if (accessibleFrom!(const typeof(this)))
7634 {
7635 size_t toHash() const nothrow @safe
7636 {
7637 static if (__traits(compiles, .hashOf(a)))
7638 return .hashOf(a);
7639 else
7640 // Workaround for when .hashOf is not both @safe and nothrow.
7641 {
7642 static if (is(typeof(&a) == ValueType*))
7643 alias v = a;
7644 else
7645 auto v = a; // if a is (property) function
7646 // BUG: Improperly casts away `shared`!
7647 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)());
7648 }
7649 }
7650 }
7651 }
7652
7653 auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); }
7654
7655 auto ref opCast(T, this X)() { return cast(T) a; }
7656
7657 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; }
7658 auto ref opSlice(this X )() { return a[]; }
7659 auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b .. e]; }
7660
7661 auto ref opUnary (string op, this X )() { return mixin(op~"a"); }
7662 auto ref opIndexUnary(string op, this X, D...)(auto ref D i) { return mixin(op~"a[i]"); }
7663 auto ref opSliceUnary(string op, this X )() { return mixin(op~"a[]"); }
7664 auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b .. e]"); }
7665
7666 auto ref opBinary(string op, this X, B)(auto ref B b)
7667 if (op == "in" && is(typeof(a in b)) || op != "in")
7668 {
7669 return mixin("a "~op~" b");
7670 }
7671 auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); }
7672
7673 static if (!is(typeof(this) == class))
7674 {
7675 import std.traits;
7676 static if (isAssignable!ValueType)
7677 {
7678 auto ref opAssign(this X)(auto ref typeof(this) v)
7679 {
7680 a = mixin("v."~__traits(identifier, a));
7681 return this;
7682 }
7683 }
7684 else
7685 {
7686 @disable void opAssign(this X)(auto ref typeof(this) v);
7687 }
7688 }
7689
7690 auto ref opAssign (this X, V )(auto ref V v) if (!is(V == typeof(this))) { return a = v; }
7691 auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i) { return a[i] = v; }
7692 auto ref opSliceAssign(this X, V )(auto ref V v) { return a[] = v; }
7693 auto ref opSliceAssign(this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return a[b .. e] = v; }
7694
7695 auto ref opOpAssign (string op, this X, V )(auto ref V v)
7696 {
7697 return mixin("a = a "~op~" v");
7698 }
7699 auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i)
7700 {
7701 return mixin("a[i] " ~op~"= v");
7702 }
7703 auto ref opSliceOpAssign(string op, this X, V )(auto ref V v)
7704 {
7705 return mixin("a[] " ~op~"= v");
7706 }
7707 auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e)
7708 {
7709 return mixin("a[b .. e] "~op~"= v");
7710 }
7711
7712 template opDispatch(string name)
7713 {
7714 static if (is(typeof(__traits(getMember, a, name)) == function))
7715 {
7716 // non template function
7717 auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); }
7718 }
7719 else static if (is(typeof({ enum x = mixin("a."~name); })))
7720 {
7721 // built-in type field, manifest constant, and static non-mutable field
7722 enum opDispatch = mixin("a."~name);
7723 }
7724 else static if (__traits(isTemplate, mixin("a."~name)))
7725 {
7726 // member template
7727 template opDispatch(T...)
7728 {
7729 enum targs = T.length ? "!T" : "";
7730 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
7731 }
7732 }
7733 else
7734 {
7735 // field or property function
7736 @property auto ref opDispatch(this X)() { return mixin("a."~name); }
7737 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
7738 }
7739
7740 }
7741
7742 import std.traits : isArray;
7743
7744 static if (isArray!ValueType)
7745 {
7746 auto opDollar() const { return a.length; }
7747 }
7748 else static if (is(typeof(a.opDollar!0)))
7749 {
7750 auto ref opDollar(size_t pos)() { return a.opDollar!pos(); }
7751 }
7752 else static if (is(typeof(a.opDollar) == function))
7753 {
7754 auto ref opDollar() { return a.opDollar(); }
7755 }
7756 else static if (is(typeof(a.opDollar)))
7757 {
7758 alias opDollar = a.opDollar;
7759 }
7760 }
7761
7762 ///
7763 @safe unittest
7764 {
7765 struct MyInt
7766 {
7767 private int value;
7768 mixin Proxy!value;
7769
7770 this(int n){ value = n; }
7771 }
7772
7773 MyInt n = 10;
7774
7775 // Enable operations that original type has.
7776 ++n;
7777 assert(n == 11);
7778 assert(n * 2 == 22);
7779
7780 void func(int n) { }
7781
7782 // Disable implicit conversions to original type.
7783 //int x = n;
7784 //func(n);
7785 }
7786
7787 ///The proxied value must be an $(B lvalue).
7788 @safe unittest
7789 {
7790 struct NewIntType
7791 {
7792 //Won't work; the literal '1'
7793 //is an rvalue, not an lvalue
7794 //mixin Proxy!1;
7795
7796 //Okay, n is an lvalue
7797 int n;
7798 mixin Proxy!n;
7799
7800 this(int n) { this.n = n; }
7801 }
7802
7803 NewIntType nit = 0;
7804 nit++;
7805 assert(nit == 1);
7806
7807
7808 struct NewObjectType
7809 {
7810 Object obj;
7811 //Ok, obj is an lvalue
7812 mixin Proxy!obj;
7813
7814 this (Object o) { obj = o; }
7815 }
7816
7817 NewObjectType not = new Object();
7818 assert(__traits(compiles, not.toHash()));
7819 }
7820
7821 /**
7822 There is one exception to the fact that the new type is not related to the
7823 old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member)
7824 functions are usable with the new type; they will be forwarded on to the
7825 proxied value.
7826 */
7827 @safe unittest
7828 {
7829 import std.math.traits : isInfinity;
7830
7831 float f = 1.0;
7832 assert(!f.isInfinity);
7833
7834 struct NewFloat
7835 {
7836 float _;
7837 mixin Proxy!_;
7838
7839 this(float f) { _ = f; }
7840 }
7841
7842 NewFloat nf = 1.0f;
7843 assert(!nf.isInfinity);
7844 }
7845
7846 @safe unittest
7847 {
7848 static struct MyInt
7849 {
7850 private int value;
7851 mixin Proxy!value;
7852 this(int n) inout { value = n; }
7853
7854 enum str = "str";
7855 static immutable arr = [1,2,3];
7856 }
7857
7858 static foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt))
7859 {{
7860 T m = 10;
7861 static assert(!__traits(compiles, { int x = m; }));
7862 static assert(!__traits(compiles, { void func(int n){} func(m); }));
7863 assert(m == 10);
7864 assert(m != 20);
7865 assert(m < 20);
7866 assert(+m == 10);
7867 assert(-m == -10);
7868 assert(cast(double) m == 10.0);
7869 assert(m + 10 == 20);
7870 assert(m - 5 == 5);
7871 assert(m * 20 == 200);
7872 assert(m / 2 == 5);
7873 assert(10 + m == 20);
7874 assert(15 - m == 5);
7875 assert(20 * m == 200);
7876 assert(50 / m == 5);
7877 static if (is(T == MyInt)) // mutable
7878 {
7879 assert(++m == 11);
7880 assert(m++ == 11); assert(m == 12);
7881 assert(--m == 11);
7882 assert(m-- == 11); assert(m == 10);
7883 m = m;
7884 m = 20; assert(m == 20);
7885 }
7886 static assert(T.max == int.max);
7887 static assert(T.min == int.min);
7888 static assert(T.init == int.init);
7889 static assert(T.str == "str");
7890 static assert(T.arr == [1,2,3]);
7891 }}
7892 }
7893 @system unittest
7894 {
7895 static struct MyArray
7896 {
7897 private int[] value;
7898 mixin Proxy!value;
7899 this(int[] arr) { value = arr; }
7900 this(immutable int[] arr) immutable { value = arr; }
7901 }
7902
7903 static foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray))
7904 {{
7905 static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; })))
7906 T a = [1,2,3,4].idup; // workaround until qualified ctor is properly supported
7907 else
7908 T a = [1,2,3,4];
7909 assert(a == [1,2,3,4]);
7910 assert(a != [5,6,7,8]);
7911 assert(+a[0] == 1);
7912 version (LittleEndian)
7913 assert(cast(ulong[]) a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]);
7914 else
7915 assert(cast(ulong[]) a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]);
7916 assert(a ~ [10,11] == [1,2,3,4,10,11]);
7917 assert(a[0] == 1);
7918 assert(a[] == [1,2,3,4]);
7919 assert(a[2 .. 4] == [3,4]);
7920 static if (is(T == MyArray)) // mutable
7921 {
7922 a = a;
7923 a = [5,6,7,8]; assert(a == [5,6,7,8]);
7924 a[0] = 0; assert(a == [0,6,7,8]);
7925 a[] = 1; assert(a == [1,1,1,1]);
7926 a[0 .. 3] = 2; assert(a == [2,2,2,1]);
7927 a[0] += 2; assert(a == [4,2,2,1]);
7928 a[] *= 2; assert(a == [8,4,4,2]);
7929 a[0 .. 2] /= 2; assert(a == [4,2,4,2]);
7930 }
7931 }}
7932 }
7933 @system unittest
7934 {
7935 class Foo
7936 {
7937 int field;
7938
7939 @property int val1() const { return field; }
7940 @property void val1(int n) { field = n; }
7941
7942 @property ref int val2() { return field; }
7943
7944 int func(int x, int y) const { return x; }
7945 void func1(ref int a) { a = 9; }
7946
7947 T ifti1(T)(T t) { return t; }
7948 void ifti2(Args...)(Args args) { }
7949 void ifti3(T, Args...)(Args args) { }
7950
7951 T opCast(T)(){ return T.init; }
7952
7953 T tempfunc(T)() { return T.init; }
7954 }
7955 class Hoge
7956 {
7957 Foo foo;
7958 mixin Proxy!foo;
7959 this(Foo f) { foo = f; }
7960 }
7961
7962 auto h = new Hoge(new Foo());
7963 int n;
7964
7965 static assert(!__traits(compiles, { Foo f = h; }));
7966
7967 // field
7968 h.field = 1; // lhs of assign
7969 n = h.field; // rhs of assign
7970 assert(h.field == 1); // lhs of BinExp
7971 assert(1 == h.field); // rhs of BinExp
7972 assert(n == 1);
7973
7974 // getter/setter property function
7975 h.val1 = 4;
7976 n = h.val1;
7977 assert(h.val1 == 4);
7978 assert(4 == h.val1);
7979 assert(n == 4);
7980
7981 // ref getter property function
7982 h.val2 = 8;
7983 n = h.val2;
7984 assert(h.val2 == 8);
7985 assert(8 == h.val2);
7986 assert(n == 8);
7987
7988 // member function
7989 assert(h.func(2,4) == 2);
7990 h.func1(n);
7991 assert(n == 9);
7992
7993 // IFTI
7994 assert(h.ifti1(4) == 4);
7995 h.ifti2(4);
7996 h.ifti3!int(4, 3);
7997
7998 // https://issues.dlang.org/show_bug.cgi?id=5896 test
7999 assert(h.opCast!int() == 0);
8000 assert(cast(int) h == 0);
8001 const ih = new const Hoge(new Foo());
8002 static assert(!__traits(compiles, ih.opCast!int()));
8003 static assert(!__traits(compiles, cast(int) ih));
8004
8005 // template member function
8006 assert(h.tempfunc!int() == 0);
8007 }
8008
8009 @system unittest // about Proxy inside a class
8010 {
8011 class MyClass
8012 {
8013 int payload;
8014 mixin Proxy!payload;
8015 this(int i){ payload = i; }
8016 string opCall(string msg){ return msg; }
8017 int pow(int i){ return payload ^^ i; }
8018 }
8019
8020 class MyClass2
8021 {
8022 MyClass payload;
8023 mixin Proxy!payload;
8024 this(int i){ payload = new MyClass(i); }
8025 }
8026
8027 class MyClass3
8028 {
8029 int payload;
8030 mixin Proxy!payload;
8031 this(int i){ payload = i; }
8032 }
8033
8034 // opEquals
8035 Object a = new MyClass(5);
8036 Object b = new MyClass(5);
8037 Object c = new MyClass2(5);
8038 Object d = new MyClass3(5);
8039 assert(a == b);
8040 assert((cast(MyClass) a) == 5);
8041 assert(5 == (cast(MyClass) b));
8042 assert(5 == cast(MyClass2) c);
8043 assert(a != d);
8044
8045 assert(c != a);
8046 // oops! above line is unexpected, isn't it?
8047 // the reason is below.
8048 // MyClass2.opEquals knows MyClass but,
8049 // MyClass.opEquals doesn't know MyClass2.
8050 // so, c.opEquals(a) is true, but a.opEquals(c) is false.
8051 // furthermore, opEquals(T) couldn't be invoked.
8052 assert((cast(MyClass2) c) != (cast(MyClass) a));
8053
8054 // opCmp
8055 Object e = new MyClass2(7);
8056 assert(a < cast(MyClass2) e); // OK. and
8057 assert(e > a); // OK, but...
8058 // assert(a < e); // RUNTIME ERROR!
8059 // assert((cast(MyClass) a) < e); // RUNTIME ERROR!
8060 assert(3 < cast(MyClass) a);
8061 assert((cast(MyClass2) e) < 11);
8062
8063 // opCall
8064 assert((cast(MyClass2) e)("hello") == "hello");
8065
8066 // opCast
8067 assert((cast(MyClass)(cast(MyClass2) c)) == a);
8068 assert((cast(int)(cast(MyClass2) c)) == 5);
8069
8070 // opIndex
8071 class MyClass4
8072 {
8073 string payload;
8074 mixin Proxy!payload;
8075 this(string s){ payload = s; }
8076 }
8077 class MyClass5
8078 {
8079 MyClass4 payload;
8080 mixin Proxy!payload;
8081 this(string s){ payload = new MyClass4(s); }
8082 }
8083 auto f = new MyClass4("hello");
8084 assert(f[1] == 'e');
8085 auto g = new MyClass5("hello");
8086 assert(f[1] == 'e');
8087
8088 // opSlice
8089 assert(f[2 .. 4] == "ll");
8090
8091 // opUnary
8092 assert(-(cast(MyClass2) c) == -5);
8093
8094 // opBinary
8095 assert((cast(MyClass) a) + (cast(MyClass2) c) == 10);
8096 assert(5 + cast(MyClass) a == 10);
8097
8098 // opAssign
8099 (cast(MyClass2) c) = 11;
8100 assert((cast(MyClass2) c) == 11);
8101 (cast(MyClass2) c) = new MyClass(13);
8102 assert((cast(MyClass2) c) == 13);
8103
8104 // opOpAssign
8105 assert((cast(MyClass2) c) += 4);
8106 assert((cast(MyClass2) c) == 17);
8107
8108 // opDispatch
8109 assert((cast(MyClass2) c).pow(2) == 289);
8110
8111 // opDollar
8112 assert(f[2..$-1] == "ll");
8113
8114 // toHash
8115 int[Object] hash;
8116 hash[a] = 19;
8117 hash[c] = 21;
8118 assert(hash[b] == 19);
8119 assert(hash[c] == 21);
8120 }
8121
8122 @safe unittest
8123 {
8124 struct MyInt
8125 {
8126 int payload;
8127
8128 mixin Proxy!payload;
8129 }
8130
8131 MyInt v;
8132 v = v;
8133
8134 struct Foo
8135 {
8136 @disable void opAssign(typeof(this));
8137 }
8138 struct MyFoo
8139 {
8140 Foo payload;
8141
8142 mixin Proxy!payload;
8143 }
8144 MyFoo f;
8145 static assert(!__traits(compiles, f = f));
8146
8147 struct MyFoo2
8148 {
8149 Foo payload;
8150
8151 mixin Proxy!payload;
8152
8153 // override default Proxy behavior
8154 void opAssign(typeof(this) rhs){}
8155 }
8156 MyFoo2 f2;
8157 f2 = f2;
8158 }
8159
8160 // https://issues.dlang.org/show_bug.cgi?id=8613
8161 @safe unittest
8162 {
8163 static struct Name
8164 {
8165 mixin Proxy!val;
8166 private string val;
8167 this(string s) { val = s; }
8168 }
8169
8170 bool[Name] names;
8171 names[Name("a")] = true;
8172 bool* b = Name("a") in names;
8173 }
8174
8175 // workaround for https://issues.dlang.org/show_bug.cgi?id=19669
8176 private enum isDIP1000 = __traits(compiles, () @safe {
8177 int x;
8178 int* p;
8179 p = &x;
8180 });
8181 // excludes struct S; it's 'mixin Proxy!foo' doesn't compile with -dip1000
8182 static if (isDIP1000) {} else
8183 @system unittest
8184 {
8185 // https://issues.dlang.org/show_bug.cgi?id=14213
8186 // using function for the payload
8187 static struct S
8188 {
8189 int foo() { return 12; }
8190 mixin Proxy!foo;
8191 }
8192 S s;
8193 assert(s + 1 == 13);
8194 assert(s * 2 == 24);
8195 }
8196
8197 @system unittest
8198 {
8199 static class C
8200 {
8201 int foo() { return 12; }
8202 mixin Proxy!foo;
8203 }
8204 C c = new C();
8205 }
8206
8207 // Check all floating point comparisons for both Proxy and Typedef,
8208 // also against int and a Typedef!int, to be as regression-proof
8209 // as possible. https://issues.dlang.org/show_bug.cgi?id=15561
8210 @safe unittest
8211 {
8212 static struct MyFloatImpl
8213 {
8214 float value;
8215 mixin Proxy!value;
8216 }
8217 static void allFail(T0, T1)(T0 a, T1 b)
8218 {
8219 assert(!(a == b));
8220 assert(!(a<b));
8221 assert(!(a <= b));
8222 assert(!(a>b));
8223 assert(!(a >= b));
8224 }
8225 static foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double,
8226 float, real, Typedef!int, int))
8227 {
8228 static foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float))
8229 {{
8230 T1 a;
8231 T2 b;
8232
8233 static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1))
8234 allFail(a, b);
8235 a = 3;
8236 allFail(a, b);
8237
8238 b = 4;
8239 assert(a != b);
8240 assert(a<b);
8241 assert(a <= b);
8242 assert(!(a>b));
8243 assert(!(a >= b));
8244
8245 a = 4;
8246 assert(a == b);
8247 assert(!(a<b));
8248 assert(a <= b);
8249 assert(!(a>b));
8250 assert(a >= b);
8251 }}
8252 }
8253 }
8254
8255 /**
8256 $(B Typedef) allows the creation of a unique type which is
8257 based on an existing type. Unlike the `alias` feature,
8258 $(B Typedef) ensures the two types are not considered as equals.
8259
8260 Params:
8261
8262 init = Optional initial value for the new type.
8263 cookie = Optional, used to create multiple unique types which are
8264 based on the same origin type `T`
8265
8266 Note: If a library routine cannot handle the Typedef type,
8267 you can use the `TypedefType` template to extract the
8268 type which the Typedef wraps.
8269 */
8270 struct Typedef(T, T init = T.init, string cookie=null)
8271 {
8272 private T Typedef_payload = init;
8273
8274 // https://issues.dlang.org/show_bug.cgi?id=18415
8275 // prevent default construction if original type does too.
8276 static if ((is(T == struct) || is(T == union)) && !is(typeof({T t;})))
8277 {
8278 @disable this();
8279 }
8280
8281 this(T init)
8282 {
8283 Typedef_payload = init;
8284 }
8285
8286 this(Typedef tdef)
8287 {
8288 this(tdef.Typedef_payload);
8289 }
8290
8291 // We need to add special overload for cast(Typedef!X) exp,
8292 // thus we can't simply inherit Proxy!Typedef_payload
8293 T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)()
8294 {
8295 return T2(cast(T) Typedef_payload);
8296 }
8297
8298 auto ref opCast(T2, this X)()
8299 {
8300 return cast(T2) Typedef_payload;
8301 }
8302
8303 mixin Proxy!Typedef_payload;
8304
8305 pure nothrow @nogc @safe @property
8306 {
8307 alias TD = typeof(this);
8308 static if (isIntegral!T)
8309 {
8310 static TD min() {return TD(T.min);}
8311 static TD max() {return TD(T.max);}
8312 }
8313 else static if (isFloatingPoint!T)
8314 {
8315 static TD infinity() {return TD(T.infinity);}
8316 static TD nan() {return TD(T.nan);}
8317 static TD dig() {return TD(T.dig);}
8318 static TD epsilon() {return TD(T.epsilon);}
8319 static TD mant_dig() {return TD(T.mant_dig);}
8320 static TD max_10_exp() {return TD(T.max_10_exp);}
8321 static TD max_exp() {return TD(T.max_exp);}
8322 static TD min_10_exp() {return TD(T.min_10_exp);}
8323 static TD min_exp() {return TD(T.min_exp);}
8324 static TD max() {return TD(T.max);}
8325 static TD min_normal() {return TD(T.min_normal);}
8326 TD re() {return TD(Typedef_payload.re);}
8327 TD im() {return TD(Typedef_payload.im);}
8328 }
8329 }
8330
8331 /**
8332 * Convert wrapped value to a human readable string
8333 */
8334 string toString(this T)()
8335 {
8336 import std.array : appender;
8337 auto app = appender!string();
8338 auto spec = singleSpec("%s");
8339 toString(app, spec);
8340 return app.data;
8341 }
8342
8343 /// ditto
8344 void toString(this T, W)(ref W writer, scope const ref FormatSpec!char fmt)
8345 if (isOutputRange!(W, char))
8346 {
8347 formatValue(writer, Typedef_payload, fmt);
8348 }
8349
8350 ///
8351 @safe unittest
8352 {
8353 import std.conv : to;
8354
8355 int i = 123;
8356 auto td = Typedef!int(i);
8357 assert(i.to!string == td.to!string);
8358 }
8359 }
8360
8361 ///
8362 @safe unittest
8363 {
8364 alias MyInt = Typedef!int;
8365 MyInt foo = 10;
8366 foo++;
8367 assert(foo == 11);
8368 }
8369
8370 /// custom initialization values
8371 @safe unittest
8372 {
8373 alias MyIntInit = Typedef!(int, 42);
8374 static assert(is(TypedefType!MyIntInit == int));
8375 static assert(MyIntInit() == 42);
8376 }
8377
8378 /// Typedef creates a new type
8379 @safe unittest
8380 {
8381 alias MyInt = Typedef!int;
8382 static void takeInt(int) {}
8383 static void takeMyInt(MyInt) {}
8384
8385 int i;
8386 takeInt(i); // ok
8387 static assert(!__traits(compiles, takeMyInt(i)));
8388
8389 MyInt myInt;
8390 static assert(!__traits(compiles, takeInt(myInt)));
8391 takeMyInt(myInt); // ok
8392 }
8393
8394 /// Use the optional `cookie` argument to create different types of the same base type
8395 @safe unittest
8396 {
8397 alias TypeInt1 = Typedef!int;
8398 alias TypeInt2 = Typedef!int;
8399
8400 // The two Typedefs are the same type.
8401 static assert(is(TypeInt1 == TypeInt2));
8402
8403 alias MoneyEuros = Typedef!(float, float.init, "euros");
8404 alias MoneyDollars = Typedef!(float, float.init, "dollars");
8405
8406 // The two Typedefs are _not_ the same type.
8407 static assert(!is(MoneyEuros == MoneyDollars));
8408 }
8409
8410 // https://issues.dlang.org/show_bug.cgi?id=12461
8411 @safe unittest
8412 {
8413 alias Int = Typedef!int;
8414
8415 Int a, b;
8416 a += b;
8417 assert(a == 0);
8418 }
8419
8420 /**
8421 Get the underlying type which a `Typedef` wraps.
8422 If `T` is not a `Typedef` it will alias itself to `T`.
8423 */
8424 template TypedefType(T)
8425 {
8426 static if (is(T : Typedef!Arg, Arg))
8427 alias TypedefType = Arg;
8428 else
8429 alias TypedefType = T;
8430 }
8431
8432 ///
8433 @safe unittest
8434 {
8435 import std.conv : to;
8436
8437 alias MyInt = Typedef!int;
8438 static assert(is(TypedefType!MyInt == int));
8439
8440 /// Instantiating with a non-Typedef will return that type
8441 static assert(is(TypedefType!int == int));
8442
8443 string num = "5";
8444
8445 // extract the needed type
8446 MyInt myInt = MyInt( num.to!(TypedefType!MyInt) );
8447 assert(myInt == 5);
8448
8449 // cast to the underlying type to get the value that's being wrapped
8450 int x = cast(TypedefType!MyInt) myInt;
8451
8452 alias MyIntInit = Typedef!(int, 42);
8453 static assert(is(TypedefType!MyIntInit == int));
8454 static assert(MyIntInit() == 42);
8455 }
8456
8457 @safe unittest
8458 {
8459 Typedef!int x = 10;
8460 static assert(!__traits(compiles, { int y = x; }));
8461 static assert(!__traits(compiles, { long z = x; }));
8462
8463 Typedef!int y = 10;
8464 assert(x == y);
8465
8466 static assert(Typedef!int.init == int.init);
8467
8468 Typedef!(float, 1.0) z; // specifies the init
8469 assert(z == 1.0);
8470
8471 static assert(typeof(z).init == 1.0);
8472
8473 alias Dollar = Typedef!(int, 0, "dollar");
8474 alias Yen = Typedef!(int, 0, "yen");
8475 static assert(!is(Dollar == Yen));
8476
8477 Typedef!(int[3]) sa;
8478 static assert(sa.length == 3);
8479 static assert(typeof(sa).length == 3);
8480
8481 Typedef!(int[3]) dollar1;
8482 assert(dollar1[0..$] is dollar1[0 .. 3]);
8483
8484 Typedef!(int[]) dollar2;
8485 dollar2.length = 3;
8486 assert(dollar2[0..$] is dollar2[0 .. 3]);
8487
8488 static struct Dollar1
8489 {
8490 static struct DollarToken {}
8491 enum opDollar = DollarToken.init;
8492 auto opSlice(size_t, DollarToken) { return 1; }
8493 auto opSlice(size_t, size_t) { return 2; }
8494 }
8495
8496 Typedef!Dollar1 drange1;
8497 assert(drange1[0..$] == 1);
8498 assert(drange1[0 .. 1] == 2);
8499
8500 static struct Dollar2
8501 {
8502 size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; }
8503 size_t opIndex(size_t i, size_t j) { return i + j; }
8504 }
8505
8506 Typedef!Dollar2 drange2;
8507 assert(drange2[$, $] == 101);
8508
8509 static struct Dollar3
8510 {
8511 size_t opDollar() { return 123; }
8512 size_t opIndex(size_t i) { return i; }
8513 }
8514
8515 Typedef!Dollar3 drange3;
8516 assert(drange3[$] == 123);
8517 }
8518
8519 // https://issues.dlang.org/show_bug.cgi?id=18415
8520 @safe @nogc pure nothrow unittest
8521 {
8522 struct NoDefCtorS{@disable this();}
8523 union NoDefCtorU{@disable this();}
8524 static assert(!is(typeof({Typedef!NoDefCtorS s;})));
8525 static assert(!is(typeof({Typedef!NoDefCtorU u;})));
8526 }
8527
8528 // https://issues.dlang.org/show_bug.cgi?id=11703
8529 @safe @nogc pure nothrow unittest
8530 {
8531 alias I = Typedef!int;
8532 static assert(is(typeof(I.min) == I));
8533 static assert(is(typeof(I.max) == I));
8534
8535 alias F = Typedef!double;
8536 static assert(is(typeof(F.infinity) == F));
8537 static assert(is(typeof(F.epsilon) == F));
8538
8539 F f;
8540 assert(!is(typeof(F.re).stringof == double));
8541 assert(!is(typeof(F.im).stringof == double));
8542 }
8543
8544 @safe unittest
8545 {
8546 // https://issues.dlang.org/show_bug.cgi?id=8655
8547 import std.typecons;
8548 import std.bitmanip;
8549 static import core.stdc.config;
8550
8551 alias c_ulong = Typedef!(core.stdc.config.c_ulong);
8552
8553 static struct Foo
8554 {
8555 mixin(bitfields!(
8556 c_ulong, "NameOffset", 31,
8557 c_ulong, "NameIsString", 1
8558 ));
8559 }
8560 }
8561
8562 // https://issues.dlang.org/show_bug.cgi?id=12596
8563 @safe unittest
8564 {
8565 import std.typecons;
8566 alias TD = Typedef!int;
8567 TD x = TD(1);
8568 TD y = TD(x);
8569 assert(x == y);
8570 }
8571
8572 @safe unittest // about toHash
8573 {
8574 import std.typecons;
8575 {
8576 alias TD = Typedef!int;
8577 int[TD] td;
8578 td[TD(1)] = 1;
8579 assert(td[TD(1)] == 1);
8580 }
8581
8582 {
8583 alias TD = Typedef!(int[]);
8584 int[TD] td;
8585 td[TD([1,2,3,4])] = 2;
8586 assert(td[TD([1,2,3,4])] == 2);
8587 }
8588
8589 {
8590 alias TD = Typedef!(int[][]);
8591 int[TD] td;
8592 td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3;
8593 assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3);
8594 }
8595
8596 {
8597 struct MyStruct{ int x; }
8598 alias TD = Typedef!MyStruct;
8599 int[TD] td;
8600 td[TD(MyStruct(10))] = 4;
8601 assert(TD(MyStruct(20)) !in td);
8602 assert(td[TD(MyStruct(10))] == 4);
8603 }
8604
8605 {
8606 static struct MyStruct2
8607 {
8608 int x;
8609 size_t toHash() const nothrow @safe { return x; }
8610 bool opEquals(ref const MyStruct2 r) const { return r.x == x; }
8611 }
8612
8613 alias TD = Typedef!MyStruct2;
8614 int[TD] td;
8615 td[TD(MyStruct2(50))] = 5;
8616 assert(td[TD(MyStruct2(50))] == 5);
8617 }
8618
8619 {
8620 class MyClass{}
8621 alias TD = Typedef!MyClass;
8622 int[TD] td;
8623 auto c = new MyClass;
8624 td[TD(c)] = 6;
8625 assert(TD(new MyClass) !in td);
8626 assert(td[TD(c)] == 6);
8627 }
8628 }
8629
8630 @system unittest
8631 {
8632 alias String = Typedef!(char[]);
8633 alias CString = Typedef!(const(char)[]);
8634 CString cs = "fubar";
8635 String s = cast(String) cs;
8636 assert(cs == s);
8637 char[] s2 = cast(char[]) cs;
8638 const(char)[] cs2 = cast(const(char)[])s;
8639 assert(s2 == cs2);
8640 }
8641
8642 @system unittest // toString
8643 {
8644 import std.meta : AliasSeq;
8645 import std.conv : to;
8646
8647 struct TestS {}
8648 class TestC {}
8649
8650 static foreach (T; AliasSeq!(int, bool, float, double, real,
8651 char, dchar, wchar,
8652 TestS, TestC,
8653 int*, int[], int[2], int[int]))
8654 {{
8655 T t;
8656
8657 Typedef!T td;
8658 Typedef!(const T) ctd;
8659 Typedef!(immutable T) itd;
8660
8661 assert(t.to!string() == td.to!string());
8662
8663 static if (!(is(T == TestS) || is(T == TestC)))
8664 {
8665 assert(t.to!string() == ctd.to!string());
8666 assert(t.to!string() == itd.to!string());
8667 }
8668 }}
8669 }
8670
8671 @safe @nogc unittest // typedef'ed type with custom operators
8672 {
8673 static struct MyInt
8674 {
8675 int value;
8676 int opCmp(MyInt other)
8677 {
8678 if (value < other.value)
8679 return -1;
8680 return !(value == other.value);
8681 }
8682 }
8683
8684 auto m1 = Typedef!MyInt(MyInt(1));
8685 auto m2 = Typedef!MyInt(MyInt(2));
8686 assert(m1 < m2);
8687 }
8688
8689 /**
8690 Allocates a `class` object right inside the current scope,
8691 therefore avoiding the overhead of `new`. This facility is unsafe;
8692 it is the responsibility of the user to not escape a reference to the
8693 object outside the scope.
8694
8695 The class destructor will be called when the result of `scoped()` is
8696 itself destroyed.
8697
8698 Scoped class instances can be embedded in a parent `class` or `struct`,
8699 just like a child struct instance. Scoped member variables must have
8700 type `typeof(scoped!Class(args))`, and be initialized with a call to
8701 scoped. See below for an example.
8702
8703 Note:
8704 It's illegal to move a class instance even if you are sure there
8705 are no pointers to it. As such, it is illegal to move a scoped object.
8706 */
8707 template scoped(T)
8708 if (is(T == class))
8709 {
8710 // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for
8711 // small objects). We will just use the maximum of filed alignments.
8712 enum alignment = __traits(classInstanceAlignment, T);
8713 alias aligned = _alignUp!alignment;
8714
8715 static struct Scoped
8716 {
8717 // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory.
8718 private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void;
8719
8720 @property inout(T) Scoped_payload() inout
8721 {
8722 void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr);
8723 // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly.
8724 immutable size_t d = alignedStore - Scoped_store.ptr;
8725 size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof];
8726 if (d != *currD)
8727 {
8728 import core.stdc.string : memmove;
8729 memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T));
8730 *currD = d;
8731 }
8732 return cast(inout(T)) alignedStore;
8733 }
8734 alias Scoped_payload this;
8735
8736 @disable this();
8737 @disable this(this);
8738
8739 ~this()
8740 {
8741 // `destroy` will also write .init but we have no functions in druntime
8742 // for deterministic finalization and memory releasing for now.
8743 .destroy(Scoped_payload);
8744 }
8745 }
8746
8747 /** Returns the _scoped object.
8748 Params: args = Arguments to pass to `T`'s constructor.
8749 */
8750 @system auto scoped(Args...)(auto ref Args args)
8751 {
8752 import core.lifetime : emplace, forward;
8753
8754 Scoped result = void;
8755 void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr);
8756 immutable size_t d = alignedStore - result.Scoped_store.ptr;
8757 *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d;
8758 emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], forward!args);
8759 return result;
8760 }
8761 }
8762
8763 ///
8764 @system unittest
8765 {
8766 class A
8767 {
8768 int x;
8769 this() {x = 0;}
8770 this(int i){x = i;}
8771 ~this() {}
8772 }
8773
8774 // Standard usage, constructing A on the stack
8775 auto a1 = scoped!A();
8776 a1.x = 42;
8777
8778 // Result of `scoped` call implicitly converts to a class reference
8779 A aRef = a1;
8780 assert(aRef.x == 42);
8781
8782 // Scoped destruction
8783 {
8784 auto a2 = scoped!A(1);
8785 assert(a2.x == 1);
8786 aRef = a2;
8787 // a2 is destroyed here, calling A's destructor
8788 }
8789 // aRef is now an invalid reference
8790
8791 // Here the temporary scoped A is immediately destroyed.
8792 // This means the reference is then invalid.
8793 version (Bug)
8794 {
8795 // Wrong, should use `auto`
8796 A invalid = scoped!A();
8797 }
8798
8799 // Restrictions
8800 version (Bug)
8801 {
8802 import std.algorithm.mutation : move;
8803 auto invalid = a1.move; // illegal, scoped objects can't be moved
8804 }
8805 static assert(!is(typeof({
8806 auto e1 = a1; // illegal, scoped objects can't be copied
8807 assert([a1][0].x == 42); // ditto
8808 })));
8809 static assert(!is(typeof({
8810 alias ScopedObject = typeof(a1);
8811 auto e2 = ScopedObject(); // illegal, must be built via scoped!A
8812 auto e3 = ScopedObject(1); // ditto
8813 })));
8814
8815 // Use with alias
8816 alias makeScopedA = scoped!A;
8817 auto a3 = makeScopedA();
8818 auto a4 = makeScopedA(1);
8819
8820 // Use as member variable
8821 struct B
8822 {
8823 typeof(scoped!A()) a; // note the trailing parentheses
8824
8825 this(int i)
8826 {
8827 // construct member
8828 a = scoped!A(i);
8829 }
8830 }
8831
8832 // Stack-allocate
8833 auto b1 = B(5);
8834 aRef = b1.a;
8835 assert(aRef.x == 5);
8836 destroy(b1); // calls A's destructor for b1.a
8837 // aRef is now an invalid reference
8838
8839 // Heap-allocate
8840 auto b2 = new B(6);
8841 assert(b2.a.x == 6);
8842 destroy(*b2); // calls A's destructor for b2.a
8843 }
8844
8845 private size_t _alignUp(size_t alignment)(size_t n)
8846 if (alignment > 0 && !((alignment - 1) & alignment))
8847 {
8848 enum badEnd = alignment - 1; // 0b11, 0b111, ...
8849 return (n + badEnd) & ~badEnd;
8850 }
8851
8852 // https://issues.dlang.org/show_bug.cgi?id=6580 testcase
8853 @system unittest
8854 {
8855 enum alignment = (void*).alignof;
8856
8857 static class C0 { }
8858 static class C1 { byte b; }
8859 static class C2 { byte[2] b; }
8860 static class C3 { byte[3] b; }
8861 static class C7 { byte[7] b; }
8862 static assert(scoped!C0().sizeof % alignment == 0);
8863 static assert(scoped!C1().sizeof % alignment == 0);
8864 static assert(scoped!C2().sizeof % alignment == 0);
8865 static assert(scoped!C3().sizeof % alignment == 0);
8866 static assert(scoped!C7().sizeof % alignment == 0);
8867
8868 enum longAlignment = long.alignof;
8869 static class C1long
8870 {
8871 long long_; byte byte_ = 4;
8872 this() { }
8873 this(long _long, ref int i) { long_ = _long; ++i; }
8874 }
8875 static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; }
8876 static assert(scoped!C1long().sizeof % longAlignment == 0);
8877 static assert(scoped!C2long().sizeof % longAlignment == 0);
8878
8879 void alignmentTest()
8880 {
8881 int var = 5;
8882 auto c1long = scoped!C1long(3, var);
8883 assert(var == 6);
8884 auto c2long = scoped!C2long();
8885 assert(cast(uint)&c1long.long_ % longAlignment == 0);
8886 assert(cast(uint)&c2long.long_ % longAlignment == 0);
8887 assert(c1long.long_ == 3 && c1long.byte_ == 4);
8888 assert(c2long.byte_ == [5, 6] && c2long.long_ == 7);
8889 }
8890
8891 alignmentTest();
8892
8893 version (DigitalMars)
8894 {
8895 void test(size_t size)
8896 {
8897 import core.stdc.stdlib : alloca;
8898 cast(void) alloca(size);
8899 alignmentTest();
8900 }
8901 foreach (i; 0 .. 10)
8902 test(i);
8903 }
8904 else
8905 {
8906 void test(size_t size)()
8907 {
8908 byte[size] arr;
8909 alignmentTest();
8910 }
8911 static foreach (i; 0 .. 11)
8912 test!i();
8913 }
8914 }
8915
8916 // Original https://issues.dlang.org/show_bug.cgi?id=6580 testcase
8917 @system unittest
8918 {
8919 class C { int i; byte b; }
8920
8921 auto sa = [scoped!C(), scoped!C()];
8922 assert(cast(uint)&sa[0].i % int.alignof == 0);
8923 assert(cast(uint)&sa[1].i % int.alignof == 0); // fails
8924 }
8925
8926 @system unittest
8927 {
8928 class A { int x = 1; }
8929 auto a1 = scoped!A();
8930 assert(a1.x == 1);
8931 auto a2 = scoped!A();
8932 a1.x = 42;
8933 a2.x = 53;
8934 assert(a1.x == 42);
8935 }
8936
8937 @system unittest
8938 {
8939 class A { int x = 1; this() { x = 2; } }
8940 auto a1 = scoped!A();
8941 assert(a1.x == 2);
8942 auto a2 = scoped!A();
8943 a1.x = 42;
8944 a2.x = 53;
8945 assert(a1.x == 42);
8946 }
8947
8948 @system unittest
8949 {
8950 class A { int x = 1; this(int y) { x = y; } ~this() {} }
8951 auto a1 = scoped!A(5);
8952 assert(a1.x == 5);
8953 auto a2 = scoped!A(42);
8954 a1.x = 42;
8955 a2.x = 53;
8956 assert(a1.x == 42);
8957 }
8958
8959 @system unittest
8960 {
8961 class A { static bool dead; ~this() { dead = true; } }
8962 class B : A { static bool dead; ~this() { dead = true; } }
8963 {
8964 auto b = scoped!B();
8965 }
8966 assert(B.dead, "asdasd");
8967 assert(A.dead, "asdasd");
8968 }
8969
8970 // https://issues.dlang.org/show_bug.cgi?id=8039 testcase
8971 @system unittest
8972 {
8973 static int dels;
8974 static struct S { ~this(){ ++dels; } }
8975
8976 static class A { S s; }
8977 dels = 0; { scoped!A(); }
8978 assert(dels == 1);
8979
8980 static class B { S[2] s; }
8981 dels = 0; { scoped!B(); }
8982 assert(dels == 2);
8983
8984 static struct S2 { S[3] s; }
8985 static class C { S2[2] s; }
8986 dels = 0; { scoped!C(); }
8987 assert(dels == 6);
8988
8989 static class D: A { S2[2] s; }
8990 dels = 0; { scoped!D(); }
8991 assert(dels == 1+6);
8992 }
8993
8994 @system unittest
8995 {
8996 // https://issues.dlang.org/show_bug.cgi?id=4500
8997 class A
8998 {
8999 this() { a = this; }
9000 this(int i) { a = this; }
9001 A a;
9002 bool check() { return this is a; }
9003 }
9004
9005 auto a1 = scoped!A();
9006 assert(a1.check());
9007
9008 auto a2 = scoped!A(1);
9009 assert(a2.check());
9010
9011 a1.a = a1;
9012 assert(a1.check());
9013 }
9014
9015 @system unittest
9016 {
9017 static class A
9018 {
9019 static int sdtor;
9020
9021 this() { ++sdtor; assert(sdtor == 1); }
9022 ~this() { assert(sdtor == 1); --sdtor; }
9023 }
9024
9025 interface Bob {}
9026
9027 static class ABob : A, Bob
9028 {
9029 this() { ++sdtor; assert(sdtor == 2); }
9030 ~this() { assert(sdtor == 2); --sdtor; }
9031 }
9032
9033 A.sdtor = 0;
9034 scope(exit) assert(A.sdtor == 0);
9035 auto abob = scoped!ABob();
9036 }
9037
9038 @safe unittest
9039 {
9040 static class A { this(int) {} }
9041 static assert(!__traits(compiles, scoped!A()));
9042 }
9043
9044 @system unittest
9045 {
9046 static class A { @property inout(int) foo() inout { return 1; } }
9047
9048 auto a1 = scoped!A();
9049 assert(a1.foo == 1);
9050 static assert(is(typeof(a1.foo) == int));
9051
9052 auto a2 = scoped!(const(A))();
9053 assert(a2.foo == 1);
9054 static assert(is(typeof(a2.foo) == const(int)));
9055
9056 auto a3 = scoped!(immutable(A))();
9057 assert(a3.foo == 1);
9058 static assert(is(typeof(a3.foo) == immutable(int)));
9059
9060 const c1 = scoped!A();
9061 assert(c1.foo == 1);
9062 static assert(is(typeof(c1.foo) == const(int)));
9063
9064 const c2 = scoped!(const(A))();
9065 assert(c2.foo == 1);
9066 static assert(is(typeof(c2.foo) == const(int)));
9067
9068 const c3 = scoped!(immutable(A))();
9069 assert(c3.foo == 1);
9070 static assert(is(typeof(c3.foo) == immutable(int)));
9071 }
9072
9073 @system unittest
9074 {
9075 class C
9076 {
9077 this(int rval) { assert(rval == 1); }
9078 this(ref int lval) { assert(lval == 3); ++lval; }
9079 }
9080
9081 auto c1 = scoped!C(1);
9082 int lval = 3;
9083 auto c2 = scoped!C(lval);
9084 assert(lval == 4);
9085 }
9086
9087 @system unittest
9088 {
9089 class C
9090 {
9091 this(){}
9092 this(int){}
9093 this(int, int){}
9094 }
9095 alias makeScopedC = scoped!C;
9096
9097 auto a = makeScopedC();
9098 auto b = makeScopedC(1);
9099 auto c = makeScopedC(1, 1);
9100
9101 static assert(is(typeof(a) == typeof(b)));
9102 static assert(is(typeof(b) == typeof(c)));
9103 }
9104
9105 /**
9106 Defines a simple, self-documenting yes/no flag. This makes it easy for
9107 APIs to define functions accepting flags without resorting to $(D
9108 bool), which is opaque in calls, and without needing to define an
9109 enumerated type separately. Using `Flag!"Name"` instead of $(D
9110 bool) makes the flag's meaning visible in calls. Each yes/no flag has
9111 its own type, which makes confusions and mix-ups impossible.
9112
9113 Example:
9114
9115 Code calling `getLine` (usually far away from its definition) can't be
9116 understood without looking at the documentation, even by users familiar with
9117 the API:
9118 ----
9119 string getLine(bool keepTerminator)
9120 {
9121 ...
9122 if (keepTerminator) ...
9123 ...
9124 }
9125 ...
9126 auto line = getLine(false);
9127 ----
9128
9129 Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong
9130 code compiles and runs with erroneous results.
9131
9132 After replacing the boolean parameter with an instantiation of `Flag`, code
9133 calling `getLine` can be easily read and understood even by people not
9134 fluent with the API:
9135
9136 ----
9137 string getLine(Flag!"keepTerminator" keepTerminator)
9138 {
9139 ...
9140 if (keepTerminator) ...
9141 ...
9142 }
9143 ...
9144 auto line = getLine(Yes.keepTerminator);
9145 ----
9146
9147 The structs `Yes` and `No` are provided as shorthand for
9148 `Flag!"Name".yes` and `Flag!"Name".no` and are preferred for brevity and
9149 readability. These convenience structs mean it is usually unnecessary and
9150 counterproductive to create an alias of a `Flag` as a way of avoiding typing
9151 out the full type while specifying the affirmative or negative options.
9152
9153 Passing categorical data by means of unstructured `bool`
9154 parameters is classified under "simple-data coupling" by Steve
9155 McConnell in the $(LUCKY Code Complete) book, along with three other
9156 kinds of coupling. The author argues citing several studies that
9157 coupling has a negative effect on code quality. `Flag` offers a
9158 simple structuring method for passing yes/no flags to APIs.
9159 */
9160 template Flag(string name) {
9161 ///
9162 enum Flag : bool
9163 {
9164 /**
9165 When creating a value of type `Flag!"Name"`, use $(D
9166 Flag!"Name".no) for the negative option. When using a value
9167 of type `Flag!"Name"`, compare it against $(D
9168 Flag!"Name".no) or just `false` or `0`. */
9169 no = false,
9170
9171 /** When creating a value of type `Flag!"Name"`, use $(D
9172 Flag!"Name".yes) for the affirmative option. When using a
9173 value of type `Flag!"Name"`, compare it against $(D
9174 Flag!"Name".yes).
9175 */
9176 yes = true
9177 }
9178 }
9179
9180 ///
9181 @safe unittest
9182 {
9183 Flag!"abc" flag;
9184
9185 assert(flag == Flag!"abc".no);
9186 assert(flag == No.abc);
9187 assert(!flag);
9188 if (flag) assert(0);
9189 }
9190
9191 ///
9192 @safe unittest
9193 {
9194 auto flag = Yes.abc;
9195
9196 assert(flag);
9197 assert(flag == Yes.abc);
9198 if (!flag) assert(0);
9199 if (flag) {} else assert(0);
9200 }
9201
9202 /**
9203 Convenience names that allow using e.g. `Yes.encryption` instead of
9204 `Flag!"encryption".yes` and `No.encryption` instead of $(D
9205 Flag!"encryption".no).
9206 */
9207 struct Yes
9208 {
9209 template opDispatch(string name)
9210 {
9211 enum opDispatch = Flag!name.yes;
9212 }
9213 }
9214 //template yes(string name) { enum Flag!name yes = Flag!name.yes; }
9215
9216 /// Ditto
9217 struct No
9218 {
9219 template opDispatch(string name)
9220 {
9221 enum opDispatch = Flag!name.no;
9222 }
9223 }
9224
9225 ///
9226 @safe unittest
9227 {
9228 Flag!"abc" flag;
9229
9230 assert(flag == Flag!"abc".no);
9231 assert(flag == No.abc);
9232 assert(!flag);
9233 if (flag) assert(0);
9234 }
9235
9236 ///
9237 @safe unittest
9238 {
9239 auto flag = Yes.abc;
9240
9241 assert(flag);
9242 assert(flag == Yes.abc);
9243 if (!flag) assert(0);
9244 if (flag) {} else assert(0);
9245 }
9246
9247 /**
9248 Detect whether an enum is of integral type and has only "flag" values
9249 (i.e. values with a bit count of exactly 1).
9250 Additionally, a zero value is allowed for compatibility with enums including
9251 a "None" value.
9252 */
9253 template isBitFlagEnum(E)
9254 {
9255 static if (is(E Base == enum) && isIntegral!Base)
9256 {
9257 enum isBitFlagEnum = (E.min >= 0) &&
9258 {
9259 static foreach (immutable flag; EnumMembers!E)
9260 {{
9261 Base value = flag;
9262 value &= value - 1;
9263 if (value != 0) return false;
9264 }}
9265 return true;
9266 }();
9267 }
9268 else
9269 {
9270 enum isBitFlagEnum = false;
9271 }
9272 }
9273
9274 ///
9275 @safe pure nothrow unittest
9276 {
9277 enum A
9278 {
9279 None,
9280 A = 1 << 0,
9281 B = 1 << 1,
9282 C = 1 << 2,
9283 D = 1 << 3,
9284 }
9285
9286 static assert(isBitFlagEnum!A);
9287 }
9288
9289 /// Test an enum with default (consecutive) values
9290 @safe pure nothrow unittest
9291 {
9292 enum B
9293 {
9294 A,
9295 B,
9296 C,
9297 D // D == 3
9298 }
9299
9300 static assert(!isBitFlagEnum!B);
9301 }
9302
9303 /// Test an enum with non-integral values
9304 @safe pure nothrow unittest
9305 {
9306 enum C: double
9307 {
9308 A = 1 << 0,
9309 B = 1 << 1
9310 }
9311
9312 static assert(!isBitFlagEnum!C);
9313 }
9314
9315 /**
9316 A typesafe structure for storing combinations of enum values.
9317
9318 This template defines a simple struct to represent bitwise OR combinations of
9319 enum values. It can be used if all the enum values are integral constants with
9320 a bit count of at most 1, or if the `unsafe` parameter is explicitly set to
9321 Yes.
9322 This is much safer than using the enum itself to store
9323 the OR combination, which can produce surprising effects like this:
9324 ----
9325 enum E
9326 {
9327 A = 1 << 0,
9328 B = 1 << 1
9329 }
9330 E e = E.A | E.B;
9331 // will throw SwitchError
9332 final switch (e)
9333 {
9334 case E.A:
9335 return;
9336 case E.B:
9337 return;
9338 }
9339 ----
9340 */
9341 struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe)
9342 if (unsafe || isBitFlagEnum!(E))
9343 {
9344 @safe @nogc pure nothrow:
9345 private:
9346 enum isBaseEnumType(T) = is(E == T);
9347 alias Base = OriginalType!E;
9348 Base mValue;
9349
9350 public:
9351 this(E flag)
9352 {
9353 this = flag;
9354 }
9355
9356 this(T...)(T flags)
9357 if (allSatisfy!(isBaseEnumType, T))
9358 {
9359 this = flags;
9360 }
9361
9362 bool opCast(B: bool)() const
9363 {
9364 return mValue != 0;
9365 }
9366
9367 Base opCast(B)() const
9368 if (is(Base : B))
9369 {
9370 return mValue;
9371 }
9372
9373 auto opUnary(string op)() const
9374 if (op == "~")
9375 {
9376 return BitFlags(cast(E) cast(Base) ~mValue);
9377 }
9378
9379 auto ref opAssign(T...)(T flags)
9380 if (allSatisfy!(isBaseEnumType, T))
9381 {
9382 mValue = 0;
9383 foreach (E flag; flags)
9384 {
9385 mValue |= flag;
9386 }
9387 return this;
9388 }
9389
9390 auto ref opAssign(E flag)
9391 {
9392 mValue = flag;
9393 return this;
9394 }
9395
9396 auto ref opOpAssign(string op: "|")(BitFlags flags)
9397 {
9398 mValue |= flags.mValue;
9399 return this;
9400 }
9401
9402 auto ref opOpAssign(string op: "&")(BitFlags flags)
9403 {
9404 mValue &= flags.mValue;
9405 return this;
9406 }
9407
9408 auto ref opOpAssign(string op: "|")(E flag)
9409 {
9410 mValue |= flag;
9411 return this;
9412 }
9413
9414 auto ref opOpAssign(string op: "&")(E flag)
9415 {
9416 mValue &= flag;
9417 return this;
9418 }
9419
9420 auto opBinary(string op)(BitFlags flags) const
9421 if (op == "|" || op == "&")
9422 {
9423 BitFlags result = this;
9424 result.opOpAssign!op(flags);
9425 return result;
9426 }
9427
9428 auto opBinary(string op)(E flag) const
9429 if (op == "|" || op == "&")
9430 {
9431 BitFlags result = this;
9432 result.opOpAssign!op(flag);
9433 return result;
9434 }
9435
9436 auto opBinaryRight(string op)(E flag) const
9437 if (op == "|" || op == "&")
9438 {
9439 return opBinary!op(flag);
9440 }
9441
9442 bool opDispatch(string name)() const
9443 if (__traits(hasMember, E, name))
9444 {
9445 enum e = __traits(getMember, E, name);
9446 return (mValue & e) == e;
9447 }
9448
9449 void opDispatch(string name)(bool set)
9450 if (__traits(hasMember, E, name))
9451 {
9452 enum e = __traits(getMember, E, name);
9453 if (set)
9454 mValue |= e;
9455 else
9456 mValue &= ~e;
9457 }
9458 }
9459
9460 /// Set values with the | operator and test with &
9461 @safe @nogc pure nothrow unittest
9462 {
9463 enum Enum
9464 {
9465 A = 1 << 0,
9466 }
9467
9468 // A default constructed BitFlags has no value set
9469 immutable BitFlags!Enum flags_empty;
9470 assert(!flags_empty.A);
9471
9472 // Value can be set with the | operator
9473 immutable flags_A = flags_empty | Enum.A;
9474
9475 // and tested using property access
9476 assert(flags_A.A);
9477
9478 // or the & operator
9479 assert(flags_A & Enum.A);
9480 // which commutes.
9481 assert(Enum.A & flags_A);
9482 }
9483
9484 /// A default constructed BitFlags has no value set
9485 @safe @nogc pure nothrow unittest
9486 {
9487 enum Enum
9488 {
9489 None,
9490 A = 1 << 0,
9491 B = 1 << 1,
9492 C = 1 << 2
9493 }
9494
9495 immutable BitFlags!Enum flags_empty;
9496 assert(!(flags_empty & (Enum.A | Enum.B | Enum.C)));
9497 assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C));
9498 }
9499
9500 // BitFlags can be variadically initialized
9501 @safe @nogc pure nothrow unittest
9502 {
9503 import std.traits : EnumMembers;
9504
9505 enum Enum
9506 {
9507 A = 1 << 0,
9508 B = 1 << 1,
9509 C = 1 << 2
9510 }
9511
9512 // Values can also be set using property access
9513 BitFlags!Enum flags;
9514 flags.A = true;
9515 assert(flags & Enum.A);
9516 flags.A = false;
9517 assert(!(flags & Enum.A));
9518
9519 // BitFlags can be variadically initialized
9520 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
9521 assert(flags_AB.A && flags_AB.B && !flags_AB.C);
9522
9523 // You can use the EnumMembers template to set all flags
9524 immutable BitFlags!Enum flags_all = EnumMembers!Enum;
9525 assert(flags_all.A && flags_all.B && flags_all.C);
9526 }
9527
9528 /// Binary operations: subtracting and intersecting flags
9529 @safe @nogc pure nothrow unittest
9530 {
9531 enum Enum
9532 {
9533 A = 1 << 0,
9534 B = 1 << 1,
9535 C = 1 << 2,
9536 }
9537 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
9538 immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C);
9539
9540 // Use the ~ operator for subtracting flags
9541 immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A);
9542 assert(!flags_B.A && flags_B.B && !flags_B.C);
9543
9544 // use & between BitFlags for intersection
9545 assert(flags_B == (flags_BC & flags_AB));
9546 }
9547
9548 /// All the binary operators work in their assignment version
9549 @safe @nogc pure nothrow unittest
9550 {
9551 enum Enum
9552 {
9553 A = 1 << 0,
9554 B = 1 << 1,
9555 }
9556
9557 BitFlags!Enum flags_empty, temp, flags_AB;
9558 flags_AB = Enum.A | Enum.B;
9559
9560 temp |= flags_AB;
9561 assert(temp == (flags_empty | flags_AB));
9562
9563 temp = flags_empty;
9564 temp |= Enum.B;
9565 assert(temp == (flags_empty | Enum.B));
9566
9567 temp = flags_empty;
9568 temp &= flags_AB;
9569 assert(temp == (flags_empty & flags_AB));
9570
9571 temp = flags_empty;
9572 temp &= Enum.A;
9573 assert(temp == (flags_empty & Enum.A));
9574 }
9575
9576 /// Conversion to bool and int
9577 @safe @nogc pure nothrow unittest
9578 {
9579 enum Enum
9580 {
9581 A = 1 << 0,
9582 B = 1 << 1,
9583 }
9584
9585 BitFlags!Enum flags;
9586
9587 // BitFlags with no value set evaluate to false
9588 assert(!flags);
9589
9590 // BitFlags with at least one value set evaluate to true
9591 flags |= Enum.A;
9592 assert(flags);
9593
9594 // This can be useful to check intersection between BitFlags
9595 BitFlags!Enum flags_AB = Enum.A | Enum.B;
9596 assert(flags & flags_AB);
9597 assert(flags & Enum.A);
9598
9599 // You can of course get you raw value out of flags
9600 auto value = cast(int) flags;
9601 assert(value == Enum.A);
9602 }
9603
9604 /// You need to specify the `unsafe` parameter for enums with custom values
9605 @safe @nogc pure nothrow unittest
9606 {
9607 enum UnsafeEnum
9608 {
9609 A = 1,
9610 B = 2,
9611 C = 4,
9612 BC = B|C
9613 }
9614 static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; }));
9615 BitFlags!(UnsafeEnum, Yes.unsafe) flags;
9616
9617 // property access tests for exact match of unsafe enums
9618 flags.B = true;
9619 assert(!flags.BC); // only B
9620 flags.C = true;
9621 assert(flags.BC); // both B and C
9622 flags.B = false;
9623 assert(!flags.BC); // only C
9624
9625 // property access sets all bits of unsafe enum group
9626 flags = flags.init;
9627 flags.BC = true;
9628 assert(!flags.A && flags.B && flags.C);
9629 flags.A = true;
9630 flags.BC = false;
9631 assert(flags.A && !flags.B && !flags.C);
9632 }
9633
9634 // Negation of BitFlags should work with any base type.
9635 // Double-negation of BitFlags should work.
9636 @safe @nogc pure nothrow unittest
9637 {
9638 static foreach (alias Base; AliasSeq!(
9639 byte,
9640 ubyte,
9641 short,
9642 ushort,
9643 int,
9644 uint,
9645 long,
9646 ulong,
9647 ))
9648 {{
9649 enum Enum : Base
9650 {
9651 A = 1 << 0,
9652 B = 1 << 1,
9653 C = 1 << 2,
9654 }
9655
9656 auto flags = BitFlags!Enum(Enum.A);
9657
9658 assert(flags == ~~flags);
9659 }}
9660 }
9661
9662 private enum false_(T) = false;
9663
9664 // ReplaceType
9665 /**
9666 Replaces all occurrences of `From` into `To`, in one or more types `T`. For
9667 example, `ReplaceType!(int, uint, Tuple!(int, float)[string])` yields
9668 `Tuple!(uint, float)[string]`. The types in which replacement is performed
9669 may be arbitrarily complex, including qualifiers, built-in type constructors
9670 (pointers, arrays, associative arrays, functions, and delegates), and template
9671 instantiations; replacement proceeds transitively through the type definition.
9672 However, member types in `struct`s or `class`es are not replaced because there
9673 are no ways to express the types resulting after replacement.
9674
9675 This is an advanced type manipulation necessary e.g. for replacing the
9676 placeholder type `This` in $(REF Algebraic, std,variant).
9677
9678 Returns: `ReplaceType` aliases itself to the type(s) that result after
9679 replacement.
9680 */
9681 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T);
9682
9683 ///
9684 @safe unittest
9685 {
9686 static assert(
9687 is(ReplaceType!(int, string, int[]) == string[]) &&
9688 is(ReplaceType!(int, string, int[int]) == string[string]) &&
9689 is(ReplaceType!(int, string, const(int)[]) == const(string)[]) &&
9690 is(ReplaceType!(int, string, Tuple!(int[], float))
9691 == Tuple!(string[], float))
9692 );
9693 }
9694
9695 /**
9696 Like $(LREF ReplaceType), but does not perform replacement in types for which
9697 `pred` evaluates to `true`.
9698 */
9699 template ReplaceTypeUnless(alias pred, From, To, T...)
9700 {
9701 import std.meta;
9702
9703 static if (T.length == 1)
9704 {
9705 static if (pred!(T[0]))
9706 alias ReplaceTypeUnless = T[0];
9707 else static if (is(T[0] == From))
9708 alias ReplaceTypeUnless = To;
9709 else static if (is(T[0] == const(U), U))
9710 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U));
9711 else static if (is(T[0] == immutable(U), U))
9712 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U));
9713 else static if (is(T[0] == shared(U), U))
9714 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U));
9715 else static if (is(T[0] == U*, U))
9716 {
9717 static if (is(U == function))
9718 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]);
9719 else
9720 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*;
9721 }
9722 else static if (is(T[0] == delegate))
9723 {
9724 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]);
9725 }
9726 else static if (is(T[0] == function))
9727 {
9728 static assert(0, "Function types not supported," ~
9729 " use a function pointer type instead of " ~ T[0].stringof);
9730 }
9731 else static if (is(T[0] == U!V, alias U, V...))
9732 {
9733 template replaceTemplateArgs(T...)
9734 {
9735 static if (is(typeof(T[0]))) { // template argument is value or symbol
9736 static if (__traits(compiles, { alias _ = T[0]; }))
9737 // it's a symbol
9738 alias replaceTemplateArgs = T[0];
9739 else
9740 // it's a value
9741 enum replaceTemplateArgs = T[0];
9742 } else
9743 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]);
9744 }
9745 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V));
9746 }
9747 else static if (is(T[0] == struct))
9748 // don't match with alias this struct below
9749 // https://issues.dlang.org/show_bug.cgi?id=15168
9750 alias ReplaceTypeUnless = T[0];
9751 else static if (is(T[0] == U[], U))
9752 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[];
9753 else static if (is(T[0] == U[n], U, size_t n))
9754 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n];
9755 else static if (is(T[0] == U[V], U, V))
9756 alias ReplaceTypeUnless =
9757 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)];
9758 else
9759 alias ReplaceTypeUnless = T[0];
9760 }
9761 else static if (T.length > 1)
9762 {
9763 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]),
9764 ReplaceTypeUnless!(pred, From, To, T[1 .. $]));
9765 }
9766 else
9767 {
9768 alias ReplaceTypeUnless = AliasSeq!();
9769 }
9770 }
9771
9772 ///
9773 @safe unittest
9774 {
9775 import std.traits : isArray;
9776
9777 static assert(
9778 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) &&
9779 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) &&
9780 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[]))
9781 == Tuple!(string, int[]))
9782 );
9783 }
9784
9785 private template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun)
9786 {
9787 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun);
9788 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun));
9789 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return
9790 // tuple if Parameters!fun.length == 1
9791
9792 string gen()
9793 {
9794 enum linkage = functionLinkage!fun;
9795 alias attributes = functionAttributes!fun;
9796 enum variadicStyle = variadicFunctionStyle!fun;
9797 alias storageClasses = ParameterStorageClassTuple!fun;
9798
9799 string result;
9800
9801 result ~= "extern(" ~ linkage ~ ") ";
9802 static if (attributes & FunctionAttribute.ref_)
9803 {
9804 result ~= "ref ";
9805 }
9806
9807 result ~= "RX";
9808 static if (is(fun == delegate))
9809 result ~= " delegate";
9810 else
9811 result ~= " function";
9812
9813 result ~= "(";
9814 static foreach (i; 0 .. PX.length)
9815 {
9816 if (i)
9817 result ~= ", ";
9818 if (storageClasses[i] & ParameterStorageClass.scope_)
9819 result ~= "scope ";
9820 if (storageClasses[i] & ParameterStorageClass.in_)
9821 result ~= "in ";
9822 if (storageClasses[i] & ParameterStorageClass.out_)
9823 result ~= "out ";
9824 if (storageClasses[i] & ParameterStorageClass.ref_)
9825 result ~= "ref ";
9826 if (storageClasses[i] & ParameterStorageClass.lazy_)
9827 result ~= "lazy ";
9828 if (storageClasses[i] & ParameterStorageClass.return_)
9829 result ~= "return ";
9830
9831 result ~= "PX[" ~ i.stringof ~ "]";
9832 }
9833 static if (variadicStyle == Variadic.typesafe)
9834 result ~= " ...";
9835 else static if (variadicStyle != Variadic.no)
9836 result ~= ", ...";
9837 result ~= ")";
9838
9839 static if (attributes & FunctionAttribute.pure_)
9840 result ~= " pure";
9841 static if (attributes & FunctionAttribute.nothrow_)
9842 result ~= " nothrow";
9843 static if (attributes & FunctionAttribute.property)
9844 result ~= " @property";
9845 static if (attributes & FunctionAttribute.trusted)
9846 result ~= " @trusted";
9847 static if (attributes & FunctionAttribute.safe)
9848 result ~= " @safe";
9849 static if (attributes & FunctionAttribute.nogc)
9850 result ~= " @nogc";
9851 static if (attributes & FunctionAttribute.system)
9852 result ~= " @system";
9853 static if (attributes & FunctionAttribute.const_)
9854 result ~= " const";
9855 static if (attributes & FunctionAttribute.immutable_)
9856 result ~= " immutable";
9857 static if (attributes & FunctionAttribute.inout_)
9858 result ~= " inout";
9859 static if (attributes & FunctionAttribute.shared_)
9860 result ~= " shared";
9861 static if (attributes & FunctionAttribute.return_)
9862 result ~= " return";
9863 static if (attributes & FunctionAttribute.live)
9864 result ~= " @live";
9865
9866 return result;
9867 }
9868
9869 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";");
9870 }
9871
9872 @safe unittest
9873 {
9874 template Test(Ts...)
9875 {
9876 static if (Ts.length)
9877 {
9878 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", "
9879 // ~Ts[1].stringof~", "~Ts[2].stringof~")");
9880 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]),
9881 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", "
9882 ~Ts[2].stringof~") == "
9883 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof);
9884 alias Test = Test!(Ts[4 .. $]);
9885 }
9886 else alias Test = void;
9887 }
9888
9889 //import core.stdc.stdio;
9890 alias RefFun1 = ref int function(float, long);
9891 alias RefFun2 = ref float function(float, long);
9892 extern(C) int printf(const char*, ...) nothrow @nogc @system;
9893 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system;
9894 int func(float);
9895
9896 int x;
9897 struct S1 { void foo() { x = 1; } }
9898 struct S2 { void bar() { x = 2; } }
9899
9900 alias Pass = Test!(
9901 int, float, typeof(&func), float delegate(float),
9902 int, float, typeof(&printf), typeof(&floatPrintf),
9903 int, float, int function(out long, ...),
9904 float function(out long, ...),
9905 int, float, int function(ref float, long),
9906 float function(ref float, long),
9907 int, float, int function(ref int, long),
9908 float function(ref float, long),
9909 int, float, int function(out int, long),
9910 float function(out float, long),
9911 int, float, int function(lazy int, long),
9912 float function(lazy float, long),
9913 int, float, int function(out long, ref const int),
9914 float function(out long, ref const float),
9915 int, float, int function(in long, ref const int),
9916 float function(in long, ref const float),
9917 int, float, int function(long, in int),
9918 float function(long, in float),
9919 int, int, int, int,
9920 int, float, int, float,
9921 int, float, const int, const float,
9922 int, float, immutable int, immutable float,
9923 int, float, shared int, shared float,
9924 int, float, int*, float*,
9925 int, float, const(int)*, const(float)*,
9926 int, float, const(int*), const(float*),
9927 const(int)*, float, const(int*), const(float),
9928 int*, float, const(int)*, const(int)*,
9929 int, float, int[], float[],
9930 int, float, int[42], float[42],
9931 int, float, const(int)[42], const(float)[42],
9932 int, float, const(int[42]), const(float[42]),
9933 int, float, int[int], float[float],
9934 int, float, int[double], float[double],
9935 int, float, double[int], double[float],
9936 int, float, int function(float, long), float function(float, long),
9937 int, float, int function(float), float function(float),
9938 int, float, int function(float, int), float function(float, float),
9939 int, float, int delegate(float, long), float delegate(float, long),
9940 int, float, int delegate(float), float delegate(float),
9941 int, float, int delegate(float, int), float delegate(float, float),
9942 int, float, Unique!int, Unique!float,
9943 int, float, Tuple!(float, int), Tuple!(float, float),
9944 int, float, RefFun1, RefFun2,
9945 S1, S2,
9946 S1[1][][S1]* function(),
9947 S2[1][][S2]* function(),
9948 int, string,
9949 int[3] function( int[] arr, int[2] ...) pure @trusted,
9950 string[3] function(string[] arr, string[2] ...) pure @trusted,
9951 );
9952
9953 // https://issues.dlang.org/show_bug.cgi?id=15168
9954 static struct T1 { string s; alias s this; }
9955 static struct T2 { char[10] s; alias s this; }
9956 static struct T3 { string[string] s; alias s this; }
9957 alias Pass2 = Test!(
9958 ubyte, ubyte, T1, T1,
9959 ubyte, ubyte, T2, T2,
9960 ubyte, ubyte, T3, T3,
9961 );
9962 }
9963
9964 // https://issues.dlang.org/show_bug.cgi?id=17116
9965 @safe unittest
9966 {
9967 alias ConstDg = void delegate(float) const;
9968 alias B = void delegate(int) const;
9969 alias A = ReplaceType!(float, int, ConstDg);
9970 static assert(is(B == A));
9971 }
9972
9973 // https://issues.dlang.org/show_bug.cgi?id=19696
9974 @safe unittest
9975 {
9976 static struct T(U) {}
9977 static struct S { T!int t; alias t this; }
9978 static assert(is(ReplaceType!(float, float, S) == S));
9979 }
9980
9981 // https://issues.dlang.org/show_bug.cgi?id=19697
9982 @safe unittest
9983 {
9984 class D(T) {}
9985 class C : D!C {}
9986 static assert(is(ReplaceType!(float, float, C)));
9987 }
9988
9989 // https://issues.dlang.org/show_bug.cgi?id=16132
9990 @safe unittest
9991 {
9992 interface I(T) {}
9993 class C : I!int {}
9994 static assert(is(ReplaceType!(int, string, C) == C));
9995 }
9996
9997 // https://issues.dlang.org/show_bug.cgi?id=22325
9998 @safe unittest
9999 {
10000 static struct Foo(alias f) {}
10001 static void bar() {}
10002 alias _ = ReplaceType!(int, int, Foo!bar);
10003 }
10004
10005 /**
10006 Ternary type with three truth values:
10007
10008 $(UL
10009 $(LI `Ternary.yes` for `true`)
10010 $(LI `Ternary.no` for `false`)
10011 $(LI `Ternary.unknown` as an unknown state)
10012 )
10013
10014 Also known as trinary, trivalent, or trilean.
10015
10016 See_Also:
10017 $(HTTP en.wikipedia.org/wiki/Three-valued_logic,
10018 Three Valued Logic on Wikipedia)
10019 */
10020 struct Ternary
10021 {
10022 @safe @nogc nothrow pure:
10023
10024 private ubyte value = 6;
10025 private static Ternary make(ubyte b)
10026 {
10027 Ternary r = void;
10028 r.value = b;
10029 return r;
10030 }
10031
10032 /**
10033 The possible states of the `Ternary`
10034 */
10035 enum no = make(0);
10036 /// ditto
10037 enum yes = make(2);
10038 /// ditto
10039 enum unknown = make(6);
10040
10041 /**
10042 Construct and assign from a `bool`, receiving `no` for `false` and `yes`
10043 for `true`.
10044 */
10045 this(bool b) { value = b << 1; }
10046
10047 /// ditto
10048 void opAssign(bool b) { value = b << 1; }
10049
10050 /**
10051 Construct a ternary value from another ternary value
10052 */
10053 this(const Ternary b) { value = b.value; }
10054
10055 /**
10056 $(TABLE Truth table for logical operations,
10057 $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`))
10058 $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`))
10059 $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`))
10060 $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
10061 $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`))
10062 $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`))
10063 $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
10064 $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
10065 $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
10066 $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`))
10067 )
10068 */
10069 Ternary opUnary(string s)() if (s == "~")
10070 {
10071 return make((386 >> value) & 6);
10072 }
10073
10074 /// ditto
10075 Ternary opBinary(string s)(Ternary rhs) if (s == "|")
10076 {
10077 return make((25_512 >> (value + rhs.value)) & 6);
10078 }
10079
10080 /// ditto
10081 Ternary opBinary(string s)(Ternary rhs) if (s == "&")
10082 {
10083 return make((26_144 >> (value + rhs.value)) & 6);
10084 }
10085
10086 /// ditto
10087 Ternary opBinary(string s)(Ternary rhs) if (s == "^")
10088 {
10089 return make((26_504 >> (value + rhs.value)) & 6);
10090 }
10091
10092 /// ditto
10093 Ternary opBinary(string s)(bool rhs)
10094 if (s == "|" || s == "&" || s == "^")
10095 {
10096 return this.opBinary!s(Ternary(rhs));
10097 }
10098 }
10099
10100 ///
10101 @safe @nogc nothrow pure
10102 unittest
10103 {
10104 Ternary a;
10105 assert(a == Ternary.unknown);
10106
10107 assert(~Ternary.yes == Ternary.no);
10108 assert(~Ternary.no == Ternary.yes);
10109 assert(~Ternary.unknown == Ternary.unknown);
10110 }
10111
10112 @safe @nogc nothrow pure
10113 unittest
10114 {
10115 alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown;
10116 Ternary[27] truthTableAnd =
10117 [
10118 t, t, t,
10119 t, u, u,
10120 t, f, f,
10121 u, t, u,
10122 u, u, u,
10123 u, f, f,
10124 f, t, f,
10125 f, u, f,
10126 f, f, f,
10127 ];
10128
10129 Ternary[27] truthTableOr =
10130 [
10131 t, t, t,
10132 t, u, t,
10133 t, f, t,
10134 u, t, t,
10135 u, u, u,
10136 u, f, u,
10137 f, t, t,
10138 f, u, u,
10139 f, f, f,
10140 ];
10141
10142 Ternary[27] truthTableXor =
10143 [
10144 t, t, f,
10145 t, u, u,
10146 t, f, t,
10147 u, t, u,
10148 u, u, u,
10149 u, f, u,
10150 f, t, t,
10151 f, u, u,
10152 f, f, f,
10153 ];
10154
10155 for (auto i = 0; i != truthTableAnd.length; i += 3)
10156 {
10157 assert((truthTableAnd[i] & truthTableAnd[i + 1])
10158 == truthTableAnd[i + 2]);
10159 assert((truthTableOr[i] | truthTableOr[i + 1])
10160 == truthTableOr[i + 2]);
10161 assert((truthTableXor[i] ^ truthTableXor[i + 1])
10162 == truthTableXor[i + 2]);
10163 }
10164
10165 Ternary a;
10166 assert(a == Ternary.unknown);
10167 static assert(!is(typeof({ if (a) {} })));
10168 assert(!is(typeof({ auto b = Ternary(3); })));
10169 a = true;
10170 assert(a == Ternary.yes);
10171 a = false;
10172 assert(a == Ternary.no);
10173 a = Ternary.unknown;
10174 assert(a == Ternary.unknown);
10175 Ternary b;
10176 b = a;
10177 assert(b == a);
10178 assert(~Ternary.yes == Ternary.no);
10179 assert(~Ternary.no == Ternary.yes);
10180 assert(~Ternary.unknown == Ternary.unknown);
10181 }
10182
10183 @safe @nogc nothrow pure
10184 unittest
10185 {
10186 Ternary a = Ternary(true);
10187 assert(a == Ternary.yes);
10188 assert((a & false) == Ternary.no);
10189 assert((a | false) == Ternary.yes);
10190 assert((a ^ true) == Ternary.no);
10191 assert((a ^ false) == Ternary.yes);
10192 }
10193
10194 // https://issues.dlang.org/show_bug.cgi?id=22511
10195 @safe unittest
10196 {
10197 static struct S
10198 {
10199 int b;
10200 @disable this(this);
10201 this(ref return scope inout S rhs) inout
10202 {
10203 this.b = rhs.b + 1;
10204 }
10205 }
10206
10207 Nullable!S s1 = S(1);
10208 assert(s1.get().b == 2);
10209 Nullable!S s2 = s1;
10210 assert(s2.get().b == 3);
10211 }
10212
10213 @safe unittest
10214 {
10215 static struct S
10216 {
10217 int b;
10218 this(this) { ++b; }
10219 }
10220
10221 Nullable!S s1 = S(1);
10222 assert(s1.get().b == 2);
10223 Nullable!S s2 = s1;
10224 assert(s2.get().b == 3);
10225 }
10226
10227 /// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed.
10228 /// Old code may be relying on `@safe`ty of some of the member functions which
10229 /// cannot be safe in the new scheme, and
10230 /// can avoid breakage by continuing to use this. `SafeRefCounted` should be
10231 /// preferred, as this type is outdated and unrecommended for new code.
10232 struct RefCounted(T, RefCountedAutoInitialize autoInit =
10233 RefCountedAutoInitialize.yes)
10234 {
10235 version (D_BetterC)
10236 {
10237 private enum enableGCScan = false;
10238 }
10239 else
10240 {
10241 private enum enableGCScan = hasIndirections!T;
10242 }
10243
10244 extern(C) private pure nothrow @nogc static
10245 {
10246 pragma(mangle, "free") void pureFree( void *ptr );
10247 static if (enableGCScan)
10248 import core.memory : GC;
10249 }
10250
10251 struct RefCountedStore
10252 {
10253 private struct Impl
10254 {
10255 T _payload;
10256 size_t _count;
10257 }
10258
10259 private Impl* _store;
10260
10261 private void initialize(A...)(auto ref A args)
10262 {
10263 import core.lifetime : emplace, forward;
10264
10265 allocateStore();
10266 version (D_Exceptions) scope(failure) deallocateStore();
10267 emplace(&_store._payload, forward!args);
10268 _store._count = 1;
10269 }
10270
10271 private void move(ref T source) nothrow pure
10272 {
10273 import std.algorithm.mutation : moveEmplace;
10274
10275 allocateStore();
10276 moveEmplace(source, _store._payload);
10277 _store._count = 1;
10278 }
10279
10280 // 'nothrow': can only generate an Error
10281 private void allocateStore() nothrow pure
10282 {
10283 static if (enableGCScan)
10284 {
10285 import std.internal.memory : enforceCalloc;
10286 _store = cast(Impl*) enforceCalloc(1, Impl.sizeof);
10287 GC.addRange(&_store._payload, T.sizeof);
10288 }
10289 else
10290 {
10291 import std.internal.memory : enforceMalloc;
10292 _store = cast(Impl*) enforceMalloc(Impl.sizeof);
10293 }
10294 }
10295
10296 private void deallocateStore() nothrow pure
10297 {
10298 static if (enableGCScan)
10299 {
10300 GC.removeRange(&this._store._payload);
10301 }
10302 pureFree(_store);
10303 _store = null;
10304 }
10305
10306 @property nothrow @safe pure @nogc
10307 bool isInitialized() const
10308 {
10309 return _store !is null;
10310 }
10311
10312 @property nothrow @safe pure @nogc
10313 size_t refCount() const
10314 {
10315 return isInitialized ? _store._count : 0;
10316 }
10317
10318 void ensureInitialized()()
10319 {
10320 // By checking for `@disable this()` and failing early we can
10321 // produce a clearer error message.
10322 static assert(__traits(compiles, { static T t; }),
10323 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~
10324 "` because `" ~ fullyQualifiedName!T ~
10325 ".this()` is annotated with `@disable`.");
10326 if (!isInitialized) initialize();
10327 }
10328
10329 }
10330 RefCountedStore _refCounted;
10331
10332 @property nothrow @safe
10333 ref inout(RefCountedStore) refCountedStore() inout
10334 {
10335 return _refCounted;
10336 }
10337
10338 this(A...)(auto ref A args) if (A.length > 0)
10339 out
10340 {
10341 assert(refCountedStore.isInitialized);
10342 }
10343 do
10344 {
10345 import core.lifetime : forward;
10346 _refCounted.initialize(forward!args);
10347 }
10348
10349 this(T val)
10350 {
10351 _refCounted.move(val);
10352 }
10353
10354 this(this) @safe pure nothrow @nogc
10355 {
10356 if (!_refCounted.isInitialized) return;
10357 ++_refCounted._store._count;
10358 }
10359
10360 ~this()
10361 {
10362 if (!_refCounted.isInitialized) return;
10363 assert(_refCounted._store._count > 0);
10364 if (--_refCounted._store._count)
10365 return;
10366 // Done, destroy and deallocate
10367 .destroy(_refCounted._store._payload);
10368 _refCounted.deallocateStore();
10369 }
10370
10371 void opAssign(typeof(this) rhs)
10372 {
10373 import std.algorithm.mutation : swap;
10374
10375 swap(_refCounted._store, rhs._refCounted._store);
10376 }
10377
10378 void opAssign(T rhs)
10379 {
10380 import std.algorithm.mutation : move;
10381
10382 static if (autoInit == RefCountedAutoInitialize.yes)
10383 {
10384 _refCounted.ensureInitialized();
10385 }
10386 else
10387 {
10388 assert(_refCounted.isInitialized);
10389 }
10390 move(rhs, _refCounted._store._payload);
10391 }
10392
10393 static if (autoInit == RefCountedAutoInitialize.yes)
10394 {
10395 //Can't use inout here because of potential mutation
10396 @property
10397 ref T refCountedPayload() return
10398 {
10399 _refCounted.ensureInitialized();
10400 return _refCounted._store._payload;
10401 }
10402 }
10403
10404 @property nothrow @safe pure @nogc
10405 ref inout(T) refCountedPayload() inout return
10406 {
10407 assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload.");
10408 return _refCounted._store._payload;
10409 }
10410
10411 alias refCountedPayload this;
10412
10413 static if (is(T == struct) && !is(typeof((ref T t) => t.toString())))
10414 {
10415 string toString(this This)()
10416 {
10417 import std.conv : to;
10418
10419 static if (autoInit)
10420 return to!string(refCountedPayload);
10421 else
10422 {
10423 if (!_refCounted.isInitialized)
10424 return This.stringof ~ "(RefCountedStore(null))";
10425 else
10426 return to!string(_refCounted._store._payload);
10427 }
10428 }
10429 }
10430 }
10431
10432 ///
10433 @betterC pure @system nothrow @nogc unittest
10434 {
10435 auto rc1 = RefCounted!int(5);
10436 assert(rc1 == 5);
10437 auto rc2 = rc1;
10438 rc2 = 42;
10439 assert(rc1 == 42);
10440 }
10441
10442 // More unit tests below SafeRefCounted
10443
10444 /**
10445 * Like $(LREF safeRefCounted) but used to initialize $(LREF RefCounted)
10446 * instead. Intended for backwards compatibility, otherwise it is preferable
10447 * to use `safeRefCounted`.
10448 */
10449 RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val)
10450 {
10451 typeof(return) res;
10452 res._refCounted.move(val);
10453 return res;
10454 }
10455
10456 ///
10457 @system unittest
10458 {
10459 static struct File
10460 {
10461 static size_t nDestroyed;
10462 string name;
10463 @disable this(this); // not copyable
10464 ~this() { name = null; ++nDestroyed; }
10465 }
10466
10467 auto file = File("name");
10468 assert(file.name == "name");
10469 static assert(!__traits(compiles, {auto file2 = file;}));
10470 assert(File.nDestroyed == 0);
10471
10472 {
10473 import std.algorithm.mutation : move;
10474 auto rcFile = refCounted(move(file));
10475 assert(rcFile.name == "name");
10476 assert(File.nDestroyed == 1);
10477 assert(file.name == null);
10478
10479 auto rcFile2 = rcFile;
10480 assert(rcFile.refCountedStore.refCount == 2);
10481 assert(File.nDestroyed == 1);
10482 }
10483
10484 assert(File.nDestroyed == 2);
10485 }
10486
10487 // More unit tests below safeRefCounted