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