1760c2415Smrg // Written in the D programming language.
2760c2415Smrg 
3760c2415Smrg /**
4760c2415Smrg This module implements a variety of type constructors, i.e., templates
5760c2415Smrg that allow construction of new, useful general-purpose types.
6760c2415Smrg 
7760c2415Smrg $(SCRIPT inhibitQuickIndex = 1;)
8760c2415Smrg $(BOOKTABLE,
9760c2415Smrg $(TR $(TH Category) $(TH Functions))
10760c2415Smrg $(TR $(TD Tuple) $(TD
11760c2415Smrg     $(LREF isTuple)
12760c2415Smrg     $(LREF Tuple)
13760c2415Smrg     $(LREF tuple)
14760c2415Smrg     $(LREF reverse)
15760c2415Smrg ))
16760c2415Smrg $(TR $(TD Flags) $(TD
17760c2415Smrg     $(LREF BitFlags)
18760c2415Smrg     $(LREF isBitFlagEnum)
19760c2415Smrg     $(LREF Flag)
20760c2415Smrg     $(LREF No)
21760c2415Smrg     $(LREF Yes)
22760c2415Smrg ))
23760c2415Smrg $(TR $(TD Memory allocation) $(TD
24760c2415Smrg     $(LREF RefCounted)
25760c2415Smrg     $(LREF refCounted)
26760c2415Smrg     $(LREF RefCountedAutoInitialize)
27760c2415Smrg     $(LREF scoped)
28760c2415Smrg     $(LREF Unique)
29760c2415Smrg ))
30760c2415Smrg $(TR $(TD Code generation) $(TD
31760c2415Smrg     $(LREF AutoImplement)
32760c2415Smrg     $(LREF BlackHole)
33760c2415Smrg     $(LREF generateAssertTrap)
34760c2415Smrg     $(LREF generateEmptyFunction)
35760c2415Smrg     $(LREF WhiteHole)
36760c2415Smrg ))
37760c2415Smrg $(TR $(TD Nullable) $(TD
38760c2415Smrg     $(LREF Nullable)
39760c2415Smrg     $(LREF nullable)
40760c2415Smrg     $(LREF NullableRef)
41760c2415Smrg     $(LREF nullableRef)
42760c2415Smrg ))
43760c2415Smrg $(TR $(TD Proxies) $(TD
44760c2415Smrg     $(LREF Proxy)
45760c2415Smrg     $(LREF rebindable)
46760c2415Smrg     $(LREF Rebindable)
47760c2415Smrg     $(LREF ReplaceType)
48760c2415Smrg     $(LREF unwrap)
49760c2415Smrg     $(LREF wrap)
50760c2415Smrg ))
51760c2415Smrg $(TR $(TD Types) $(TD
52760c2415Smrg     $(LREF alignForSize)
53760c2415Smrg     $(LREF Ternary)
54760c2415Smrg     $(LREF Typedef)
55760c2415Smrg     $(LREF TypedefType)
56760c2415Smrg     $(LREF UnqualRef)
57760c2415Smrg ))
58760c2415Smrg )
59760c2415Smrg 
60760c2415Smrg Copyright: Copyright the respective authors, 2008-
61760c2415Smrg License:   $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
62760c2415Smrg Source:    $(PHOBOSSRC std/_typecons.d)
63760c2415Smrg Authors:   $(HTTP erdani.org, Andrei Alexandrescu),
64760c2415Smrg            $(HTTP bartoszmilewski.wordpress.com, Bartosz Milewski),
65760c2415Smrg            Don Clugston,
66760c2415Smrg            Shin Fujishiro,
67760c2415Smrg            Kenji Hara
68760c2415Smrg  */
69760c2415Smrg module std.typecons;
70760c2415Smrg 
71760c2415Smrg import core.stdc.stdint : uintptr_t;
72760c2415Smrg import std.meta; // : AliasSeq, allSatisfy;
73760c2415Smrg import std.traits;
74760c2415Smrg 
75760c2415Smrg ///
76760c2415Smrg @safe unittest
77760c2415Smrg {
78760c2415Smrg     // value tuples
79760c2415Smrg     alias Coord = Tuple!(int, "x", int, "y", int, "z");
80760c2415Smrg     Coord c;
81760c2415Smrg     c[1] = 1;       // access by index
82760c2415Smrg     c.z = 1;        // access by given name
83760c2415Smrg     assert(c == Coord(0, 1, 1));
84760c2415Smrg 
85760c2415Smrg     // names can be omitted
86760c2415Smrg     alias DicEntry = Tuple!(string, string);
87760c2415Smrg 
88760c2415Smrg     // tuples can also be constructed on instantiation
89760c2415Smrg     assert(tuple(2, 3, 4)[1] == 3);
90760c2415Smrg     // construction on instantiation works with names too
91760c2415Smrg     assert(tuple!("x", "y", "z")(2, 3, 4).y == 3);
92760c2415Smrg 
93760c2415Smrg     // Rebindable references to const and immutable objects
94760c2415Smrg     {
foo()95760c2415Smrg         class Widget { void foo() const @safe {} }
96760c2415Smrg         const w1 = new Widget, w2 = new Widget;
97760c2415Smrg         w1.foo();
98760c2415Smrg         // w1 = w2 would not work; can't rebind const object
99760c2415Smrg         auto r = Rebindable!(const Widget)(w1);
100760c2415Smrg         // invoke method as if r were a Widget object
101760c2415Smrg         r.foo();
102760c2415Smrg         // rebind r to refer to another object
103760c2415Smrg         r = w2;
104760c2415Smrg     }
105760c2415Smrg }
106760c2415Smrg 
107760c2415Smrg debug(Unique) import std.stdio;
108760c2415Smrg 
109760c2415Smrg /**
110760c2415Smrg Encapsulates unique ownership of a resource.
111760c2415Smrg 
112760c2415Smrg When a $(D Unique!T) goes out of scope it will call $(D destroy)
113760c2415Smrg on the resource $(D T) that it manages, unless it is transferred.
114760c2415Smrg One important consequence of $(D destroy) is that it will call the
115760c2415Smrg destructor of the resource $(D T).  GC-managed references are not
116760c2415Smrg guaranteed to be valid during a destructor call, but other members of
117760c2415Smrg $(D T), such as file handles or pointers to $(D malloc) memory, will
118760c2415Smrg still be valid during the destructor call.  This allows the resource
119760c2415Smrg $(D T) to deallocate or clean up any non-GC resources.
120760c2415Smrg 
121760c2415Smrg If it is desirable to persist a $(D Unique!T) outside of its original
122760c2415Smrg scope, then it can be transferred.  The transfer can be explicit, by
123760c2415Smrg calling $(D release), or implicit, when returning Unique from a
124760c2415Smrg function. The resource $(D T) can be a polymorphic class object or
125760c2415Smrg instance of an interface, in which case Unique behaves polymorphically
126760c2415Smrg too.
127760c2415Smrg 
128760c2415Smrg If $(D T) is a value type, then $(D Unique!T) will be implemented
129760c2415Smrg as a reference to a $(D T).
130760c2415Smrg */
Unique(T)131760c2415Smrg struct Unique(T)
132760c2415Smrg {
133760c2415Smrg /** Represents a reference to $(D T). Resolves to $(D T*) if $(D T) is a value type. */
134760c2415Smrg static if (is(T == class) || is(T == interface))
135760c2415Smrg     alias RefT = T;
136760c2415Smrg else
137760c2415Smrg     alias RefT = T*;
138760c2415Smrg 
139760c2415Smrg public:
140760c2415Smrg     // Deferred in case we get some language support for checking uniqueness.
141760c2415Smrg     version (None)
142760c2415Smrg     /**
143760c2415Smrg     Allows safe construction of $(D Unique). It creates the resource and
144760c2415Smrg     guarantees unique ownership of it (unless $(D T) publishes aliases of
145760c2415Smrg     $(D this)).
146760c2415Smrg     Note: Nested structs/classes cannot be created.
147760c2415Smrg     Params:
148760c2415Smrg     args = Arguments to pass to $(D T)'s constructor.
149760c2415Smrg     ---
150760c2415Smrg     static class C {}
151760c2415Smrg     auto u = Unique!(C).create();
152760c2415Smrg     ---
153760c2415Smrg     */
154760c2415Smrg     static Unique!T create(A...)(auto ref A args)
155760c2415Smrg     if (__traits(compiles, new T(args)))
156760c2415Smrg     {
157760c2415Smrg         debug(Unique) writeln("Unique.create for ", T.stringof);
158760c2415Smrg         Unique!T u;
159760c2415Smrg         u._p = new T(args);
160760c2415Smrg         return u;
161760c2415Smrg     }
162760c2415Smrg 
163760c2415Smrg     /**
164760c2415Smrg     Constructor that takes an rvalue.
165760c2415Smrg     It will ensure uniqueness, as long as the rvalue
166760c2415Smrg     isn't just a view on an lvalue (e.g., a cast).
167760c2415Smrg     Typical usage:
168760c2415Smrg     ----
169760c2415Smrg     Unique!Foo f = new Foo;
170760c2415Smrg     ----
171760c2415Smrg     */
172760c2415Smrg     this(RefT p)
173760c2415Smrg     {
174760c2415Smrg         debug(Unique) writeln("Unique constructor with rvalue");
175760c2415Smrg         _p = p;
176760c2415Smrg     }
177760c2415Smrg     /**
178760c2415Smrg     Constructor that takes an lvalue. It nulls its source.
179760c2415Smrg     The nulling will ensure uniqueness as long as there
180760c2415Smrg     are no previous aliases to the source.
181760c2415Smrg     */
182760c2415Smrg     this(ref RefT p)
183760c2415Smrg     {
184760c2415Smrg         _p = p;
185760c2415Smrg         debug(Unique) writeln("Unique constructor nulling source");
186760c2415Smrg         p = null;
187760c2415Smrg         assert(p is null);
188760c2415Smrg     }
189760c2415Smrg     /**
190760c2415Smrg     Constructor that takes a $(D Unique) of a type that is convertible to our type.
191760c2415Smrg 
192760c2415Smrg     Typically used to transfer a $(D Unique) rvalue of derived type to
193760c2415Smrg     a $(D Unique) of base type.
194760c2415Smrg     Example:
195760c2415Smrg     ---
196760c2415Smrg     class C : Object {}
197760c2415Smrg 
198760c2415Smrg     Unique!C uc = new C;
199760c2415Smrg     Unique!Object uo = uc.release;
200760c2415Smrg     ---
201760c2415Smrg     */
202760c2415Smrg     this(U)(Unique!U u)
203760c2415Smrg     if (is(u.RefT:RefT))
204760c2415Smrg     {
205760c2415Smrg         debug(Unique) writeln("Unique constructor converting from ", U.stringof);
206760c2415Smrg         _p = u._p;
207760c2415Smrg         u._p = null;
208760c2415Smrg     }
209760c2415Smrg 
210760c2415Smrg     /// Transfer ownership from a $(D Unique) of a type that is convertible to our type.
211760c2415Smrg     void opAssign(U)(Unique!U u)
212760c2415Smrg     if (is(u.RefT:RefT))
213760c2415Smrg     {
214760c2415Smrg         debug(Unique) writeln("Unique opAssign converting from ", U.stringof);
215760c2415Smrg         // first delete any resource we own
216760c2415Smrg         destroy(this);
217760c2415Smrg         _p = u._p;
218760c2415Smrg         u._p = null;
219760c2415Smrg     }
220760c2415Smrg 
221760c2415Smrg     ~this()
222760c2415Smrg     {
223760c2415Smrg         debug(Unique) writeln("Unique destructor of ", (_p is null)? null: _p);
224760c2415Smrg         if (_p !is null)
225760c2415Smrg         {
226760c2415Smrg             destroy(_p);
227760c2415Smrg             _p = null;
228760c2415Smrg         }
229760c2415Smrg     }
230760c2415Smrg 
231760c2415Smrg     /** Returns whether the resource exists. */
232760c2415Smrg     @property bool isEmpty() const
233760c2415Smrg     {
234760c2415Smrg         return _p is null;
235760c2415Smrg     }
236760c2415Smrg     /** Transfer ownership to a $(D Unique) rvalue. Nullifies the current contents.
237760c2415Smrg     Same as calling std.algorithm.move on it.
238760c2415Smrg     */
239760c2415Smrg     Unique release()
240760c2415Smrg     {
241760c2415Smrg         debug(Unique) writeln("Unique Release");
242760c2415Smrg         import std.algorithm.mutation : move;
243760c2415Smrg         return this.move;
244760c2415Smrg     }
245760c2415Smrg 
246760c2415Smrg     /** Forwards member access to contents. */
247760c2415Smrg     mixin Proxy!_p;
248760c2415Smrg 
249760c2415Smrg     /**
250760c2415Smrg     Postblit operator is undefined to prevent the cloning of $(D Unique) objects.
251760c2415Smrg     */
252760c2415Smrg     @disable this(this);
253760c2415Smrg 
254760c2415Smrg private:
255760c2415Smrg     RefT _p;
256760c2415Smrg }
257760c2415Smrg 
258760c2415Smrg ///
259760c2415Smrg @system unittest
260760c2415Smrg {
261760c2415Smrg     static struct S
262760c2415Smrg     {
263760c2415Smrg         int i;
thisS264760c2415Smrg         this(int i){this.i = i;}
265760c2415Smrg     }
266760c2415Smrg     Unique!S produce()
267760c2415Smrg     {
268760c2415Smrg         // Construct a unique instance of S on the heap
269760c2415Smrg         Unique!S ut = new S(5);
270760c2415Smrg         // Implicit transfer of ownership
271760c2415Smrg         return ut;
272760c2415Smrg     }
273760c2415Smrg     // Borrow a unique resource by ref
274760c2415Smrg     void increment(ref Unique!S ur)
275760c2415Smrg     {
276760c2415Smrg         ur.i++;
277760c2415Smrg     }
278760c2415Smrg     void consume(Unique!S u2)
279760c2415Smrg     {
280760c2415Smrg         assert(u2.i == 6);
281760c2415Smrg         // Resource automatically deleted here
282760c2415Smrg     }
283760c2415Smrg     Unique!S u1;
284760c2415Smrg     assert(u1.isEmpty);
285760c2415Smrg     u1 = produce();
286760c2415Smrg     increment(u1);
287760c2415Smrg     assert(u1.i == 6);
288760c2415Smrg     //consume(u1); // Error: u1 is not copyable
289760c2415Smrg     // Transfer ownership of the resource
290760c2415Smrg     consume(u1.release);
291760c2415Smrg     assert(u1.isEmpty);
292760c2415Smrg }
293760c2415Smrg 
294760c2415Smrg @system unittest
295760c2415Smrg {
296760c2415Smrg     // test conversion to base ref
297760c2415Smrg     int deleted = 0;
298760c2415Smrg     class C
299760c2415Smrg     {
~this()300760c2415Smrg         ~this(){deleted++;}
301760c2415Smrg     }
302760c2415Smrg     // constructor conversion
303760c2415Smrg     Unique!Object u = Unique!C(new C);
304760c2415Smrg     static assert(!__traits(compiles, {u = new C;}));
305760c2415Smrg     assert(!u.isEmpty);
306760c2415Smrg     destroy(u);
307760c2415Smrg     assert(deleted == 1);
308760c2415Smrg 
309760c2415Smrg     Unique!C uc = new C;
310760c2415Smrg     static assert(!__traits(compiles, {Unique!Object uo = uc;}));
311760c2415Smrg     Unique!Object uo = new C;
312760c2415Smrg     // opAssign conversion, deleting uo resource first
313760c2415Smrg     uo = uc.release;
314760c2415Smrg     assert(uc.isEmpty);
315760c2415Smrg     assert(!uo.isEmpty);
316760c2415Smrg     assert(deleted == 2);
317760c2415Smrg }
318760c2415Smrg 
319760c2415Smrg @system unittest
320760c2415Smrg {
321760c2415Smrg     debug(Unique) writeln("Unique class");
322760c2415Smrg     class Bar
323760c2415Smrg     {
~this()324760c2415Smrg         ~this() { debug(Unique) writeln("    Bar destructor"); }
val()325760c2415Smrg         int val() const { return 4; }
326760c2415Smrg     }
327760c2415Smrg     alias UBar = Unique!(Bar);
g(UBar u)328760c2415Smrg     UBar g(UBar u)
329760c2415Smrg     {
330760c2415Smrg         debug(Unique) writeln("inside g");
331760c2415Smrg         return u.release;
332760c2415Smrg     }
333760c2415Smrg     auto ub = UBar(new Bar);
334760c2415Smrg     assert(!ub.isEmpty);
335760c2415Smrg     assert(ub.val == 4);
336760c2415Smrg     static assert(!__traits(compiles, {auto ub3 = g(ub);}));
337760c2415Smrg     debug(Unique) writeln("Calling g");
338760c2415Smrg     auto ub2 = g(ub.release);
339760c2415Smrg     debug(Unique) writeln("Returned from g");
340760c2415Smrg     assert(ub.isEmpty);
341760c2415Smrg     assert(!ub2.isEmpty);
342760c2415Smrg }
343760c2415Smrg 
344760c2415Smrg @system unittest
345760c2415Smrg {
346760c2415Smrg     debug(Unique) writeln("Unique interface");
347760c2415Smrg     interface Bar
348760c2415Smrg     {
349760c2415Smrg         int val() const;
350760c2415Smrg     }
351760c2415Smrg     class BarImpl : Bar
352760c2415Smrg     {
353760c2415Smrg         static int count;
this()354760c2415Smrg         this()
355760c2415Smrg         {
356760c2415Smrg             count++;
357760c2415Smrg         }
~this()358760c2415Smrg         ~this()
359760c2415Smrg         {
360760c2415Smrg             count--;
361760c2415Smrg         }
val()362760c2415Smrg         int val() const { return 4; }
363760c2415Smrg     }
364760c2415Smrg     alias UBar = Unique!Bar;
g(UBar u)365760c2415Smrg     UBar g(UBar u)
366760c2415Smrg     {
367760c2415Smrg         debug(Unique) writeln("inside g");
368760c2415Smrg         return u.release;
369760c2415Smrg     }
consume(UBar u)370760c2415Smrg     void consume(UBar u)
371760c2415Smrg     {
372760c2415Smrg         assert(u.val() == 4);
373760c2415Smrg         // Resource automatically deleted here
374760c2415Smrg     }
375760c2415Smrg     auto ub = UBar(new BarImpl);
376760c2415Smrg     assert(BarImpl.count == 1);
377760c2415Smrg     assert(!ub.isEmpty);
378760c2415Smrg     assert(ub.val == 4);
379760c2415Smrg     static assert(!__traits(compiles, {auto ub3 = g(ub);}));
380760c2415Smrg     debug(Unique) writeln("Calling g");
381760c2415Smrg     auto ub2 = g(ub.release);
382760c2415Smrg     debug(Unique) writeln("Returned from g");
383760c2415Smrg     assert(ub.isEmpty);
384760c2415Smrg     assert(!ub2.isEmpty);
385760c2415Smrg     consume(ub2.release);
386760c2415Smrg     assert(BarImpl.count == 0);
387760c2415Smrg }
388760c2415Smrg 
389760c2415Smrg @system unittest
390760c2415Smrg {
391760c2415Smrg     debug(Unique) writeln("Unique struct");
392760c2415Smrg     struct Foo
393760c2415Smrg     {
~thisFoo394760c2415Smrg         ~this() { debug(Unique) writeln("    Foo destructor"); }
valFoo395760c2415Smrg         int val() const { return 3; }
396760c2415Smrg         @disable this(this);
397760c2415Smrg     }
398760c2415Smrg     alias UFoo = Unique!(Foo);
399760c2415Smrg 
f(UFoo u)400760c2415Smrg     UFoo f(UFoo u)
401760c2415Smrg     {
402760c2415Smrg         debug(Unique) writeln("inside f");
403760c2415Smrg         return u.release;
404760c2415Smrg     }
405760c2415Smrg 
406760c2415Smrg     auto uf = UFoo(new Foo);
407760c2415Smrg     assert(!uf.isEmpty);
408760c2415Smrg     assert(uf.val == 3);
409760c2415Smrg     static assert(!__traits(compiles, {auto uf3 = f(uf);}));
410760c2415Smrg     debug(Unique) writeln("Unique struct: calling f");
411760c2415Smrg     auto uf2 = f(uf.release);
412760c2415Smrg     debug(Unique) writeln("Unique struct: returned from f");
413760c2415Smrg     assert(uf.isEmpty);
414760c2415Smrg     assert(!uf2.isEmpty);
415760c2415Smrg }
416760c2415Smrg 
417760c2415Smrg // ensure Unique behaves correctly through const access paths
418760c2415Smrg @system unittest
419760c2415Smrg {
420760c2415Smrg     struct Bar {int val;}
421760c2415Smrg     struct Foo
422760c2415Smrg     {
423760c2415Smrg         Unique!Bar bar = new Bar;
424760c2415Smrg     }
425760c2415Smrg 
426760c2415Smrg     Foo foo;
427760c2415Smrg     foo.bar.val = 6;
428760c2415Smrg     const Foo* ptr = &foo;
429760c2415Smrg     static assert(is(typeof(ptr) == const(Foo*)));
430760c2415Smrg     static assert(is(typeof(ptr.bar) == const(Unique!Bar)));
431760c2415Smrg     static assert(is(typeof(ptr.bar.val) == const(int)));
432760c2415Smrg     assert(ptr.bar.val == 6);
433760c2415Smrg     foo.bar.val = 7;
434760c2415Smrg     assert(ptr.bar.val == 7);
435760c2415Smrg }
436760c2415Smrg 
437760c2415Smrg // Used in Tuple.toString
438760c2415Smrg private template sharedToString(alias field)
439760c2415Smrg     if (is(typeof(field) == shared))
440760c2415Smrg {
441760c2415Smrg     static immutable sharedToString = typeof(field).stringof;
442760c2415Smrg }
443760c2415Smrg 
444760c2415Smrg private template sharedToString(alias field)
445760c2415Smrg     if (!is(typeof(field) == shared))
446760c2415Smrg {
447760c2415Smrg     alias sharedToString = field;
448760c2415Smrg }
449760c2415Smrg 
450760c2415Smrg /**
451760c2415Smrg _Tuple of values, for example $(D Tuple!(int, string)) is a record that
452760c2415Smrg stores an $(D int) and a $(D string). $(D Tuple) can be used to bundle
453760c2415Smrg values together, notably when returning multiple values from a
454760c2415Smrg function. If $(D obj) is a `Tuple`, the individual members are
455760c2415Smrg accessible with the syntax $(D obj[0]) for the first field, $(D obj[1])
456760c2415Smrg for the second, and so on.
457760c2415Smrg 
458760c2415Smrg The choice of zero-based indexing instead of one-base indexing was
459760c2415Smrg motivated by the ability to use value tuples with various compile-time
460760c2415Smrg loop constructs (e.g. $(REF AliasSeq, std,meta) iteration), all of which use
461760c2415Smrg zero-based indexing.
462760c2415Smrg 
463760c2415Smrg See_Also: $(LREF tuple).
464760c2415Smrg 
465760c2415Smrg Params:
466760c2415Smrg     Specs = A list of types (and optionally, member names) that the `Tuple` contains.
467760c2415Smrg */
Tuple(Specs...)468760c2415Smrg template Tuple(Specs...)
469760c2415Smrg {
470760c2415Smrg     import std.meta : staticMap;
471760c2415Smrg 
472760c2415Smrg     // Parse (type,name) pairs (FieldSpecs) out of the specified
473760c2415Smrg     // arguments. Some fields would have name, others not.
474760c2415Smrg     template parseSpecs(Specs...)
475760c2415Smrg     {
476760c2415Smrg         static if (Specs.length == 0)
477760c2415Smrg         {
478760c2415Smrg             alias parseSpecs = AliasSeq!();
479760c2415Smrg         }
480760c2415Smrg         else static if (is(Specs[0]))
481760c2415Smrg         {
482760c2415Smrg             static if (is(typeof(Specs[1]) : string))
483760c2415Smrg             {
484760c2415Smrg                 alias parseSpecs =
485760c2415Smrg                     AliasSeq!(FieldSpec!(Specs[0 .. 2]),
486760c2415Smrg                               parseSpecs!(Specs[2 .. $]));
487760c2415Smrg             }
488760c2415Smrg             else
489760c2415Smrg             {
490760c2415Smrg                 alias parseSpecs =
491760c2415Smrg                     AliasSeq!(FieldSpec!(Specs[0]),
492760c2415Smrg                               parseSpecs!(Specs[1 .. $]));
493760c2415Smrg             }
494760c2415Smrg         }
495760c2415Smrg         else
496760c2415Smrg         {
497760c2415Smrg             static assert(0, "Attempted to instantiate Tuple with an "
498760c2415Smrg                             ~"invalid argument: "~ Specs[0].stringof);
499760c2415Smrg         }
500760c2415Smrg     }
501760c2415Smrg 
502760c2415Smrg     template FieldSpec(T, string s = "")
503760c2415Smrg     {
504760c2415Smrg         alias Type = T;
505760c2415Smrg         alias name = s;
506760c2415Smrg     }
507760c2415Smrg 
508760c2415Smrg     alias fieldSpecs = parseSpecs!Specs;
509760c2415Smrg 
510760c2415Smrg     // Used with staticMap.
511760c2415Smrg     alias extractType(alias spec) = spec.Type;
512760c2415Smrg     alias extractName(alias spec) = spec.name;
513760c2415Smrg 
514760c2415Smrg     // Generates named fields as follows:
515760c2415Smrg     //    alias name_0 = Identity!(field[0]);
516760c2415Smrg     //    alias name_1 = Identity!(field[1]);
517760c2415Smrg     //      :
518760c2415Smrg     // NOTE: field[k] is an expression (which yields a symbol of a
519760c2415Smrg     //       variable) and can't be aliased directly.
520760c2415Smrg     string injectNamedFields()
521760c2415Smrg     {
522760c2415Smrg         string decl = "";
523760c2415Smrg         foreach (i, name; staticMap!(extractName, fieldSpecs))
524760c2415Smrg         {
525760c2415Smrg             import std.format : format;
526760c2415Smrg 
527760c2415Smrg             decl ~= format("alias _%s = Identity!(field[%s]);", i, i);
528760c2415Smrg             if (name.length != 0)
529760c2415Smrg             {
530760c2415Smrg                 decl ~= format("alias %s = _%s;", name, i);
531760c2415Smrg             }
532760c2415Smrg         }
533760c2415Smrg         return decl;
534760c2415Smrg     }
535760c2415Smrg 
536760c2415Smrg     // Returns Specs for a subtuple this[from .. to] preserving field
537760c2415Smrg     // names if any.
538760c2415Smrg     alias sliceSpecs(size_t from, size_t to) =
539760c2415Smrg         staticMap!(expandSpec, fieldSpecs[from .. to]);
540760c2415Smrg 
541760c2415Smrg     template expandSpec(alias spec)
542760c2415Smrg     {
543760c2415Smrg         static if (spec.name.length == 0)
544760c2415Smrg         {
545760c2415Smrg             alias expandSpec = AliasSeq!(spec.Type);
546760c2415Smrg         }
547760c2415Smrg         else
548760c2415Smrg         {
549760c2415Smrg             alias expandSpec = AliasSeq!(spec.Type, spec.name);
550760c2415Smrg         }
551760c2415Smrg     }
552760c2415Smrg 
553760c2415Smrg     enum areCompatibleTuples(Tup1, Tup2, string op) = isTuple!Tup2 && is(typeof(
554760c2415Smrg     (ref Tup1 tup1, ref Tup2 tup2)
555760c2415Smrg     {
556760c2415Smrg         static assert(tup1.field.length == tup2.field.length);
557760c2415Smrg         foreach (i, _; Tup1.Types)
558760c2415Smrg         {
559760c2415Smrg             auto lhs = typeof(tup1.field[i]).init;
560760c2415Smrg             auto rhs = typeof(tup2.field[i]).init;
561760c2415Smrg             static if (op == "=")
562760c2415Smrg                 lhs = rhs;
563760c2415Smrg             else
564760c2415Smrg                 auto result = mixin("lhs "~op~" rhs");
565760c2415Smrg         }
566760c2415Smrg     }));
567760c2415Smrg 
568760c2415Smrg     enum areBuildCompatibleTuples(Tup1, Tup2) = isTuple!Tup2 && is(typeof(
569760c2415Smrg     {
570760c2415Smrg         static assert(Tup1.Types.length == Tup2.Types.length);
571760c2415Smrg         foreach (i, _; Tup1.Types)
572760c2415Smrg             static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i]));
573760c2415Smrg     }));
574760c2415Smrg 
575760c2415Smrg     /+ Returns $(D true) iff a $(D T) can be initialized from a $(D U). +/
576760c2415Smrg     enum isBuildable(T, U) =  is(typeof(
577760c2415Smrg     {
578760c2415Smrg         U u = U.init;
579760c2415Smrg         T t = u;
580760c2415Smrg     }));
581760c2415Smrg     /+ Helper for partial instanciation +/
582760c2415Smrg     template isBuildableFrom(U)
583760c2415Smrg     {
584760c2415Smrg         enum isBuildableFrom(T) = isBuildable!(T, U);
585760c2415Smrg     }
586760c2415Smrg 
587760c2415Smrg     struct Tuple
588760c2415Smrg     {
589760c2415Smrg         /**
590760c2415Smrg          * The types of the `Tuple`'s components.
591760c2415Smrg          */
592760c2415Smrg         alias Types = staticMap!(extractType, fieldSpecs);
593760c2415Smrg 
594760c2415Smrg         ///
595760c2415Smrg         static if (Specs.length == 0) @safe unittest
596760c2415Smrg         {
597760c2415Smrg             alias Fields = Tuple!(int, "id", string, float);
598760c2415Smrg             static assert(is(Fields.Types == AliasSeq!(int, string, float)));
599760c2415Smrg         }
600760c2415Smrg 
601760c2415Smrg         /**
602760c2415Smrg          * The names of the `Tuple`'s components. Unnamed fields have empty names.
603760c2415Smrg          */
604760c2415Smrg         alias fieldNames = staticMap!(extractName, fieldSpecs);
605760c2415Smrg 
606760c2415Smrg         ///
607760c2415Smrg         static if (Specs.length == 0) @safe unittest
608760c2415Smrg         {
609760c2415Smrg             alias Fields = Tuple!(int, "id", string, float);
610760c2415Smrg             static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
611760c2415Smrg         }
612760c2415Smrg 
613760c2415Smrg         /**
614760c2415Smrg          * Use $(D t.expand) for a `Tuple` $(D t) to expand it into its
615760c2415Smrg          * components. The result of $(D expand) acts as if the `Tuple`'s components
616760c2415Smrg          * were listed as a list of values. (Ordinarily, a $(D Tuple) acts as a
617760c2415Smrg          * single value.)
618760c2415Smrg          */
619760c2415Smrg         Types expand;
620760c2415Smrg         mixin(injectNamedFields());
621760c2415Smrg 
622760c2415Smrg         ///
623760c2415Smrg         static if (Specs.length == 0) @safe unittest
624760c2415Smrg         {
625760c2415Smrg             auto t1 = tuple(1, " hello ", 2.3);
626760c2415Smrg             assert(t1.toString() == `Tuple!(int, string, double)(1, " hello ", 2.3)`);
627760c2415Smrg 
628760c2415Smrg             void takeSeveralTypes(int n, string s, bool b)
629760c2415Smrg             {
630760c2415Smrg                 assert(n == 4 && s == "test" && b == false);
631760c2415Smrg             }
632760c2415Smrg 
633760c2415Smrg             auto t2 = tuple(4, "test", false);
634760c2415Smrg             //t.expand acting as a list of values
635760c2415Smrg             takeSeveralTypes(t2.expand);
636760c2415Smrg         }
637760c2415Smrg 
638760c2415Smrg         static if (is(Specs))
639760c2415Smrg         {
640760c2415Smrg             // This is mostly to make t[n] work.
641760c2415Smrg             alias expand this;
642760c2415Smrg         }
643760c2415Smrg         else
644760c2415Smrg         {
645760c2415Smrg             @property
646760c2415Smrg             ref inout(Tuple!Types) _Tuple_super() inout @trusted
647760c2415Smrg             {
648760c2415Smrg                 foreach (i, _; Types)   // Rely on the field layout
649760c2415Smrg                 {
650760c2415Smrg                     static assert(typeof(return).init.tupleof[i].offsetof ==
651760c2415Smrg                                                        expand[i].offsetof);
652760c2415Smrg                 }
653760c2415Smrg                 return *cast(typeof(return)*) &(field[0]);
654760c2415Smrg             }
655760c2415Smrg             // This is mostly to make t[n] work.
656760c2415Smrg             alias _Tuple_super this;
657760c2415Smrg         }
658760c2415Smrg 
659760c2415Smrg         // backwards compatibility
660760c2415Smrg         alias field = expand;
661760c2415Smrg 
662760c2415Smrg         /**
663760c2415Smrg          * Constructor taking one value for each field.
664760c2415Smrg          *
665760c2415Smrg          * Params:
666760c2415Smrg          *     values = A list of values that are either the same
667760c2415Smrg          *              types as those given by the `Types` field
668760c2415Smrg          *              of this `Tuple`, or can implicitly convert
669760c2415Smrg          *              to those types. They must be in the same
670760c2415Smrg          *              order as they appear in `Types`.
671760c2415Smrg          */
672760c2415Smrg         static if (Types.length > 0)
673760c2415Smrg         {
674760c2415Smrg             this(Types values)
675760c2415Smrg             {
676760c2415Smrg                 field[] = values[];
677760c2415Smrg             }
678760c2415Smrg         }
679760c2415Smrg 
680760c2415Smrg         ///
681760c2415Smrg         static if (Specs.length == 0) @safe unittest
682760c2415Smrg         {
683760c2415Smrg             alias ISD = Tuple!(int, string, double);
684760c2415Smrg             auto tup = ISD(1, "test", 3.2);
685760c2415Smrg             assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`);
686760c2415Smrg         }
687760c2415Smrg 
688760c2415Smrg         /**
689760c2415Smrg          * Constructor taking a compatible array.
690760c2415Smrg          *
691760c2415Smrg          * Params:
692760c2415Smrg          *     values = A compatible static array to build the `Tuple` from.
693760c2415Smrg          *              Array slices are not supported.
694760c2415Smrg          */
695760c2415Smrg         this(U, size_t n)(U[n] values)
696760c2415Smrg         if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))
697760c2415Smrg         {
698760c2415Smrg             foreach (i, _; Types)
699760c2415Smrg             {
700760c2415Smrg                 field[i] = values[i];
701760c2415Smrg             }
702760c2415Smrg         }
703760c2415Smrg 
704760c2415Smrg         ///
705760c2415Smrg         static if (Specs.length == 0) @safe unittest
706760c2415Smrg         {
707760c2415Smrg             int[2] ints;
708760c2415Smrg             Tuple!(int, int) t = ints;
709760c2415Smrg         }
710760c2415Smrg 
711760c2415Smrg         /**
712760c2415Smrg          * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible
713760c2415Smrg          * $(B iff) they are both of the same length, and, for each type `T` on the
714760c2415Smrg          * left-hand side, the corresponding type `U` on the right-hand side can
715760c2415Smrg          * implicitly convert to `T`.
716760c2415Smrg          *
717760c2415Smrg          * Params:
718760c2415Smrg          *     another = A compatible `Tuple` to build from. Its type must be
719760c2415Smrg          *               compatible with the target `Tuple`'s type.
720760c2415Smrg          */
721760c2415Smrg         this(U)(U another)
722760c2415Smrg         if (areBuildCompatibleTuples!(typeof(this), U))
723760c2415Smrg         {
724760c2415Smrg             field[] = another.field[];
725760c2415Smrg         }
726760c2415Smrg 
727760c2415Smrg         ///
728760c2415Smrg         static if (Specs.length == 0) @safe unittest
729760c2415Smrg         {
730760c2415Smrg             alias IntVec = Tuple!(int, int, int);
731760c2415Smrg             alias DubVec = Tuple!(double, double, double);
732760c2415Smrg 
733760c2415Smrg             IntVec iv = tuple(1, 1, 1);
734760c2415Smrg 
735760c2415Smrg             //Ok, int can implicitly convert to double
736760c2415Smrg             DubVec dv = iv;
737760c2415Smrg             //Error: double cannot implicitly convert to int
738760c2415Smrg             //IntVec iv2 = dv;
739760c2415Smrg         }
740760c2415Smrg 
741760c2415Smrg         /**
742760c2415Smrg          * Comparison for equality. Two `Tuple`s are considered equal
743760c2415Smrg          * $(B iff) they fulfill the following criteria:
744760c2415Smrg          *
745760c2415Smrg          * $(UL
746760c2415Smrg          *   $(LI Each `Tuple` is the same length.)
747760c2415Smrg          *   $(LI For each type `T` on the left-hand side and each type
748760c2415Smrg          *        `U` on the right-hand side, values of type `T` can be
749760c2415Smrg          *        compared with values of type `U`.)
750760c2415Smrg          *   $(LI For each value `v1` on the left-hand side and each value
751760c2415Smrg          *        `v2` on the right-hand side, the expression `v1 == v2` is
752760c2415Smrg          *        true.))
753760c2415Smrg          *
754760c2415Smrg          * Params:
755760c2415Smrg          *     rhs = The `Tuple` to compare against. It must meeting the criteria
756760c2415Smrg          *           for comparison between `Tuple`s.
757760c2415Smrg          *
758760c2415Smrg          * Returns:
759760c2415Smrg          *     true if both `Tuple`s are equal, otherwise false.
760760c2415Smrg          */
761760c2415Smrg         bool opEquals(R)(R rhs)
762760c2415Smrg         if (areCompatibleTuples!(typeof(this), R, "=="))
763760c2415Smrg         {
764760c2415Smrg             return field[] == rhs.field[];
765760c2415Smrg         }
766760c2415Smrg 
767760c2415Smrg         /// ditto
768760c2415Smrg         bool opEquals(R)(R rhs) const
769760c2415Smrg         if (areCompatibleTuples!(typeof(this), R, "=="))
770760c2415Smrg         {
771760c2415Smrg             return field[] == rhs.field[];
772760c2415Smrg         }
773760c2415Smrg 
774760c2415Smrg         ///
775760c2415Smrg         static if (Specs.length == 0) @safe unittest
776760c2415Smrg         {
777760c2415Smrg             Tuple!(int, string) t1 = tuple(1, "test");
778760c2415Smrg             Tuple!(double, string) t2 =  tuple(1.0, "test");
779760c2415Smrg             //Ok, int can be compared with double and
780760c2415Smrg             //both have a value of 1
781760c2415Smrg             assert(t1 == t2);
782760c2415Smrg         }
783760c2415Smrg 
784760c2415Smrg         /**
785760c2415Smrg          * Comparison for ordering.
786760c2415Smrg          *
787760c2415Smrg          * Params:
788760c2415Smrg          *     rhs = The `Tuple` to compare against. It must meet the criteria
789760c2415Smrg          *           for comparison between `Tuple`s.
790760c2415Smrg          *
791760c2415Smrg          * Returns:
792760c2415Smrg          * For any values `v1` on the right-hand side and `v2` on the
793760c2415Smrg          * left-hand side:
794760c2415Smrg          *
795760c2415Smrg          * $(UL
796760c2415Smrg          *   $(LI A negative integer if the expression `v1 < v2` is true.)
797760c2415Smrg          *   $(LI A positive integer if the expression `v1 > v2` is true.)
798760c2415Smrg          *   $(LI 0 if the expression `v1 == v2` is true.))
799760c2415Smrg          */
800760c2415Smrg         int opCmp(R)(R rhs)
801760c2415Smrg         if (areCompatibleTuples!(typeof(this), R, "<"))
802760c2415Smrg         {
803760c2415Smrg             foreach (i, Unused; Types)
804760c2415Smrg             {
805760c2415Smrg                 if (field[i] != rhs.field[i])
806760c2415Smrg                 {
807760c2415Smrg                     return field[i] < rhs.field[i] ? -1 : 1;
808760c2415Smrg                 }
809760c2415Smrg             }
810760c2415Smrg             return 0;
811760c2415Smrg         }
812760c2415Smrg 
813760c2415Smrg         /// ditto
814760c2415Smrg         int opCmp(R)(R rhs) const
815760c2415Smrg         if (areCompatibleTuples!(typeof(this), R, "<"))
816760c2415Smrg         {
817760c2415Smrg             foreach (i, Unused; Types)
818760c2415Smrg             {
819760c2415Smrg                 if (field[i] != rhs.field[i])
820760c2415Smrg                 {
821760c2415Smrg                     return field[i] < rhs.field[i] ? -1 : 1;
822760c2415Smrg                 }
823760c2415Smrg             }
824760c2415Smrg             return 0;
825760c2415Smrg         }
826760c2415Smrg 
827760c2415Smrg         /**
828760c2415Smrg             The first `v1` for which `v1 > v2` is true determines
829760c2415Smrg             the result. This could lead to unexpected behaviour.
830760c2415Smrg          */
831760c2415Smrg         static if (Specs.length == 0) @safe unittest
832760c2415Smrg         {
833760c2415Smrg             auto tup1 = tuple(1, 1, 1);
834760c2415Smrg             auto tup2 = tuple(1, 100, 100);
835760c2415Smrg             assert(tup1 < tup2);
836760c2415Smrg 
837760c2415Smrg             //Only the first result matters for comparison
838760c2415Smrg             tup1[0] = 2;
839760c2415Smrg             assert(tup1 > tup2);
840760c2415Smrg         }
841760c2415Smrg 
842760c2415Smrg         /**
843760c2415Smrg          * Assignment from another `Tuple`.
844760c2415Smrg          *
845760c2415Smrg          * Params:
846760c2415Smrg          *     rhs = The source `Tuple` to assign from. Each element of the
847760c2415Smrg          *           source `Tuple` must be implicitly assignable to each
848760c2415Smrg          *           respective element of the target `Tuple`.
849760c2415Smrg          */
850760c2415Smrg         void opAssign(R)(auto ref R rhs)
851760c2415Smrg         if (areCompatibleTuples!(typeof(this), R, "="))
852760c2415Smrg         {
853760c2415Smrg             import std.algorithm.mutation : swap;
854760c2415Smrg 
855760c2415Smrg             static if (is(R : Tuple!Types) && !__traits(isRef, rhs))
856760c2415Smrg             {
857760c2415Smrg                 if (__ctfe)
858760c2415Smrg                 {
859760c2415Smrg                     // Cannot use swap at compile time
860760c2415Smrg                     field[] = rhs.field[];
861760c2415Smrg                 }
862760c2415Smrg                 else
863760c2415Smrg                 {
864760c2415Smrg                     // Use swap-and-destroy to optimize rvalue assignment
865760c2415Smrg                     swap!(Tuple!Types)(this, rhs);
866760c2415Smrg                 }
867760c2415Smrg             }
868760c2415Smrg             else
869760c2415Smrg             {
870760c2415Smrg                 // Do not swap; opAssign should be called on the fields.
871760c2415Smrg                 field[] = rhs.field[];
872760c2415Smrg             }
873760c2415Smrg         }
874760c2415Smrg 
875760c2415Smrg         /**
876760c2415Smrg          * Renames the elements of a $(LREF Tuple).
877760c2415Smrg          *
878760c2415Smrg          * `rename` uses the passed `names` and returns a new
879760c2415Smrg          * $(LREF Tuple) using these names, with the content
880760c2415Smrg          * unchanged.
881760c2415Smrg          * If fewer names are passed than there are members
882760c2415Smrg          * of the $(LREF Tuple) then those trailing members are unchanged.
883760c2415Smrg          * An empty string will remove the name for that member.
884760c2415Smrg          * It is an compile-time error to pass more names than
885760c2415Smrg          * there are members of the $(LREF Tuple).
886760c2415Smrg          */
887760c2415Smrg         ref rename(names...)() return
888760c2415Smrg         if (names.length == 0 || allSatisfy!(isSomeString, typeof(names)))
889760c2415Smrg         {
890760c2415Smrg             import std.algorithm.comparison : equal;
891760c2415Smrg             // to circumvent bug 16418
892760c2415Smrg             static if (names.length == 0 || equal([names], [fieldNames]))
893760c2415Smrg                 return this;
894760c2415Smrg             else
895760c2415Smrg             {
896760c2415Smrg                 enum nT = Types.length;
897760c2415Smrg                 enum nN = names.length;
898760c2415Smrg                 static assert(nN <= nT, "Cannot have more names than tuple members");
899760c2415Smrg                 alias allNames = AliasSeq!(names, fieldNames[nN .. $]);
900760c2415Smrg 
901760c2415Smrg                 template GetItem(size_t idx)
902760c2415Smrg                 {
903760c2415Smrg                     import std.array : empty;
904760c2415Smrg                     static if (idx < nT)
905760c2415Smrg                         alias GetItem = Alias!(Types[idx]);
906760c2415Smrg                     else static if (allNames[idx - nT].empty)
907760c2415Smrg                         alias GetItem = AliasSeq!();
908760c2415Smrg                     else
909760c2415Smrg                         alias GetItem = Alias!(allNames[idx - nT]);
910760c2415Smrg                 }
911760c2415Smrg 
912760c2415Smrg                 import std.range : roundRobin, iota;
913760c2415Smrg                 alias NewTupleT = Tuple!(staticMap!(GetItem, aliasSeqOf!(
914760c2415Smrg                         roundRobin(iota(nT), iota(nT, 2*nT)))));
915760c2415Smrg                 return *(() @trusted => cast(NewTupleT*)&this)();
916760c2415Smrg             }
917760c2415Smrg         }
918760c2415Smrg 
919760c2415Smrg         ///
920760c2415Smrg         static if (Specs.length == 0) @safe unittest
921760c2415Smrg         {
922760c2415Smrg             auto t0 = tuple(4, "hello");
923760c2415Smrg 
924760c2415Smrg             auto t0Named = t0.rename!("val", "tag");
925760c2415Smrg             assert(t0Named.val == 4);
926760c2415Smrg             assert(t0Named.tag == "hello");
927760c2415Smrg 
928760c2415Smrg             Tuple!(float, "dat", size_t[2], "pos") t1;
929760c2415Smrg             t1.pos = [2, 1];
930760c2415Smrg             auto t1Named = t1.rename!"height";
931760c2415Smrg             t1Named.height = 3.4f;
932760c2415Smrg             assert(t1Named.height == 3.4f);
933760c2415Smrg             assert(t1Named.pos == [2, 1]);
934760c2415Smrg             t1Named.rename!"altitude".altitude = 5;
935760c2415Smrg             assert(t1Named.height == 5);
936760c2415Smrg 
937760c2415Smrg             Tuple!(int, "a", int, int, "c") t2;
938760c2415Smrg             t2 = tuple(3,4,5);
939760c2415Smrg             auto t2Named = t2.rename!("", "b");
940760c2415Smrg             // "a" no longer has a name
941760c2415Smrg             static assert(!hasMember!(typeof(t2Named), "a"));
942760c2415Smrg             assert(t2Named[0] == 3);
943760c2415Smrg             assert(t2Named.b == 4);
944760c2415Smrg             assert(t2Named.c == 5);
945760c2415Smrg 
946760c2415Smrg             // not allowed to specify more names than the tuple has members
947760c2415Smrg             static assert(!__traits(compiles, t2.rename!("a","b","c","d")));
948760c2415Smrg 
949760c2415Smrg             // use it in a range pipeline
950760c2415Smrg             import std.range : iota, zip;
951760c2415Smrg             import std.algorithm.iteration : map, sum;
952760c2415Smrg             auto res = zip(iota(1, 4), iota(10, 13))
953760c2415Smrg                 .map!(t => t.rename!("a", "b"))
954760c2415Smrg                 .map!(t => t.a * t.b)
955760c2415Smrg                 .sum;
956760c2415Smrg             assert(res == 68);
957760c2415Smrg         }
958760c2415Smrg 
959760c2415Smrg         /**
960760c2415Smrg          * Overload of $(LREF _rename) that takes an associative array
961760c2415Smrg          * `translate` as a template parameter, where the keys are
962760c2415Smrg          * either the names or indices of the members to be changed
963760c2415Smrg          * and the new names are the corresponding values.
964760c2415Smrg          * Every key in `translate` must be the name of a member of the
965760c2415Smrg          * $(LREF tuple).
966760c2415Smrg          * The same rules for empty strings apply as for the variadic
967760c2415Smrg          * template overload of $(LREF _rename).
968760c2415Smrg         */
969760c2415Smrg         ref rename(alias translate)()
970760c2415Smrg         if (is(typeof(translate) : V[K], V, K) && isSomeString!V &&
971760c2415Smrg                 (isSomeString!K || is(K : size_t)))
972760c2415Smrg         {
973760c2415Smrg             import std.range : ElementType;
974760c2415Smrg             static if (isSomeString!(ElementType!(typeof(translate.keys))))
975760c2415Smrg             {
976760c2415Smrg                 {
977760c2415Smrg                     import std.conv : to;
978760c2415Smrg                     import std.algorithm.iteration : filter;
979760c2415Smrg                     import std.algorithm.searching : canFind;
980760c2415Smrg                     enum notFound = translate.keys
981760c2415Smrg                         .filter!(k => fieldNames.canFind(k) == -1);
982760c2415Smrg                     static assert(notFound.empty, "Cannot find members "
983760c2415Smrg                         ~ notFound.to!string ~ " in type "
984760c2415Smrg                         ~ typeof(this).stringof);
985760c2415Smrg                 }
986760c2415Smrg                 return this.rename!(aliasSeqOf!(
987760c2415Smrg                     {
988760c2415Smrg                         import std.array : empty;
989760c2415Smrg                         auto names = [fieldNames];
990760c2415Smrg                         foreach (ref n; names)
991760c2415Smrg                             if (!n.empty)
992760c2415Smrg                                 if (auto p = n in translate)
993760c2415Smrg                                     n = *p;
994760c2415Smrg                         return names;
995760c2415Smrg                     }()));
996760c2415Smrg             }
997760c2415Smrg             else
998760c2415Smrg             {
999760c2415Smrg                 {
1000760c2415Smrg                     import std.algorithm.iteration : filter;
1001760c2415Smrg                     import std.conv : to;
1002760c2415Smrg                     enum invalid = translate.keys.
1003760c2415Smrg                         filter!(k => k < 0 || k >= this.length);
1004760c2415Smrg                     static assert(invalid.empty, "Indices " ~ invalid.to!string
1005760c2415Smrg                         ~ " are out of bounds for tuple with length "
1006760c2415Smrg                         ~ this.length.to!string);
1007760c2415Smrg                 }
1008760c2415Smrg                 return this.rename!(aliasSeqOf!(
1009760c2415Smrg                     {
1010760c2415Smrg                         auto names = [fieldNames];
1011760c2415Smrg                         foreach (k, v; translate)
1012760c2415Smrg                             names[k] = v;
1013760c2415Smrg                         return names;
1014760c2415Smrg                     }()));
1015760c2415Smrg             }
1016760c2415Smrg         }
1017760c2415Smrg 
1018760c2415Smrg         ///
1019760c2415Smrg         static if (Specs.length == 0) @safe unittest
1020760c2415Smrg         {
1021760c2415Smrg             //replacing names by their current name
1022760c2415Smrg 
1023760c2415Smrg             Tuple!(float, "dat", size_t[2], "pos") t1;
1024760c2415Smrg             t1.pos = [2, 1];
1025760c2415Smrg             auto t1Named = t1.rename!(["dat": "height"]);
1026760c2415Smrg             t1Named.height = 3.4;
1027760c2415Smrg             assert(t1Named.pos == [2, 1]);
1028760c2415Smrg             t1Named.rename!(["height": "altitude"]).altitude = 5;
1029760c2415Smrg             assert(t1Named.height == 5);
1030760c2415Smrg 
1031760c2415Smrg             Tuple!(int, "a", int, "b") t2;
1032760c2415Smrg             t2 = tuple(3, 4);
1033760c2415Smrg             auto t2Named = t2.rename!(["a": "b", "b": "c"]);
1034760c2415Smrg             assert(t2Named.b == 3);
1035760c2415Smrg             assert(t2Named.c == 4);
1036760c2415Smrg         }
1037760c2415Smrg 
1038760c2415Smrg         ///
1039760c2415Smrg         static if (Specs.length == 0) @safe unittest
1040760c2415Smrg         {
1041760c2415Smrg             //replace names by their position
1042760c2415Smrg 
1043760c2415Smrg             Tuple!(float, "dat", size_t[2], "pos") t1;
1044760c2415Smrg             t1.pos = [2, 1];
1045760c2415Smrg             auto t1Named = t1.rename!([0: "height"]);
1046760c2415Smrg             t1Named.height = 3.4;
1047760c2415Smrg             assert(t1Named.pos == [2, 1]);
1048760c2415Smrg             t1Named.rename!([0: "altitude"]).altitude = 5;
1049760c2415Smrg             assert(t1Named.height == 5);
1050760c2415Smrg 
1051760c2415Smrg             Tuple!(int, "a", int, "b", int, "c") t2;
1052760c2415Smrg             t2 = tuple(3, 4, 5);
1053760c2415Smrg             auto t2Named = t2.rename!([0: "c", 2: "a"]);
1054760c2415Smrg             assert(t2Named.a == 5);
1055760c2415Smrg             assert(t2Named.b == 4);
1056760c2415Smrg             assert(t2Named.c == 3);
1057760c2415Smrg         }
1058760c2415Smrg 
1059760c2415Smrg         static if (Specs.length == 0) @safe unittest
1060760c2415Smrg         {
1061760c2415Smrg             //check that empty translations work fine
1062760c2415Smrg             enum string[string] a0 = null;
1063760c2415Smrg             enum string[int] a1 = null;
1064760c2415Smrg             Tuple!(float, "a", float, "b") t0;
1065760c2415Smrg 
1066760c2415Smrg             auto t1 = t0.rename!a0;
1067760c2415Smrg 
1068760c2415Smrg             t1.a = 3;
1069760c2415Smrg             t1.b = 4;
1070760c2415Smrg             auto t2 = t0.rename!a1;
1071760c2415Smrg             t2.a = 3;
1072760c2415Smrg             t2.b = 4;
1073760c2415Smrg             auto t3 = t0.rename;
1074760c2415Smrg             t3.a = 3;
1075760c2415Smrg             t3.b = 4;
1076760c2415Smrg         }
1077760c2415Smrg 
1078760c2415Smrg         /**
1079760c2415Smrg          * Takes a slice by-reference of this `Tuple`.
1080760c2415Smrg          *
1081760c2415Smrg          * Params:
1082760c2415Smrg          *     from = A `size_t` designating the starting position of the slice.
1083760c2415Smrg          *     to = A `size_t` designating the ending position (exclusive) of the slice.
1084760c2415Smrg          *
1085760c2415Smrg          * Returns:
1086760c2415Smrg          *     A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original.
1087760c2415Smrg          *     It has the same types and values as the range `[from, to$(RPAREN)` in
1088760c2415Smrg          *     the original.
1089760c2415Smrg          */
1090760c2415Smrg         @property
1091760c2415Smrg         ref inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout @trusted
1092760c2415Smrg         if (from <= to && to <= Types.length)
1093760c2415Smrg         {
1094760c2415Smrg             static assert(
1095760c2415Smrg                 (typeof(this).alignof % typeof(return).alignof == 0) &&
1096760c2415Smrg                 (expand[from].offsetof % typeof(return).alignof == 0),
1097760c2415Smrg                 "Slicing by reference is impossible because of an alignment mistmatch. (See Phobos issue #15645.)");
1098760c2415Smrg 
1099760c2415Smrg             return *cast(typeof(return)*) &(field[from]);
1100760c2415Smrg         }
1101760c2415Smrg 
1102760c2415Smrg         ///
1103760c2415Smrg         static if (Specs.length == 0) @safe unittest
1104760c2415Smrg         {
1105760c2415Smrg             Tuple!(int, string, float, double) a;
1106760c2415Smrg             a[1] = "abc";
1107760c2415Smrg             a[2] = 4.5;
1108760c2415Smrg             auto s = a.slice!(1, 3);
1109760c2415Smrg             static assert(is(typeof(s) == Tuple!(string, float)));
1110760c2415Smrg             assert(s[0] == "abc" && s[1] == 4.5);
1111760c2415Smrg 
1112760c2415Smrg             // Phobos issue #15645
1113760c2415Smrg             Tuple!(int, short, bool, double) b;
1114760c2415Smrg             static assert(!__traits(compiles, b.slice!(2, 4)));
1115760c2415Smrg         }
1116760c2415Smrg 
1117760c2415Smrg         /**
1118760c2415Smrg             Creates a hash of this `Tuple`.
1119760c2415Smrg 
1120760c2415Smrg             Returns:
1121760c2415Smrg                 A `size_t` representing the hash of this `Tuple`.
1122760c2415Smrg          */
1123760c2415Smrg         size_t toHash() const nothrow @trusted
1124760c2415Smrg         {
1125760c2415Smrg             size_t h = 0;
1126760c2415Smrg             foreach (i, T; Types)
1127760c2415Smrg                 h += typeid(T).getHash(cast(const void*)&field[i]);
1128760c2415Smrg             return h;
1129760c2415Smrg         }
1130760c2415Smrg 
1131760c2415Smrg         ///
1132760c2415Smrg         template toString()
1133760c2415Smrg         {
1134760c2415Smrg             /**
1135760c2415Smrg              * Converts to string.
1136760c2415Smrg              *
1137760c2415Smrg              * Returns:
1138760c2415Smrg              *     The string representation of this `Tuple`.
1139760c2415Smrg              */
1140760c2415Smrg             string toString()() const
1141760c2415Smrg             {
1142760c2415Smrg                 import std.array : appender;
1143760c2415Smrg                 auto app = appender!string();
1144760c2415Smrg                 this.toString((const(char)[] chunk) => app ~= chunk);
1145760c2415Smrg                 return app.data;
1146760c2415Smrg             }
1147760c2415Smrg 
1148760c2415Smrg             import std.format : FormatSpec;
1149760c2415Smrg 
1150760c2415Smrg             /**
1151760c2415Smrg              * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`.
1152760c2415Smrg              *
1153760c2415Smrg              * $(TABLE2 Formats supported by Tuple,
1154760c2415Smrg              * $(THEAD Format, Description)
1155760c2415Smrg              * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.))
1156760c2415Smrg              * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`, so
1157760c2415Smrg              *      it may contain as many formats as the `Tuple` has fields.))
1158760c2415Smrg              * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format, that is applied
1159760c2415Smrg              *      on all fields of the `Tuple`. The inner format must be compatible to all
1160760c2415Smrg              *      of them.)))
1161760c2415Smrg              * ---
1162760c2415Smrg              *  Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ];
1163760c2415Smrg              *
1164760c2415Smrg              *  // Default format
1165760c2415Smrg              *  assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`);
1166760c2415Smrg              *
1167760c2415Smrg              *  // One Format for each individual component
1168760c2415Smrg              *  assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10))         == `0x1 v 1.0000 w 0xa`);
1169760c2415Smrg              *  assert(format(  "%#x v %.4f w %#x"  , tuple(1, 1.0, 10).expand)  == `0x1 v 1.0000 w 0xa`);
1170760c2415Smrg              *
1171760c2415Smrg              *  // One Format for all components
1172760c2415Smrg              *  assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`);
1173760c2415Smrg              *
1174760c2415Smrg              *  // Array of Tuples
1175760c2415Smrg              *  assert(format("%(%(f(%d) = %.1f%);  %)", tupList) == `f(1) = 1.0;  f(2) = 4.0;  f(3) = 9.0`);
1176760c2415Smrg              *
1177760c2415Smrg              *
1178760c2415Smrg              *  // Error: %( %) missing.
1179760c2415Smrg              *  assertThrown!FormatException(
1180760c2415Smrg              *      format("%d, %f", tuple(1, 2.0)) == `1, 2.0`
1181760c2415Smrg              *  );
1182760c2415Smrg              *
1183760c2415Smrg              *  // Error: %( %| %) missing.
1184760c2415Smrg              *  assertThrown!FormatException(
1185760c2415Smrg              *      format("%d", tuple(1, 2)) == `1, 2`
1186760c2415Smrg              *  );
1187760c2415Smrg              *
1188760c2415Smrg              *  // Error: %d inadequate for double.
1189760c2415Smrg              *  assertThrown!FormatException(
1190760c2415Smrg              *      format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0`
1191760c2415Smrg              *  );
1192760c2415Smrg              * ---
1193760c2415Smrg              */
1194760c2415Smrg             void toString(DG)(scope DG sink) const
1195760c2415Smrg             {
1196760c2415Smrg                 toString(sink, FormatSpec!char());
1197760c2415Smrg             }
1198760c2415Smrg 
1199760c2415Smrg             /// ditto
1200760c2415Smrg             void toString(DG, Char)(scope DG sink, FormatSpec!Char fmt) const
1201760c2415Smrg             {
1202760c2415Smrg                 import std.format : formatElement, formattedWrite, FormatException;
1203760c2415Smrg                 if (fmt.nested)
1204760c2415Smrg                 {
1205760c2415Smrg                     if (fmt.sep)
1206760c2415Smrg                     {
1207760c2415Smrg                         foreach (i, Type; Types)
1208760c2415Smrg                         {
1209760c2415Smrg                             static if (i > 0)
1210760c2415Smrg                             {
1211760c2415Smrg                                 sink(fmt.sep);
1212760c2415Smrg                             }
1213760c2415Smrg                             // TODO: Change this once formattedWrite() works for shared objects.
1214760c2415Smrg                             static if (is(Type == class) && is(Type == shared))
1215760c2415Smrg                             {
1216760c2415Smrg                                 sink(Type.stringof);
1217760c2415Smrg                             }
1218760c2415Smrg                             else
1219760c2415Smrg                             {
1220760c2415Smrg                                 formattedWrite(sink, fmt.nested, this.field[i]);
1221760c2415Smrg                             }
1222760c2415Smrg                         }
1223760c2415Smrg                     }
1224760c2415Smrg                     else
1225760c2415Smrg                     {
1226760c2415Smrg                         formattedWrite(sink, fmt.nested, staticMap!(sharedToString, this.expand));
1227760c2415Smrg                     }
1228760c2415Smrg                 }
1229760c2415Smrg                 else if (fmt.spec == 's')
1230760c2415Smrg                 {
1231760c2415Smrg                     enum header = Unqual!(typeof(this)).stringof ~ "(",
1232760c2415Smrg                          footer = ")",
1233760c2415Smrg                          separator = ", ";
1234760c2415Smrg                     sink(header);
1235760c2415Smrg                     foreach (i, Type; Types)
1236760c2415Smrg                     {
1237760c2415Smrg                         static if (i > 0)
1238760c2415Smrg                         {
1239760c2415Smrg                             sink(separator);
1240760c2415Smrg                         }
1241760c2415Smrg                         // TODO: Change this once formatElement() works for shared objects.
1242760c2415Smrg                         static if (is(Type == class) && is(Type == shared))
1243760c2415Smrg                         {
1244760c2415Smrg                             sink(Type.stringof);
1245760c2415Smrg                         }
1246760c2415Smrg                         else
1247760c2415Smrg                         {
1248760c2415Smrg                             FormatSpec!Char f;
1249760c2415Smrg                             formatElement(sink, field[i], f);
1250760c2415Smrg                         }
1251760c2415Smrg                     }
1252760c2415Smrg                     sink(footer);
1253760c2415Smrg                 }
1254760c2415Smrg                 else
1255760c2415Smrg                 {
1256760c2415Smrg                     throw new FormatException(
1257760c2415Smrg                         "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~
1258760c2415Smrg                             Unqual!(typeof(this)).stringof ~ "', not '%" ~ fmt.spec ~ "'.");
1259760c2415Smrg                 }
1260760c2415Smrg             }
1261760c2415Smrg         }
1262760c2415Smrg     }
1263760c2415Smrg }
1264760c2415Smrg 
1265760c2415Smrg ///
1266760c2415Smrg @safe unittest
1267760c2415Smrg {
1268760c2415Smrg     Tuple!(int, int) point;
1269760c2415Smrg     // assign coordinates
1270760c2415Smrg     point[0] = 5;
1271760c2415Smrg     point[1] = 6;
1272760c2415Smrg     // read coordinates
1273760c2415Smrg     auto x = point[0];
1274760c2415Smrg     auto y = point[1];
1275760c2415Smrg }
1276760c2415Smrg 
1277760c2415Smrg /**
1278760c2415Smrg     `Tuple` members can be named. It is legal to mix named and unnamed
1279760c2415Smrg     members. The method above is still applicable to all fields.
1280760c2415Smrg  */
1281760c2415Smrg @safe unittest
1282760c2415Smrg {
1283760c2415Smrg     alias Entry = Tuple!(int, "index", string, "value");
1284760c2415Smrg     Entry e;
1285760c2415Smrg     e.index = 4;
1286760c2415Smrg     e.value = "Hello";
1287760c2415Smrg     assert(e[1] == "Hello");
1288760c2415Smrg     assert(e[0] == 4);
1289760c2415Smrg }
1290760c2415Smrg 
1291760c2415Smrg /**
1292760c2415Smrg     A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed
1293760c2415Smrg     fields, i.e. each naming imparts a separate type for the `Tuple`. Two
1294760c2415Smrg     `Tuple`s differing in naming only are still distinct, even though they
1295760c2415Smrg     might have the same structure.
1296760c2415Smrg  */
1297760c2415Smrg @safe unittest
1298760c2415Smrg {
1299760c2415Smrg     Tuple!(int, "x", int, "y") point1;
1300760c2415Smrg     Tuple!(int, int) point2;
1301760c2415Smrg     assert(!is(typeof(point1) == typeof(point2)));
1302760c2415Smrg }
1303760c2415Smrg 
1304760c2415Smrg /**
1305760c2415Smrg     Creates a copy of a $(LREF Tuple) with its fields in _reverse order.
1306760c2415Smrg 
1307760c2415Smrg     Params:
1308760c2415Smrg         t = The `Tuple` to copy.
1309760c2415Smrg 
1310760c2415Smrg     Returns:
1311760c2415Smrg         A new `Tuple`.
1312760c2415Smrg  */
1313760c2415Smrg auto reverse(T)(T t)
1314760c2415Smrg     if (isTuple!T)
1315760c2415Smrg {
1316760c2415Smrg     import std.meta : Reverse;
1317760c2415Smrg     // @@@BUG@@@ Cannot be an internal function due to forward reference issues.
1318760c2415Smrg 
1319760c2415Smrg     // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple
1320760c2415Smrg     // return tuple(Reverse!(t.expand));
1321760c2415Smrg 
1322760c2415Smrg     ReverseTupleType!T result;
1323760c2415Smrg     auto tup = t.expand;
1324760c2415Smrg     result.expand = Reverse!tup;
1325760c2415Smrg     return result;
1326760c2415Smrg }
1327760c2415Smrg 
1328760c2415Smrg ///
1329760c2415Smrg @safe unittest
1330760c2415Smrg {
1331760c2415Smrg     auto tup = tuple(1, "2");
1332760c2415Smrg     assert(tup.reverse == tuple("2", 1));
1333760c2415Smrg }
1334760c2415Smrg 
1335760c2415Smrg /* Get a Tuple type with the reverse specification of Tuple T. */
1336760c2415Smrg private template ReverseTupleType(T)
1337760c2415Smrg     if (isTuple!T)
1338760c2415Smrg {
1339760c2415Smrg     static if (is(T : Tuple!A, A...))
1340760c2415Smrg         alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A);
1341760c2415Smrg }
1342760c2415Smrg 
1343760c2415Smrg /* Reverse the Specs of a Tuple. */
1344760c2415Smrg private template ReverseTupleSpecs(T...)
1345760c2415Smrg {
1346760c2415Smrg     static if (T.length > 1)
1347760c2415Smrg     {
1348760c2415Smrg         static if (is(typeof(T[$-1]) : string))
1349760c2415Smrg         {
1350760c2415Smrg             alias ReverseTupleSpecs = AliasSeq!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2]));
1351760c2415Smrg         }
1352760c2415Smrg         else
1353760c2415Smrg         {
1354760c2415Smrg             alias ReverseTupleSpecs = AliasSeq!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1]));
1355760c2415Smrg         }
1356760c2415Smrg     }
1357760c2415Smrg     else
1358760c2415Smrg     {
1359760c2415Smrg         alias ReverseTupleSpecs = T;
1360760c2415Smrg     }
1361760c2415Smrg }
1362760c2415Smrg 
1363760c2415Smrg // ensure that internal Tuple unittests are compiled
1364760c2415Smrg @safe unittest
1365760c2415Smrg {
1366760c2415Smrg     Tuple!() t;
1367760c2415Smrg }
1368760c2415Smrg 
1369760c2415Smrg @safe unittest
1370760c2415Smrg {
1371760c2415Smrg     import std.conv;
1372760c2415Smrg     {
1373760c2415Smrg         Tuple!(int, "a", int, "b") nosh;
1374760c2415Smrg         static assert(nosh.length == 2);
1375760c2415Smrg         nosh.a = 5;
1376760c2415Smrg         nosh.b = 6;
1377760c2415Smrg         assert(nosh.a == 5);
1378760c2415Smrg         assert(nosh.b == 6);
1379760c2415Smrg     }
1380760c2415Smrg     {
1381760c2415Smrg         Tuple!(short, double) b;
1382760c2415Smrg         static assert(b.length == 2);
1383760c2415Smrg         b[1] = 5;
1384760c2415Smrg         auto a = Tuple!(int, real)(b);
1385760c2415Smrg         assert(a[0] == 0 && a[1] == 5);
1386760c2415Smrg         a = Tuple!(int, real)(1, 2);
1387760c2415Smrg         assert(a[0] == 1 && a[1] == 2);
1388760c2415Smrg         auto c = Tuple!(int, "a", double, "b")(a);
1389760c2415Smrg         assert(c[0] == 1 && c[1] == 2);
1390760c2415Smrg     }
1391760c2415Smrg     {
1392760c2415Smrg         Tuple!(int, real) nosh;
1393760c2415Smrg         nosh[0] = 5;
1394760c2415Smrg         nosh[1] = 0;
1395760c2415Smrg         assert(nosh[0] == 5 && nosh[1] == 0);
1396760c2415Smrg         assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string);
1397760c2415Smrg         Tuple!(int, int) yessh;
1398760c2415Smrg         nosh = yessh;
1399760c2415Smrg     }
1400760c2415Smrg     {
1401760c2415Smrg         class A {}
1402760c2415Smrg         Tuple!(int, shared A) nosh;
1403760c2415Smrg         nosh[0] = 5;
1404760c2415Smrg         assert(nosh[0] == 5 && nosh[1] is null);
1405760c2415Smrg         assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))");
1406760c2415Smrg     }
1407760c2415Smrg     {
1408760c2415Smrg         Tuple!(int, string) t;
1409760c2415Smrg         t[0] = 10;
1410760c2415Smrg         t[1] = "str";
1411760c2415Smrg         assert(t[0] == 10 && t[1] == "str");
1412760c2415Smrg         assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string);
1413760c2415Smrg     }
1414760c2415Smrg     {
1415760c2415Smrg         Tuple!(int, "a", double, "b") x;
1416760c2415Smrg         static assert(x.a.offsetof == x[0].offsetof);
1417760c2415Smrg         static assert(x.b.offsetof == x[1].offsetof);
1418760c2415Smrg         x.b = 4.5;
1419760c2415Smrg         x.a = 5;
1420760c2415Smrg         assert(x[0] == 5 && x[1] == 4.5);
1421760c2415Smrg         assert(x.a == 5 && x.b == 4.5);
1422760c2415Smrg     }
1423760c2415Smrg     // indexing
1424760c2415Smrg     {
1425760c2415Smrg         Tuple!(int, real) t;
1426760c2415Smrg         static assert(is(typeof(t[0]) == int));
1427760c2415Smrg         static assert(is(typeof(t[1]) == real));
1428760c2415Smrg         int* p0 = &t[0];
1429760c2415Smrg         real* p1 = &t[1];
1430760c2415Smrg         t[0] = 10;
1431760c2415Smrg         t[1] = -200.0L;
1432760c2415Smrg         assert(*p0 == t[0]);
1433760c2415Smrg         assert(*p1 == t[1]);
1434760c2415Smrg     }
1435760c2415Smrg     // slicing
1436760c2415Smrg     {
1437760c2415Smrg         Tuple!(int, "x", real, "y", double, "z", string) t;
1438760c2415Smrg         t[0] = 10;
1439760c2415Smrg         t[1] = 11;
1440760c2415Smrg         t[2] = 12;
1441760c2415Smrg         t[3] = "abc";
1442760c2415Smrg         auto a = t.slice!(0, 3);
1443760c2415Smrg         assert(a.length == 3);
1444760c2415Smrg         assert(a.x == t.x);
1445760c2415Smrg         assert(a.y == t.y);
1446760c2415Smrg         assert(a.z == t.z);
1447760c2415Smrg         auto b = t.slice!(2, 4);
1448760c2415Smrg         assert(b.length == 2);
1449760c2415Smrg         assert(b.z == t.z);
1450760c2415Smrg         assert(b[1] == t[3]);
1451760c2415Smrg     }
1452760c2415Smrg     // nesting
1453760c2415Smrg     {
1454760c2415Smrg         Tuple!(Tuple!(int, real), Tuple!(string, "s")) t;
1455760c2415Smrg         static assert(is(typeof(t[0]) == Tuple!(int, real)));
1456760c2415Smrg         static assert(is(typeof(t[1]) == Tuple!(string, "s")));
1457760c2415Smrg         static assert(is(typeof(t[0][0]) == int));
1458760c2415Smrg         static assert(is(typeof(t[0][1]) == real));
1459760c2415Smrg         static assert(is(typeof(t[1].s) == string));
1460760c2415Smrg         t[0] = tuple(10, 20.0L);
1461760c2415Smrg         t[1].s = "abc";
1462760c2415Smrg         assert(t[0][0] == 10);
1463760c2415Smrg         assert(t[0][1] == 20.0L);
1464760c2415Smrg         assert(t[1].s == "abc");
1465760c2415Smrg     }
1466760c2415Smrg     // non-POD
1467760c2415Smrg     {
1468760c2415Smrg         static struct S
1469760c2415Smrg         {
1470760c2415Smrg             int count;
1471760c2415Smrg             this(this) { ++count; }
1472760c2415Smrg             ~this() { --count; }
1473760c2415Smrg             void opAssign(S rhs) { count = rhs.count; }
1474760c2415Smrg         }
1475760c2415Smrg         Tuple!(S, S) ss;
1476760c2415Smrg         Tuple!(S, S) ssCopy = ss;
1477760c2415Smrg         assert(ssCopy[0].count == 1);
1478760c2415Smrg         assert(ssCopy[1].count == 1);
1479760c2415Smrg         ssCopy[1] = ssCopy[0];
1480760c2415Smrg         assert(ssCopy[1].count == 2);
1481760c2415Smrg     }
1482760c2415Smrg     // bug 2800
1483760c2415Smrg     {
1484760c2415Smrg         static struct R
1485760c2415Smrg         {
1486760c2415Smrg             Tuple!(int, int) _front;
1487760c2415Smrg             @property ref Tuple!(int, int) front() return { return _front;  }
1488760c2415Smrg             @property bool empty() { return _front[0] >= 10; }
1489760c2415Smrg             void popFront() { ++_front[0]; }
1490760c2415Smrg         }
1491760c2415Smrg         foreach (a; R())
1492760c2415Smrg         {
1493760c2415Smrg             static assert(is(typeof(a) == Tuple!(int, int)));
1494760c2415Smrg             assert(0 <= a[0] && a[0] < 10);
1495760c2415Smrg             assert(a[1] == 0);
1496760c2415Smrg         }
1497760c2415Smrg     }
1498760c2415Smrg     // Construction with compatible elements
1499760c2415Smrg     {
1500760c2415Smrg         auto t1 = Tuple!(int, double)(1, 1);
1501760c2415Smrg 
1502760c2415Smrg         // 8702
1503760c2415Smrg         auto t8702a = tuple(tuple(1));
1504760c2415Smrg         auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1));
1505760c2415Smrg     }
1506760c2415Smrg     // Construction with compatible tuple
1507760c2415Smrg     {
1508760c2415Smrg         Tuple!(int, int) x;
1509760c2415Smrg         x[0] = 10;
1510760c2415Smrg         x[1] = 20;
1511760c2415Smrg         Tuple!(int, "a", double, "b") y = x;
1512760c2415Smrg         assert(y.a == 10);
1513760c2415Smrg         assert(y.b == 20);
1514760c2415Smrg         // incompatible
1515760c2415Smrg         static assert(!__traits(compiles, Tuple!(int, int)(y)));
1516760c2415Smrg     }
1517760c2415Smrg     // 6275
1518760c2415Smrg     {
1519760c2415Smrg         const int x = 1;
1520760c2415Smrg         auto t1 = tuple(x);
1521760c2415Smrg         alias T = Tuple!(const(int));
1522760c2415Smrg         auto t2 = T(1);
1523760c2415Smrg     }
1524760c2415Smrg     // 9431
1525760c2415Smrg     {
1526760c2415Smrg         alias T = Tuple!(int[1][]);
1527760c2415Smrg         auto t = T([[10]]);
1528760c2415Smrg     }
1529760c2415Smrg     // 7666
1530760c2415Smrg     {
1531760c2415Smrg         auto tup = tuple(1, "2");
1532760c2415Smrg         assert(tup.reverse == tuple("2", 1));
1533760c2415Smrg     }
1534760c2415Smrg     {
1535760c2415Smrg         Tuple!(int, "x", string, "y") tup = tuple(1, "2");
1536760c2415Smrg         auto rev = tup.reverse;
1537760c2415Smrg         assert(rev == tuple("2", 1));
1538760c2415Smrg         assert(rev.x == 1 && rev.y == "2");
1539760c2415Smrg     }
1540760c2415Smrg     {
1541760c2415Smrg         Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup;
1542760c2415Smrg         tup = tuple('a', 'b', 3, "4", 'c', cast(byte) 0x0D, 0.00);
1543760c2415Smrg         auto rev = tup.reverse;
1544760c2415Smrg         assert(rev == tuple(0.00, cast(byte) 0x0D, 'c', "4", 3, 'b', 'a'));
1545760c2415Smrg         assert(rev.x == 3 && rev.y == "4");
1546760c2415Smrg     }
1547760c2415Smrg }
1548760c2415Smrg @safe unittest
1549760c2415Smrg {
1550760c2415Smrg     // opEquals
1551760c2415Smrg     {
1552760c2415Smrg         struct Equ1 { bool opEquals(Equ1) { return true; } }
1553760c2415Smrg         auto  tm1 = tuple(Equ1.init);
1554760c2415Smrg         const tc1 = tuple(Equ1.init);
1555760c2415Smrg         static assert( is(typeof(tm1 == tm1)));
1556760c2415Smrg         static assert(!is(typeof(tm1 == tc1)));
1557760c2415Smrg         static assert(!is(typeof(tc1 == tm1)));
1558760c2415Smrg         static assert(!is(typeof(tc1 == tc1)));
1559760c2415Smrg 
1560760c2415Smrg         struct Equ2 { bool opEquals(const Equ2) const { return true; } }
1561760c2415Smrg         auto  tm2 = tuple(Equ2.init);
1562760c2415Smrg         const tc2 = tuple(Equ2.init);
1563760c2415Smrg         static assert( is(typeof(tm2 == tm2)));
1564760c2415Smrg         static assert( is(typeof(tm2 == tc2)));
1565760c2415Smrg         static assert( is(typeof(tc2 == tm2)));
1566760c2415Smrg         static assert( is(typeof(tc2 == tc2)));
1567760c2415Smrg 
1568760c2415Smrg         struct Equ3 { bool opEquals(T)(T) { return true; } }
1569760c2415Smrg         auto  tm3 = tuple(Equ3.init);           // bugzilla 8686
1570760c2415Smrg         const tc3 = tuple(Equ3.init);
1571760c2415Smrg         static assert( is(typeof(tm3 == tm3)));
1572760c2415Smrg         static assert( is(typeof(tm3 == tc3)));
1573760c2415Smrg         static assert(!is(typeof(tc3 == tm3)));
1574760c2415Smrg         static assert(!is(typeof(tc3 == tc3)));
1575760c2415Smrg 
1576760c2415Smrg         struct Equ4 { bool opEquals(T)(T) const { return true; } }
1577760c2415Smrg         auto  tm4 = tuple(Equ4.init);
1578760c2415Smrg         const tc4 = tuple(Equ4.init);
1579760c2415Smrg         static assert( is(typeof(tm4 == tm4)));
1580760c2415Smrg         static assert( is(typeof(tm4 == tc4)));
1581760c2415Smrg         static assert( is(typeof(tc4 == tm4)));
1582760c2415Smrg         static assert( is(typeof(tc4 == tc4)));
1583760c2415Smrg     }
1584760c2415Smrg     // opCmp
1585760c2415Smrg     {
1586760c2415Smrg         struct Cmp1 { int opCmp(Cmp1) { return 0; } }
1587760c2415Smrg         auto  tm1 = tuple(Cmp1.init);
1588760c2415Smrg         const tc1 = tuple(Cmp1.init);
1589760c2415Smrg         static assert( is(typeof(tm1 < tm1)));
1590760c2415Smrg         static assert(!is(typeof(tm1 < tc1)));
1591760c2415Smrg         static assert(!is(typeof(tc1 < tm1)));
1592760c2415Smrg         static assert(!is(typeof(tc1 < tc1)));
1593760c2415Smrg 
1594760c2415Smrg         struct Cmp2 { int opCmp(const Cmp2) const { return 0; } }
1595760c2415Smrg         auto  tm2 = tuple(Cmp2.init);
1596760c2415Smrg         const tc2 = tuple(Cmp2.init);
1597760c2415Smrg         static assert( is(typeof(tm2 < tm2)));
1598760c2415Smrg         static assert( is(typeof(tm2 < tc2)));
1599760c2415Smrg         static assert( is(typeof(tc2 < tm2)));
1600760c2415Smrg         static assert( is(typeof(tc2 < tc2)));
1601760c2415Smrg 
1602760c2415Smrg         struct Cmp3 { int opCmp(T)(T) { return 0; } }
1603760c2415Smrg         auto  tm3 = tuple(Cmp3.init);
1604760c2415Smrg         const tc3 = tuple(Cmp3.init);
1605760c2415Smrg         static assert( is(typeof(tm3 < tm3)));
1606760c2415Smrg         static assert( is(typeof(tm3 < tc3)));
1607760c2415Smrg         static assert(!is(typeof(tc3 < tm3)));
1608760c2415Smrg         static assert(!is(typeof(tc3 < tc3)));
1609760c2415Smrg 
1610760c2415Smrg         struct Cmp4 { int opCmp(T)(T) const { return 0; } }
1611760c2415Smrg         auto  tm4 = tuple(Cmp4.init);
1612760c2415Smrg         const tc4 = tuple(Cmp4.init);
1613760c2415Smrg         static assert( is(typeof(tm4 < tm4)));
1614760c2415Smrg         static assert( is(typeof(tm4 < tc4)));
1615760c2415Smrg         static assert( is(typeof(tc4 < tm4)));
1616760c2415Smrg         static assert( is(typeof(tc4 < tc4)));
1617760c2415Smrg     }
1618760c2415Smrg     // Bugzilla 14890
1619760c2415Smrg     static void test14890(inout int[] dummy)
1620760c2415Smrg     {
1621760c2415Smrg         alias V = Tuple!(int, int);
1622760c2415Smrg 
1623760c2415Smrg                     V mv;
1624760c2415Smrg               const V cv;
1625760c2415Smrg           immutable V iv;
1626760c2415Smrg               inout V wv;   // OK <- NG
1627760c2415Smrg         inout const V wcv;  // OK <- NG
1628760c2415Smrg 
1629760c2415Smrg         foreach (v1; AliasSeq!(mv, cv, iv, wv, wcv))
1630760c2415Smrg         foreach (v2; AliasSeq!(mv, cv, iv, wv, wcv))
1631760c2415Smrg         {
1632760c2415Smrg             assert(!(v1 < v2));
1633760c2415Smrg         }
1634760c2415Smrg     }
1635760c2415Smrg     {
1636760c2415Smrg         int[2] ints = [ 1, 2 ];
1637760c2415Smrg         Tuple!(int, int) t = ints;
1638760c2415Smrg         assert(t[0] == 1 && t[1] == 2);
1639760c2415Smrg         Tuple!(long, uint) t2 = ints;
1640760c2415Smrg         assert(t2[0] == 1 && t2[1] == 2);
1641760c2415Smrg     }
1642760c2415Smrg }
1643760c2415Smrg @safe unittest
1644760c2415Smrg {
1645760c2415Smrg     auto t1 = Tuple!(int, "x", string, "y")(1, "a");
1646760c2415Smrg     assert(t1.x == 1);
1647760c2415Smrg     assert(t1.y == "a");
1648760c2415Smrg     void foo(Tuple!(int, string) t2) {}
1649760c2415Smrg     foo(t1);
1650760c2415Smrg 
1651760c2415Smrg     Tuple!(int, int)[] arr;
1652760c2415Smrg     arr ~= tuple(10, 20); // OK
1653760c2415Smrg     arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK
1654760c2415Smrg 
1655760c2415Smrg     static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) ==
1656760c2415Smrg                      typeof(Tuple!(int,      string     ).tupleof)));
1657760c2415Smrg }
1658760c2415Smrg @safe unittest
1659760c2415Smrg {
1660760c2415Smrg     // Bugzilla 10686
1661760c2415Smrg     immutable Tuple!(int) t1;
1662760c2415Smrg     auto r1 = t1[0]; // OK
1663760c2415Smrg     immutable Tuple!(int, "x") t2;
1664760c2415Smrg     auto r2 = t2[0]; // error
1665760c2415Smrg }
1666760c2415Smrg @safe unittest
1667760c2415Smrg {
1668760c2415Smrg     import std.exception : assertCTFEable;
1669760c2415Smrg 
1670760c2415Smrg     // Bugzilla 10218
1671760c2415Smrg     assertCTFEable!(
1672760c2415Smrg     {
1673760c2415Smrg         auto t = tuple(1);
1674760c2415Smrg         t = tuple(2);   // assignment
1675760c2415Smrg     });
1676760c2415Smrg }
1677760c2415Smrg @safe unittest
1678760c2415Smrg {
1679760c2415Smrg     class Foo{}
1680760c2415Smrg     Tuple!(immutable(Foo)[]) a;
1681760c2415Smrg }
1682760c2415Smrg 
1683760c2415Smrg @safe unittest
1684760c2415Smrg {
1685760c2415Smrg     //Test non-assignable
1686760c2415Smrg     static struct S
1687760c2415Smrg     {
1688760c2415Smrg         int* p;
1689760c2415Smrg     }
1690760c2415Smrg     alias IS = immutable S;
1691760c2415Smrg     static assert(!isAssignable!IS);
1692760c2415Smrg 
1693760c2415Smrg     auto s = IS.init;
1694760c2415Smrg 
1695760c2415Smrg     alias TIS = Tuple!IS;
1696760c2415Smrg     TIS a = tuple(s);
1697760c2415Smrg     TIS b = a;
1698760c2415Smrg 
1699760c2415Smrg     alias TISIS = Tuple!(IS, IS);
1700760c2415Smrg     TISIS d = tuple(s, s);
1701760c2415Smrg     IS[2] ss;
1702760c2415Smrg     TISIS e = TISIS(ss);
1703760c2415Smrg }
1704760c2415Smrg 
1705760c2415Smrg // Bugzilla #9819
1706760c2415Smrg @safe unittest
1707760c2415Smrg {
1708760c2415Smrg     alias T = Tuple!(int, "x", double, "foo");
1709760c2415Smrg     static assert(T.fieldNames[0] == "x");
1710760c2415Smrg     static assert(T.fieldNames[1] == "foo");
1711760c2415Smrg 
1712760c2415Smrg     alias Fields = Tuple!(int, "id", string, float);
1713760c2415Smrg     static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
1714760c2415Smrg }
1715760c2415Smrg 
1716760c2415Smrg // Bugzilla 13837
1717760c2415Smrg @safe unittest
1718760c2415Smrg {
1719760c2415Smrg     // New behaviour, named arguments.
1720760c2415Smrg     static assert(is(
1721760c2415Smrg         typeof(tuple!("x")(1)) == Tuple!(int, "x")));
1722760c2415Smrg     static assert(is(
1723760c2415Smrg         typeof(tuple!("x")(1.0)) == Tuple!(double, "x")));
1724760c2415Smrg     static assert(is(
1725760c2415Smrg         typeof(tuple!("x")("foo")) == Tuple!(string, "x")));
1726760c2415Smrg     static assert(is(
1727760c2415Smrg         typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y")));
1728760c2415Smrg 
1729760c2415Smrg     auto a = tuple!("a", "b", "c")("1", 2, 3.0f);
1730760c2415Smrg     static assert(is(typeof(a.a) == string));
1731760c2415Smrg     static assert(is(typeof(a.b) == int));
1732760c2415Smrg     static assert(is(typeof(a.c) == float));
1733760c2415Smrg 
1734760c2415Smrg     // Old behaviour, but with explicit type parameters.
1735760c2415Smrg     static assert(is(
1736760c2415Smrg         typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double)));
1737760c2415Smrg     static assert(is(
1738760c2415Smrg         typeof(tuple!(const int)(1)) == Tuple!(const int)));
1739760c2415Smrg     static assert(is(
1740760c2415Smrg         typeof(tuple()) == Tuple!()));
1741760c2415Smrg 
1742760c2415Smrg     // Nonsensical behaviour
1743760c2415Smrg     static assert(!__traits(compiles, tuple!(1)(2)));
1744760c2415Smrg     static assert(!__traits(compiles, tuple!("x")(1, 2)));
1745760c2415Smrg     static assert(!__traits(compiles, tuple!("x", "y")(1)));
1746760c2415Smrg     static assert(!__traits(compiles, tuple!("x")()));
1747760c2415Smrg     static assert(!__traits(compiles, tuple!("x", int)(2)));
1748760c2415Smrg }
1749760c2415Smrg 
1750760c2415Smrg @safe unittest
1751760c2415Smrg {
1752760c2415Smrg     class C {}
1753760c2415Smrg     Tuple!(Rebindable!(const C)) a;
1754760c2415Smrg     Tuple!(const C) b;
1755760c2415Smrg     a = b;
1756760c2415Smrg }
1757760c2415Smrg 
1758760c2415Smrg @nogc @safe unittest
1759760c2415Smrg {
1760760c2415Smrg     alias T = Tuple!(string, "s");
1761760c2415Smrg     T x;
1762760c2415Smrg     x = T.init;
1763760c2415Smrg }
1764760c2415Smrg 
1765760c2415Smrg @safe unittest
1766760c2415Smrg {
1767760c2415Smrg     import std.format : format, FormatException;
1768760c2415Smrg     import std.exception : assertThrown;
1769760c2415Smrg 
1770760c2415Smrg     // enum tupStr = tuple(1, 1.0).toString; // toString is *impure*.
1771760c2415Smrg     //static assert(tupStr == `Tuple!(int, double)(1, 1)`);
1772760c2415Smrg 
1773760c2415Smrg     Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ];
1774760c2415Smrg 
1775760c2415Smrg     // Default format
1776760c2415Smrg     assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`);
1777760c2415Smrg 
1778760c2415Smrg     // One Format for each individual component
1779760c2415Smrg     assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10))         == `0x1 v 1.0000 w 0xa`);
1780760c2415Smrg     assert(format(  "%#x v %.4f w %#x"  , tuple(1, 1.0, 10).expand)  == `0x1 v 1.0000 w 0xa`);
1781760c2415Smrg 
1782760c2415Smrg     // One Format for all components
1783760c2415Smrg     assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`);
1784760c2415Smrg 
1785760c2415Smrg     // Array of Tuples
1786760c2415Smrg     assert(format("%(%(f(%d) = %.1f%);  %)", tupList) == `f(1) = 1.0;  f(2) = 4.0;  f(3) = 9.0`);
1787760c2415Smrg 
1788760c2415Smrg 
1789760c2415Smrg     // Error: %( %) missing.
1790760c2415Smrg     assertThrown!FormatException(
1791760c2415Smrg         format("%d, %f", tuple(1, 2.0)) == `1, 2.0`
1792760c2415Smrg     );
1793760c2415Smrg 
1794760c2415Smrg     // Error: %( %| %) missing.
1795760c2415Smrg     assertThrown!FormatException(
1796760c2415Smrg         format("%d", tuple(1, 2)) == `1, 2`
1797760c2415Smrg     );
1798760c2415Smrg 
1799760c2415Smrg     // Error: %d inadequate for double
1800760c2415Smrg     assertThrown!FormatException(
1801760c2415Smrg         format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0`
1802760c2415Smrg     );
1803760c2415Smrg }
1804760c2415Smrg 
1805760c2415Smrg /**
1806760c2415Smrg     Constructs a $(LREF Tuple) object instantiated and initialized according to
1807760c2415Smrg     the given arguments.
1808760c2415Smrg 
1809760c2415Smrg     Params:
1810760c2415Smrg         Names = An optional list of strings naming each successive field of the `Tuple`.
1811760c2415Smrg                 Each name matches up with the corresponding field given by `Args`.
1812760c2415Smrg                 A name does not have to be provided for every field, but as
1813760c2415Smrg                 the names must proceed in order, it is not possible to skip
1814760c2415Smrg                 one field and name the next after it.
1815760c2415Smrg */
1816760c2415Smrg template tuple(Names...)
1817760c2415Smrg {
1818760c2415Smrg     /**
1819760c2415Smrg     Params:
1820760c2415Smrg         args = Values to initialize the `Tuple` with. The `Tuple`'s type will
1821760c2415Smrg                be inferred from the types of the values given.
1822760c2415Smrg 
1823760c2415Smrg     Returns:
1824760c2415Smrg         A new `Tuple` with its type inferred from the arguments given.
1825760c2415Smrg      */
1826760c2415Smrg     auto tuple(Args...)(Args args)
1827760c2415Smrg     {
1828760c2415Smrg         static if (Names.length == 0)
1829760c2415Smrg         {
1830760c2415Smrg             // No specified names, just infer types from Args...
1831760c2415Smrg             return Tuple!Args(args);
1832760c2415Smrg         }
1833760c2415Smrg         else static if (!is(typeof(Names[0]) : string))
1834760c2415Smrg         {
1835760c2415Smrg             // Names[0] isn't a string, must be explicit types.
1836760c2415Smrg             return Tuple!Names(args);
1837760c2415Smrg         }
1838760c2415Smrg         else
1839760c2415Smrg         {
1840760c2415Smrg             // Names[0] is a string, so must be specifying names.
1841760c2415Smrg             static assert(Names.length == Args.length,
1842760c2415Smrg                 "Insufficient number of names given.");
1843760c2415Smrg 
1844760c2415Smrg             // Interleave(a, b).and(c, d) == (a, c, b, d)
1845760c2415Smrg             // This is to get the interleaving of types and names for Tuple
1846760c2415Smrg             // e.g. Tuple!(int, "x", string, "y")
1847760c2415Smrg             template Interleave(A...)
1848760c2415Smrg             {
1849760c2415Smrg                 template and(B...) if (B.length == 1)
1850760c2415Smrg                 {
1851760c2415Smrg                     alias and = AliasSeq!(A[0], B[0]);
1852760c2415Smrg                 }
1853760c2415Smrg 
1854760c2415Smrg                 template and(B...) if (B.length != 1)
1855760c2415Smrg                 {
1856760c2415Smrg                     alias and = AliasSeq!(A[0], B[0],
1857760c2415Smrg                         Interleave!(A[1..$]).and!(B[1..$]));
1858760c2415Smrg                 }
1859760c2415Smrg             }
1860760c2415Smrg             return Tuple!(Interleave!(Args).and!(Names))(args);
1861760c2415Smrg         }
1862760c2415Smrg     }
1863760c2415Smrg }
1864760c2415Smrg 
1865760c2415Smrg ///
1866760c2415Smrg @safe unittest
1867760c2415Smrg {
1868760c2415Smrg     auto value = tuple(5, 6.7, "hello");
1869760c2415Smrg     assert(value[0] == 5);
1870760c2415Smrg     assert(value[1] == 6.7);
1871760c2415Smrg     assert(value[2] == "hello");
1872760c2415Smrg 
1873760c2415Smrg     // Field names can be provided.
1874760c2415Smrg     auto entry = tuple!("index", "value")(4, "Hello");
1875760c2415Smrg     assert(entry.index == 4);
1876760c2415Smrg     assert(entry.value == "Hello");
1877760c2415Smrg }
1878760c2415Smrg 
1879760c2415Smrg /**
1880760c2415Smrg     Returns $(D true) if and only if $(D T) is an instance of $(D std.typecons.Tuple).
1881760c2415Smrg 
1882760c2415Smrg     Params:
1883760c2415Smrg         T = The type to check.
1884760c2415Smrg 
1885760c2415Smrg     Returns:
1886760c2415Smrg         true if `T` is a `Tuple` type, false otherwise.
1887760c2415Smrg  */
1888760c2415Smrg enum isTuple(T) = __traits(compiles,
1889760c2415Smrg                            {
1890760c2415Smrg                                void f(Specs...)(Tuple!Specs tup) {}
1891760c2415Smrg                                f(T.init);
1892760c2415Smrg                            } );
1893760c2415Smrg 
1894760c2415Smrg ///
1895760c2415Smrg @safe unittest
1896760c2415Smrg {
1897760c2415Smrg     static assert(isTuple!(Tuple!()));
1898760c2415Smrg     static assert(isTuple!(Tuple!(int)));
1899760c2415Smrg     static assert(isTuple!(Tuple!(int, real, string)));
1900760c2415Smrg     static assert(isTuple!(Tuple!(int, "x", real, "y")));
1901760c2415Smrg     static assert(isTuple!(Tuple!(int, Tuple!(real), string)));
1902760c2415Smrg }
1903760c2415Smrg 
1904760c2415Smrg @safe unittest
1905760c2415Smrg {
1906760c2415Smrg     static assert(isTuple!(const Tuple!(int)));
1907760c2415Smrg     static assert(isTuple!(immutable Tuple!(int)));
1908760c2415Smrg 
1909760c2415Smrg     static assert(!isTuple!(int));
1910760c2415Smrg     static assert(!isTuple!(const int));
1911760c2415Smrg 
1912760c2415Smrg     struct S {}
1913760c2415Smrg     static assert(!isTuple!(S));
1914760c2415Smrg }
1915760c2415Smrg 
1916760c2415Smrg // used by both Rebindable and UnqualRef
1917760c2415Smrg private mixin template RebindableCommon(T, U, alias This)
1918760c2415Smrg     if (is(T == class) || is(T == interface) || isAssociativeArray!T)
1919760c2415Smrg {
1920760c2415Smrg     private union
1921760c2415Smrg     {
1922760c2415Smrg         T original;
1923760c2415Smrg         U stripped;
1924760c2415Smrg     }
1925760c2415Smrg 
1926760c2415Smrg     @trusted pure nothrow @nogc
1927760c2415Smrg     {
1928760c2415Smrg         void opAssign(T another)
1929760c2415Smrg         {
1930760c2415Smrg             stripped = cast(U) another;
1931760c2415Smrg         }
1932760c2415Smrg 
1933760c2415Smrg         void opAssign(typeof(this) another)
1934760c2415Smrg         {
1935760c2415Smrg             stripped = another.stripped;
1936760c2415Smrg         }
1937760c2415Smrg 
1938760c2415Smrg         static if (is(T == const U) && is(T == const shared U))
1939760c2415Smrg         {
1940760c2415Smrg             // safely assign immutable to const / const shared
1941760c2415Smrg             void opAssign(This!(immutable U) another)
1942760c2415Smrg             {
1943760c2415Smrg                 stripped = another.stripped;
1944760c2415Smrg             }
1945760c2415Smrg         }
1946760c2415Smrg 
1947760c2415Smrg         this(T initializer)
1948760c2415Smrg         {
1949760c2415Smrg             opAssign(initializer);
1950760c2415Smrg         }
1951760c2415Smrg 
1952760c2415Smrg         @property inout(T) get() inout
1953760c2415Smrg         {
1954760c2415Smrg             return original;
1955760c2415Smrg         }
1956760c2415Smrg     }
1957760c2415Smrg 
1958760c2415Smrg     alias get this;
1959760c2415Smrg }
1960760c2415Smrg 
1961760c2415Smrg /**
1962760c2415Smrg $(D Rebindable!(T)) is a simple, efficient wrapper that behaves just
1963760c2415Smrg like an object of type $(D T), except that you can reassign it to
1964760c2415Smrg refer to another object. For completeness, $(D Rebindable!(T)) aliases
1965760c2415Smrg itself away to $(D T) if $(D T) is a non-const object type.
1966760c2415Smrg 
1967760c2415Smrg You may want to use $(D Rebindable) when you want to have mutable
1968760c2415Smrg storage referring to $(D const) objects, for example an array of
1969760c2415Smrg references that must be sorted in place. $(D Rebindable) does not
1970760c2415Smrg break the soundness of D's type system and does not incur any of the
1971760c2415Smrg risks usually associated with $(D cast).
1972760c2415Smrg 
1973760c2415Smrg Params:
1974760c2415Smrg     T = An object, interface, array slice type, or associative array type.
1975760c2415Smrg  */
1976760c2415Smrg template Rebindable(T)
1977760c2415Smrg     if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
1978760c2415Smrg {
1979760c2415Smrg     static if (is(T == const U, U) || is(T == immutable U, U))
1980760c2415Smrg     {
1981760c2415Smrg         static if (isDynamicArray!T)
1982760c2415Smrg         {
1983760c2415Smrg             import std.range.primitives : ElementEncodingType;
1984760c2415Smrg             alias Rebindable = const(ElementEncodingType!T)[];
1985760c2415Smrg         }
1986760c2415Smrg         else
1987760c2415Smrg         {
1988760c2415Smrg             struct Rebindable
1989760c2415Smrg             {
1990760c2415Smrg                 mixin RebindableCommon!(T, U, Rebindable);
1991760c2415Smrg             }
1992760c2415Smrg         }
1993760c2415Smrg     }
1994760c2415Smrg     else
1995760c2415Smrg     {
1996760c2415Smrg         alias Rebindable = T;
1997760c2415Smrg     }
1998760c2415Smrg }
1999760c2415Smrg 
2000760c2415Smrg ///Regular $(D const) object references cannot be reassigned.
2001760c2415Smrg @system unittest
2002760c2415Smrg {
2003760c2415Smrg     class Widget { int x; int y() const { return x; } }
2004760c2415Smrg     const a = new Widget;
2005760c2415Smrg     // Fine
2006760c2415Smrg     a.y();
2007760c2415Smrg     // error! can't modify const a
2008760c2415Smrg     // a.x = 5;
2009760c2415Smrg     // error! can't modify const a
2010760c2415Smrg     // a = new Widget;
2011760c2415Smrg }
2012760c2415Smrg 
2013760c2415Smrg /**
2014760c2415Smrg     However, $(D Rebindable!(Widget)) does allow reassignment,
2015760c2415Smrg     while otherwise behaving exactly like a $(D const Widget).
2016760c2415Smrg  */
2017760c2415Smrg @system unittest
2018760c2415Smrg {
2019760c2415Smrg     class Widget { int x; int y() const { return x; } }
2020760c2415Smrg     auto a = Rebindable!(const Widget)(new Widget);
2021760c2415Smrg     // Fine
2022760c2415Smrg     a.y();
2023760c2415Smrg     // error! can't modify const a
2024760c2415Smrg     // a.x = 5;
2025760c2415Smrg     // Fine
2026760c2415Smrg     a = new Widget;
2027760c2415Smrg }
2028760c2415Smrg 
2029760c2415Smrg @safe unittest // issue 16054
2030760c2415Smrg {
2031760c2415Smrg     Rebindable!(immutable Object) r;
2032760c2415Smrg     static assert(__traits(compiles, r.get()));
2033760c2415Smrg     static assert(!__traits(compiles, &r.get()));
2034760c2415Smrg }
2035760c2415Smrg 
2036760c2415Smrg /**
2037760c2415Smrg Convenience function for creating a $(D Rebindable) using automatic type
2038760c2415Smrg inference.
2039760c2415Smrg 
2040760c2415Smrg Params:
2041760c2415Smrg     obj = A reference to an object, interface, associative array, or an array slice
2042760c2415Smrg           to initialize the `Rebindable` with.
2043760c2415Smrg 
2044760c2415Smrg Returns:
2045760c2415Smrg     A newly constructed `Rebindable` initialized with the given reference.
2046760c2415Smrg */
2047760c2415Smrg Rebindable!T rebindable(T)(T obj)
2048760c2415Smrg     if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
2049760c2415Smrg {
2050760c2415Smrg     typeof(return) ret;
2051760c2415Smrg     ret = obj;
2052760c2415Smrg     return ret;
2053760c2415Smrg }
2054760c2415Smrg 
2055760c2415Smrg /**
2056760c2415Smrg This function simply returns the $(D Rebindable) object passed in.  It's useful
2057760c2415Smrg in generic programming cases when a given object may be either a regular
2058760c2415Smrg $(D class) or a $(D Rebindable).
2059760c2415Smrg 
2060760c2415Smrg Params:
2061760c2415Smrg     obj = An instance of Rebindable!T.
2062760c2415Smrg 
2063760c2415Smrg Returns:
2064760c2415Smrg     `obj` without any modification.
2065760c2415Smrg */
2066760c2415Smrg Rebindable!T rebindable(T)(Rebindable!T obj)
2067760c2415Smrg {
2068760c2415Smrg     return obj;
2069760c2415Smrg }
2070760c2415Smrg 
2071760c2415Smrg @system unittest
2072760c2415Smrg {
2073760c2415Smrg     interface CI { int foo() const; }
2074760c2415Smrg     class C : CI {
2075760c2415Smrg       int foo() const { return 42; }
2076760c2415Smrg       @property int bar() const { return 23; }
2077760c2415Smrg     }
2078760c2415Smrg     Rebindable!(C) obj0;
2079760c2415Smrg     static assert(is(typeof(obj0) == C));
2080760c2415Smrg 
2081760c2415Smrg     Rebindable!(const(C)) obj1;
2082760c2415Smrg     static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof);
2083760c2415Smrg     static assert(is(typeof(obj1.stripped) == C));
2084760c2415Smrg     obj1 = new C;
2085760c2415Smrg     assert(obj1.get !is null);
2086760c2415Smrg     obj1 = new const(C);
2087760c2415Smrg     assert(obj1.get !is null);
2088760c2415Smrg 
2089760c2415Smrg     Rebindable!(immutable(C)) obj2;
2090760c2415Smrg     static assert(is(typeof(obj2.get) == immutable(C)));
2091760c2415Smrg     static assert(is(typeof(obj2.stripped) == C));
2092760c2415Smrg     obj2 = new immutable(C);
2093760c2415Smrg     assert(obj1.get !is null);
2094760c2415Smrg 
2095760c2415Smrg     // test opDot
2096760c2415Smrg     assert(obj2.foo() == 42);
2097760c2415Smrg     assert(obj2.bar == 23);
2098760c2415Smrg 
2099760c2415Smrg     interface I { final int foo() const { return 42; } }
2100760c2415Smrg     Rebindable!(I) obj3;
2101760c2415Smrg     static assert(is(typeof(obj3) == I));
2102760c2415Smrg 
2103760c2415Smrg     Rebindable!(const I) obj4;
2104760c2415Smrg     static assert(is(typeof(obj4.get) == const I));
2105760c2415Smrg     static assert(is(typeof(obj4.stripped) == I));
2106760c2415Smrg     static assert(is(typeof(obj4.foo()) == int));
2107760c2415Smrg     obj4 = new class I {};
2108760c2415Smrg 
2109760c2415Smrg     Rebindable!(immutable C) obj5i;
2110760c2415Smrg     Rebindable!(const C) obj5c;
2111760c2415Smrg     obj5c = obj5c;
2112760c2415Smrg     obj5c = obj5i;
2113760c2415Smrg     obj5i = obj5i;
2114760c2415Smrg     static assert(!__traits(compiles, obj5i = obj5c));
2115760c2415Smrg 
2116760c2415Smrg     // Test the convenience functions.
2117760c2415Smrg     auto obj5convenience = rebindable(obj5i);
2118760c2415Smrg     assert(obj5convenience is obj5i);
2119760c2415Smrg 
2120760c2415Smrg     auto obj6 = rebindable(new immutable(C));
2121760c2415Smrg     static assert(is(typeof(obj6) == Rebindable!(immutable C)));
2122760c2415Smrg     assert(obj6.foo() == 42);
2123760c2415Smrg 
2124760c2415Smrg     auto obj7 = rebindable(new C);
2125760c2415Smrg     CI interface1 = obj7;
2126760c2415Smrg     auto interfaceRebind1 = rebindable(interface1);
2127760c2415Smrg     assert(interfaceRebind1.foo() == 42);
2128760c2415Smrg 
2129760c2415Smrg     const interface2 = interface1;
2130760c2415Smrg     auto interfaceRebind2 = rebindable(interface2);
2131760c2415Smrg     assert(interfaceRebind2.foo() == 42);
2132760c2415Smrg 
2133760c2415Smrg     auto arr = [1,2,3,4,5];
2134760c2415Smrg     const arrConst = arr;
2135760c2415Smrg     assert(rebindable(arr) == arr);
2136760c2415Smrg     assert(rebindable(arrConst) == arr);
2137760c2415Smrg 
2138760c2415Smrg     // Issue 7654
2139760c2415Smrg     immutable(char[]) s7654;
2140760c2415Smrg     Rebindable!(typeof(s7654)) r7654 = s7654;
2141760c2415Smrg 
2142760c2415Smrg     foreach (T; AliasSeq!(char, wchar, char, int))
2143760c2415Smrg     {
2144760c2415Smrg         static assert(is(Rebindable!(immutable(T[])) == immutable(T)[]));
2145760c2415Smrg         static assert(is(Rebindable!(const(T[])) == const(T)[]));
2146760c2415Smrg         static assert(is(Rebindable!(T[]) == T[]));
2147760c2415Smrg     }
2148760c2415Smrg 
2149760c2415Smrg     // Issue 12046
2150760c2415Smrg     static assert(!__traits(compiles, Rebindable!(int[1])));
2151760c2415Smrg     static assert(!__traits(compiles, Rebindable!(const int[1])));
2152760c2415Smrg 
2153760c2415Smrg     // Pull request 3341
2154760c2415Smrg     Rebindable!(immutable int[int]) pr3341 = [123:345];
2155760c2415Smrg     assert(pr3341[123] == 345);
2156760c2415Smrg     immutable int[int] pr3341_aa = [321:543];
2157760c2415Smrg     pr3341 = pr3341_aa;
2158760c2415Smrg     assert(pr3341[321] == 543);
2159760c2415Smrg     assert(rebindable(pr3341_aa)[321] == 543);
2160760c2415Smrg }
2161760c2415Smrg 
2162760c2415Smrg /**
2163760c2415Smrg     Similar to $(D Rebindable!(T)) but strips all qualifiers from the reference as
2164760c2415Smrg     opposed to just constness / immutability. Primary intended use case is with
2165760c2415Smrg     shared (having thread-local reference to shared class data)
2166760c2415Smrg 
2167760c2415Smrg     Params:
2168760c2415Smrg         T = A class or interface type.
2169760c2415Smrg  */
2170760c2415Smrg template UnqualRef(T)
2171760c2415Smrg     if (is(T == class) || is(T == interface))
2172760c2415Smrg {
2173760c2415Smrg     static if (is(T == const U, U)
2174760c2415Smrg         || is(T == immutable U, U)
2175760c2415Smrg         || is(T == shared U, U)
2176760c2415Smrg         || is(T == const shared U, U))
2177760c2415Smrg     {
2178760c2415Smrg         struct UnqualRef
2179760c2415Smrg         {
2180760c2415Smrg             mixin RebindableCommon!(T, U, UnqualRef);
2181760c2415Smrg         }
2182760c2415Smrg     }
2183760c2415Smrg     else
2184760c2415Smrg     {
2185760c2415Smrg         alias UnqualRef = T;
2186760c2415Smrg     }
2187760c2415Smrg }
2188760c2415Smrg 
2189760c2415Smrg ///
2190760c2415Smrg @system unittest
2191760c2415Smrg {
2192760c2415Smrg     class Data {}
2193760c2415Smrg 
2194760c2415Smrg     static shared(Data) a;
2195760c2415Smrg     static UnqualRef!(shared Data) b;
2196760c2415Smrg 
2197760c2415Smrg     import core.thread;
2198760c2415Smrg 
2199760c2415Smrg     auto thread = new core.thread.Thread({
2200760c2415Smrg         a = new shared Data();
2201760c2415Smrg         b = new shared Data();
2202760c2415Smrg     });
2203760c2415Smrg 
2204760c2415Smrg     thread.start();
2205760c2415Smrg     thread.join();
2206760c2415Smrg 
2207760c2415Smrg     assert(a !is null);
2208760c2415Smrg     assert(b is null);
2209760c2415Smrg }
2210760c2415Smrg 
2211760c2415Smrg @safe unittest
2212760c2415Smrg {
2213760c2415Smrg     class C { }
2214760c2415Smrg     alias T = UnqualRef!(const shared C);
2215760c2415Smrg     static assert(is(typeof(T.stripped) == C));
2216760c2415Smrg }
2217760c2415Smrg 
2218760c2415Smrg 
2219760c2415Smrg 
2220760c2415Smrg /**
2221760c2415Smrg   Order the provided members to minimize size while preserving alignment.
2222760c2415Smrg   Alignment is not always optimal for 80-bit reals, nor for structs declared
2223760c2415Smrg   as align(1).
2224760c2415Smrg 
2225760c2415Smrg   Params:
2226760c2415Smrg       E = A list of the types to be aligned, representing fields
2227760c2415Smrg           of an aggregate such as a `struct` or `class`.
2228760c2415Smrg 
2229760c2415Smrg       names = The names of the fields that are to be aligned.
2230760c2415Smrg 
2231760c2415Smrg   Returns:
2232760c2415Smrg       A string to be mixed in to an aggregate, such as a `struct` or `class`.
2233760c2415Smrg */
2234760c2415Smrg string alignForSize(E...)(const char[][] names...)
2235760c2415Smrg {
2236760c2415Smrg     // Sort all of the members by .alignof.
2237760c2415Smrg     // BUG: Alignment is not always optimal for align(1) structs
2238760c2415Smrg     // or 80-bit reals or 64-bit primitives on x86.
2239760c2415Smrg     // TRICK: Use the fact that .alignof is always a power of 2,
2240760c2415Smrg     // and maximum 16 on extant systems. Thus, we can perform
2241760c2415Smrg     // a very limited radix sort.
2242760c2415Smrg     // Contains the members with .alignof = 64,32,16,8,4,2,1
2243760c2415Smrg 
2244760c2415Smrg     assert(E.length == names.length,
2245760c2415Smrg         "alignForSize: There should be as many member names as the types");
2246760c2415Smrg 
2247760c2415Smrg     string[7] declaration = ["", "", "", "", "", "", ""];
2248760c2415Smrg 
2249760c2415Smrg     foreach (i, T; E)
2250760c2415Smrg     {
2251760c2415Smrg         auto a = T.alignof;
2252760c2415Smrg         auto k = a >= 64? 0 : a >= 32? 1 : a >= 16? 2 : a >= 8? 3 : a >= 4? 4 : a >= 2? 5 : 6;
2253760c2415Smrg         declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n";
2254760c2415Smrg     }
2255760c2415Smrg 
2256760c2415Smrg     auto s = "";
2257760c2415Smrg     foreach (decl; declaration)
2258760c2415Smrg         s ~= decl;
2259760c2415Smrg     return s;
2260760c2415Smrg }
2261760c2415Smrg 
2262760c2415Smrg ///
2263760c2415Smrg @safe unittest
2264760c2415Smrg {
2265760c2415Smrg     struct Banner {
2266760c2415Smrg         mixin(alignForSize!(byte[6], double)(["name", "height"]));
2267760c2415Smrg     }
2268760c2415Smrg }
2269760c2415Smrg 
2270760c2415Smrg @safe unittest
2271760c2415Smrg {
2272760c2415Smrg     enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w");
2273760c2415Smrg     struct Foo { int x; }
2274760c2415Smrg     enum y = alignForSize!(ubyte, Foo, cdouble)("x", "y", "z");
2275760c2415Smrg 
2276760c2415Smrg     enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
2277760c2415Smrg     enum passNormalY = y == "cdouble z;\nFoo y;\nubyte x;\n";
2278760c2415Smrg 
2279760c2415Smrg     enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
2280760c2415Smrg     enum passAbnormalY = y == "Foo y;\ncdouble z;\nubyte x;\n";
2281760c2415Smrg     // ^ blame http://d.puremagic.com/issues/show_bug.cgi?id=231
2282760c2415Smrg 
2283760c2415Smrg     static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof);
2284760c2415Smrg     static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof);
2285760c2415Smrg }
2286760c2415Smrg 
2287760c2415Smrg // Issue 12914
2288760c2415Smrg @safe unittest
2289760c2415Smrg {
2290760c2415Smrg     immutable string[] fieldNames = ["x", "y"];
2291760c2415Smrg     struct S
2292760c2415Smrg     {
2293760c2415Smrg         mixin(alignForSize!(byte, int)(fieldNames));
2294760c2415Smrg     }
2295760c2415Smrg }
2296760c2415Smrg 
2297760c2415Smrg /**
2298760c2415Smrg Defines a value paired with a distinctive "null" state that denotes
2299760c2415Smrg the absence of a value. If default constructed, a $(D
2300760c2415Smrg Nullable!T) object starts in the null state. Assigning it renders it
2301760c2415Smrg non-null. Calling $(D nullify) can nullify it again.
2302760c2415Smrg 
2303760c2415Smrg Practically $(D Nullable!T) stores a $(D T) and a $(D bool).
2304760c2415Smrg  */
2305760c2415Smrg struct Nullable(T)
2306760c2415Smrg {
2307760c2415Smrg     private T _value;
2308760c2415Smrg     private bool _isNull = true;
2309760c2415Smrg 
2310760c2415Smrg /**
2311760c2415Smrg Constructor initializing $(D this) with $(D value).
2312760c2415Smrg 
2313760c2415Smrg Params:
2314760c2415Smrg     value = The value to initialize this `Nullable` with.
2315760c2415Smrg  */
2316760c2415Smrg     this(inout T value) inout
2317760c2415Smrg     {
2318760c2415Smrg         _value = value;
2319760c2415Smrg         _isNull = false;
2320760c2415Smrg     }
2321760c2415Smrg 
2322760c2415Smrg     /**
2323760c2415Smrg       If they are both null, then they are equal. If one is null and the other
2324760c2415Smrg       is not, then they are not equal. If they are both non-null, then they are
2325760c2415Smrg       equal if their values are equal.
2326760c2415Smrg       */
2327760c2415Smrg     bool opEquals()(auto ref const(typeof(this)) rhs) const
2328760c2415Smrg     {
2329760c2415Smrg         if (_isNull)
2330760c2415Smrg             return rhs._isNull;
2331760c2415Smrg         if (rhs._isNull)
2332760c2415Smrg             return false;
2333760c2415Smrg         return _value == rhs._value;
2334760c2415Smrg     }
2335760c2415Smrg 
2336760c2415Smrg     /// Ditto
2337760c2415Smrg     bool opEquals(U)(auto ref const(U) rhs) const
2338760c2415Smrg     if (is(typeof(this.get == rhs)))
2339760c2415Smrg     {
2340760c2415Smrg         return _isNull ? false : rhs == _value;
2341760c2415Smrg     }
2342760c2415Smrg 
2343760c2415Smrg     ///
2344760c2415Smrg     @safe unittest
2345760c2415Smrg     {
2346760c2415Smrg         Nullable!int empty;
2347760c2415Smrg         Nullable!int a = 42;
2348760c2415Smrg         Nullable!int b = 42;
2349760c2415Smrg         Nullable!int c = 27;
2350760c2415Smrg 
2351760c2415Smrg         assert(empty == empty);
2352760c2415Smrg         assert(empty == Nullable!int.init);
2353760c2415Smrg         assert(empty != a);
2354760c2415Smrg         assert(empty != b);
2355760c2415Smrg         assert(empty != c);
2356760c2415Smrg 
2357760c2415Smrg         assert(a == b);
2358760c2415Smrg         assert(a != c);
2359760c2415Smrg 
2360760c2415Smrg         assert(empty != 42);
2361760c2415Smrg         assert(a == 42);
2362760c2415Smrg         assert(c != 42);
2363760c2415Smrg     }
2364760c2415Smrg 
2365760c2415Smrg     @safe unittest
2366760c2415Smrg     {
2367760c2415Smrg         // Test constness
2368760c2415Smrg         immutable Nullable!int a = 42;
2369760c2415Smrg         Nullable!int b = 42;
2370760c2415Smrg         immutable Nullable!int c = 29;
2371760c2415Smrg         Nullable!int d = 29;
2372760c2415Smrg         immutable e = 42;
2373760c2415Smrg         int f = 29;
2374760c2415Smrg         assert(a == a);
2375760c2415Smrg         assert(a == b);
2376760c2415Smrg         assert(a != c);
2377760c2415Smrg         assert(a != d);
2378760c2415Smrg         assert(a == e);
2379760c2415Smrg         assert(a != f);
2380760c2415Smrg 
2381760c2415Smrg         // Test rvalue
2382760c2415Smrg         assert(a == const Nullable!int(42));
2383760c2415Smrg         assert(a != Nullable!int(29));
2384760c2415Smrg     }
2385760c2415Smrg 
2386760c2415Smrg     // Issue 17482
2387760c2415Smrg     @system unittest
2388760c2415Smrg     {
2389760c2415Smrg         import std.variant : Variant;
2390760c2415Smrg         Nullable!Variant a = Variant(12);
2391760c2415Smrg         assert(a == 12);
2392760c2415Smrg         Nullable!Variant e;
2393760c2415Smrg         assert(e != 12);
2394760c2415Smrg     }
2395760c2415Smrg 
2396760c2415Smrg     template toString()
2397760c2415Smrg     {
2398760c2415Smrg         import std.format : FormatSpec, formatValue;
2399760c2415Smrg         // Needs to be a template because of DMD @@BUG@@ 13737.
2400760c2415Smrg         void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
2401760c2415Smrg         {
2402760c2415Smrg             if (isNull)
2403760c2415Smrg             {
2404760c2415Smrg                 sink.formatValue("Nullable.null", fmt);
2405760c2415Smrg             }
2406760c2415Smrg             else
2407760c2415Smrg             {
2408760c2415Smrg                 sink.formatValue(_value, fmt);
2409760c2415Smrg             }
2410760c2415Smrg         }
2411760c2415Smrg 
2412760c2415Smrg         // Issue 14940
2413760c2415Smrg         void toString()(scope void delegate(const(char)[]) @safe sink, FormatSpec!char fmt)
2414760c2415Smrg         {
2415760c2415Smrg             if (isNull)
2416760c2415Smrg             {
2417760c2415Smrg                 sink.formatValue("Nullable.null", fmt);
2418760c2415Smrg             }
2419760c2415Smrg             else
2420760c2415Smrg             {
2421760c2415Smrg                 sink.formatValue(_value, fmt);
2422760c2415Smrg             }
2423760c2415Smrg         }
2424760c2415Smrg     }
2425760c2415Smrg 
2426760c2415Smrg /**
2427760c2415Smrg Check if `this` is in the null state.
2428760c2415Smrg 
2429760c2415Smrg Returns:
2430760c2415Smrg     true $(B iff) `this` is in the null state, otherwise false.
2431760c2415Smrg  */
2432760c2415Smrg     @property bool isNull() const @safe pure nothrow
2433760c2415Smrg     {
2434760c2415Smrg         return _isNull;
2435760c2415Smrg     }
2436760c2415Smrg 
2437760c2415Smrg ///
2438760c2415Smrg @system unittest
2439760c2415Smrg {
2440760c2415Smrg     Nullable!int ni;
2441760c2415Smrg     assert(ni.isNull);
2442760c2415Smrg 
2443760c2415Smrg     ni = 0;
2444760c2415Smrg     assert(!ni.isNull);
2445760c2415Smrg }
2446760c2415Smrg 
2447760c2415Smrg // Issue 14940
2448760c2415Smrg @safe unittest
2449760c2415Smrg {
2450760c2415Smrg     import std.array : appender;
2451760c2415Smrg     import std.format : formattedWrite;
2452760c2415Smrg 
2453760c2415Smrg     auto app = appender!string();
2454760c2415Smrg     Nullable!int a = 1;
2455760c2415Smrg     formattedWrite(app, "%s", a);
2456760c2415Smrg     assert(app.data == "1");
2457760c2415Smrg }
2458760c2415Smrg 
2459760c2415Smrg /**
2460760c2415Smrg Forces $(D this) to the null state.
2461760c2415Smrg  */
2462760c2415Smrg     void nullify()()
2463760c2415Smrg     {
2464760c2415Smrg         .destroy(_value);
2465760c2415Smrg         _isNull = true;
2466760c2415Smrg     }
2467760c2415Smrg 
2468760c2415Smrg ///
2469760c2415Smrg @safe unittest
2470760c2415Smrg {
2471760c2415Smrg     Nullable!int ni = 0;
2472760c2415Smrg     assert(!ni.isNull);
2473760c2415Smrg 
2474760c2415Smrg     ni.nullify();
2475760c2415Smrg     assert(ni.isNull);
2476760c2415Smrg }
2477760c2415Smrg 
2478760c2415Smrg /**
2479760c2415Smrg Assigns $(D value) to the internally-held state. If the assignment
2480760c2415Smrg succeeds, $(D this) becomes non-null.
2481760c2415Smrg 
2482760c2415Smrg Params:
2483760c2415Smrg     value = A value of type `T` to assign to this `Nullable`.
2484760c2415Smrg  */
2485760c2415Smrg     void opAssign()(T value)
2486760c2415Smrg     {
2487760c2415Smrg         _value = value;
2488760c2415Smrg         _isNull = false;
2489760c2415Smrg     }
2490760c2415Smrg 
2491760c2415Smrg /**
2492760c2415Smrg     If this `Nullable` wraps a type that already has a null value
2493760c2415Smrg     (such as a pointer), then assigning the null value to this
2494760c2415Smrg     `Nullable` is no different than assigning any other value of
2495760c2415Smrg     type `T`, and the resulting code will look very strange. It
2496760c2415Smrg     is strongly recommended that this be avoided by instead using
2497760c2415Smrg     the version of `Nullable` that takes an additional `nullValue`
2498760c2415Smrg     template argument.
2499760c2415Smrg  */
2500760c2415Smrg @safe unittest
2501760c2415Smrg {
2502760c2415Smrg     //Passes
2503760c2415Smrg     Nullable!(int*) npi;
2504760c2415Smrg     assert(npi.isNull);
2505760c2415Smrg 
2506760c2415Smrg     //Passes?!
2507760c2415Smrg     npi = null;
2508760c2415Smrg     assert(!npi.isNull);
2509760c2415Smrg }
2510760c2415Smrg 
2511760c2415Smrg /**
2512760c2415Smrg Gets the value. $(D this) must not be in the null state.
2513760c2415Smrg This function is also called for the implicit conversion to $(D T).
2514760c2415Smrg 
2515760c2415Smrg Returns:
2516760c2415Smrg     The value held internally by this `Nullable`.
2517760c2415Smrg  */
2518760c2415Smrg     @property ref inout(T) get() inout @safe pure nothrow
2519760c2415Smrg     {
2520760c2415Smrg         enum message = "Called `get' on null Nullable!" ~ T.stringof ~ ".";
2521760c2415Smrg         assert(!isNull, message);
2522760c2415Smrg         return _value;
2523760c2415Smrg     }
2524760c2415Smrg 
2525760c2415Smrg ///
2526760c2415Smrg @system unittest
2527760c2415Smrg {
2528760c2415Smrg     import core.exception : AssertError;
2529760c2415Smrg     import std.exception : assertThrown, assertNotThrown;
2530760c2415Smrg 
2531760c2415Smrg     Nullable!int ni;
2532760c2415Smrg     int i = 42;
2533760c2415Smrg     //`get` is implicitly called. Will throw
2534760c2415Smrg     //an AssertError in non-release mode
2535760c2415Smrg     assertThrown!AssertError(i = ni);
2536760c2415Smrg     assert(i == 42);
2537760c2415Smrg 
2538760c2415Smrg     ni = 5;
2539760c2415Smrg     assertNotThrown!AssertError(i = ni);
2540760c2415Smrg     assert(i == 5);
2541760c2415Smrg }
2542760c2415Smrg 
2543760c2415Smrg /**
2544760c2415Smrg Implicitly converts to $(D T).
2545760c2415Smrg $(D this) must not be in the null state.
2546760c2415Smrg  */
2547760c2415Smrg     alias get this;
2548760c2415Smrg }
2549760c2415Smrg 
2550760c2415Smrg /// ditto
2551760c2415Smrg auto nullable(T)(T t)
2552760c2415Smrg {
2553760c2415Smrg     return Nullable!T(t);
2554760c2415Smrg }
2555760c2415Smrg 
2556760c2415Smrg ///
2557760c2415Smrg @safe unittest
2558760c2415Smrg {
2559760c2415Smrg     struct CustomerRecord
2560760c2415Smrg     {
2561760c2415Smrg         string name;
2562760c2415Smrg         string address;
2563760c2415Smrg         int customerNum;
2564760c2415Smrg     }
2565760c2415Smrg 
2566760c2415Smrg     Nullable!CustomerRecord getByName(string name)
2567760c2415Smrg     {
2568760c2415Smrg         //A bunch of hairy stuff
2569760c2415Smrg 
2570760c2415Smrg         return Nullable!CustomerRecord.init;
2571760c2415Smrg     }
2572760c2415Smrg 
2573760c2415Smrg     auto queryResult = getByName("Doe, John");
2574760c2415Smrg     if (!queryResult.isNull)
2575760c2415Smrg     {
2576760c2415Smrg         //Process Mr. Doe's customer record
2577760c2415Smrg         auto address = queryResult.address;
2578760c2415Smrg         auto customerNum = queryResult.customerNum;
2579760c2415Smrg 
2580760c2415Smrg         //Do some things with this customer's info
2581760c2415Smrg     }
2582760c2415Smrg     else
2583760c2415Smrg     {
2584760c2415Smrg         //Add the customer to the database
2585760c2415Smrg     }
2586760c2415Smrg }
2587760c2415Smrg 
2588760c2415Smrg ///
2589760c2415Smrg @system unittest
2590760c2415Smrg {
2591760c2415Smrg     import std.exception : assertThrown;
2592760c2415Smrg 
2593760c2415Smrg     auto a = 42.nullable;
2594760c2415Smrg     assert(!a.isNull);
2595760c2415Smrg     assert(a.get == 42);
2596760c2415Smrg 
2597760c2415Smrg     a.nullify();
2598760c2415Smrg     assert(a.isNull);
2599760c2415Smrg     assertThrown!Throwable(a.get);
2600760c2415Smrg }
2601760c2415Smrg 
2602760c2415Smrg @system unittest
2603760c2415Smrg {
2604760c2415Smrg     import std.exception : assertThrown;
2605760c2415Smrg 
2606760c2415Smrg     Nullable!int a;
2607760c2415Smrg     assert(a.isNull);
2608760c2415Smrg     assertThrown!Throwable(a.get);
2609760c2415Smrg     a = 5;
2610760c2415Smrg     assert(!a.isNull);
2611760c2415Smrg     assert(a == 5);
2612760c2415Smrg     assert(a != 3);
2613760c2415Smrg     assert(a.get != 3);
2614760c2415Smrg     a.nullify();
2615760c2415Smrg     assert(a.isNull);
2616760c2415Smrg     a = 3;
2617760c2415Smrg     assert(a == 3);
2618760c2415Smrg     a *= 6;
2619760c2415Smrg     assert(a == 18);
2620760c2415Smrg     a = a;
2621760c2415Smrg     assert(a == 18);
2622760c2415Smrg     a.nullify();
2623760c2415Smrg     assertThrown!Throwable(a += 2);
2624760c2415Smrg }
2625760c2415Smrg @safe unittest
2626760c2415Smrg {
2627760c2415Smrg     auto k = Nullable!int(74);
2628760c2415Smrg     assert(k == 74);
2629760c2415Smrg     k.nullify();
2630760c2415Smrg     assert(k.isNull);
2631760c2415Smrg }
2632760c2415Smrg @safe unittest
2633760c2415Smrg {
2634760c2415Smrg     static int f(in Nullable!int x) {
2635760c2415Smrg         return x.isNull ? 42 : x.get;
2636760c2415Smrg     }
2637760c2415Smrg     Nullable!int a;
2638760c2415Smrg     assert(f(a) == 42);
2639760c2415Smrg     a = 8;
2640760c2415Smrg     assert(f(a) == 8);
2641760c2415Smrg     a.nullify();
2642760c2415Smrg     assert(f(a) == 42);
2643760c2415Smrg }
2644760c2415Smrg @system unittest
2645760c2415Smrg {
2646760c2415Smrg     import std.exception : assertThrown;
2647760c2415Smrg 
2648760c2415Smrg     static struct S { int x; }
2649760c2415Smrg     Nullable!S s;
2650760c2415Smrg     assert(s.isNull);
2651760c2415Smrg     s = S(6);
2652760c2415Smrg     assert(s == S(6));
2653760c2415Smrg     assert(s != S(0));
2654760c2415Smrg     assert(s.get != S(0));
2655760c2415Smrg     s.x = 9190;
2656760c2415Smrg     assert(s.x == 9190);
2657760c2415Smrg     s.nullify();
2658760c2415Smrg     assertThrown!Throwable(s.x = 9441);
2659760c2415Smrg }
2660760c2415Smrg @safe unittest
2661760c2415Smrg {
2662760c2415Smrg     // Ensure Nullable can be used in pure/nothrow/@safe environment.
2663760c2415Smrg     function() @safe pure nothrow
2664760c2415Smrg     {
2665760c2415Smrg         Nullable!int n;
2666760c2415Smrg         assert(n.isNull);
2667760c2415Smrg         n = 4;
2668760c2415Smrg         assert(!n.isNull);
2669760c2415Smrg         assert(n == 4);
2670760c2415Smrg         n.nullify();
2671760c2415Smrg         assert(n.isNull);
2672760c2415Smrg     }();
2673760c2415Smrg }
2674760c2415Smrg @system unittest
2675760c2415Smrg {
2676760c2415Smrg     // Ensure Nullable can be used when the value is not pure/nothrow/@safe
2677760c2415Smrg     static struct S
2678760c2415Smrg     {
2679760c2415Smrg         int x;
2680760c2415Smrg         this(this) @system {}
2681760c2415Smrg     }
2682760c2415Smrg 
2683760c2415Smrg     Nullable!S s;
2684760c2415Smrg     assert(s.isNull);
2685760c2415Smrg     s = S(5);
2686760c2415Smrg     assert(!s.isNull);
2687760c2415Smrg     assert(s.x == 5);
2688760c2415Smrg     s.nullify();
2689760c2415Smrg     assert(s.isNull);
2690760c2415Smrg }
2691760c2415Smrg @safe unittest
2692760c2415Smrg {
2693760c2415Smrg     // Bugzilla 9404
2694760c2415Smrg     alias N = Nullable!int;
2695760c2415Smrg 
2696760c2415Smrg     void foo(N a)
2697760c2415Smrg     {
2698760c2415Smrg         N b;
2699760c2415Smrg         b = a; // `N b = a;` works fine
2700760c2415Smrg     }
2701760c2415Smrg     N n;
2702760c2415Smrg     foo(n);
2703760c2415Smrg }
2704760c2415Smrg @safe unittest
2705760c2415Smrg {
2706760c2415Smrg     //Check nullable immutable is constructable
2707760c2415Smrg     {
2708760c2415Smrg         auto a1 = Nullable!(immutable int)();
2709760c2415Smrg         auto a2 = Nullable!(immutable int)(1);
2710760c2415Smrg         auto i = a2.get;
2711760c2415Smrg     }
2712760c2415Smrg     //Check immutable nullable is constructable
2713760c2415Smrg     {
2714760c2415Smrg         auto a1 = immutable (Nullable!int)();
2715760c2415Smrg         auto a2 = immutable (Nullable!int)(1);
2716760c2415Smrg         auto i = a2.get;
2717760c2415Smrg     }
2718760c2415Smrg }
2719760c2415Smrg @safe unittest
2720760c2415Smrg {
2721760c2415Smrg     alias NInt   = Nullable!int;
2722760c2415Smrg 
2723760c2415Smrg     //Construct tests
2724760c2415Smrg     {
2725760c2415Smrg         //from other Nullable null
2726760c2415Smrg         NInt a1;
2727760c2415Smrg         NInt b1 = a1;
2728760c2415Smrg         assert(b1.isNull);
2729760c2415Smrg 
2730760c2415Smrg         //from other Nullable non-null
2731760c2415Smrg         NInt a2 = NInt(1);
2732760c2415Smrg         NInt b2 = a2;
2733760c2415Smrg         assert(b2 == 1);
2734760c2415Smrg 
2735760c2415Smrg         //Construct from similar nullable
2736760c2415Smrg         auto a3 = immutable(NInt)();
2737760c2415Smrg         NInt b3 = a3;
2738760c2415Smrg         assert(b3.isNull);
2739760c2415Smrg     }
2740760c2415Smrg 
2741760c2415Smrg     //Assign tests
2742760c2415Smrg     {
2743760c2415Smrg         //from other Nullable null
2744760c2415Smrg         NInt a1;
2745760c2415Smrg         NInt b1;
2746760c2415Smrg         b1 = a1;
2747760c2415Smrg         assert(b1.isNull);
2748760c2415Smrg 
2749760c2415Smrg         //from other Nullable non-null
2750760c2415Smrg         NInt a2 = NInt(1);
2751760c2415Smrg         NInt b2;
2752760c2415Smrg         b2 = a2;
2753760c2415Smrg         assert(b2 == 1);
2754760c2415Smrg 
2755760c2415Smrg         //Construct from similar nullable
2756760c2415Smrg         auto a3 = immutable(NInt)();
2757760c2415Smrg         NInt b3 = a3;
2758760c2415Smrg         b3 = a3;
2759760c2415Smrg         assert(b3.isNull);
2760760c2415Smrg     }
2761760c2415Smrg }
2762760c2415Smrg @safe unittest
2763760c2415Smrg {
2764760c2415Smrg     //Check nullable is nicelly embedable in a struct
2765760c2415Smrg     static struct S1
2766760c2415Smrg     {
2767760c2415Smrg         Nullable!int ni;
2768760c2415Smrg     }
2769760c2415Smrg     static struct S2 //inspired from 9404
2770760c2415Smrg     {
2771760c2415Smrg         Nullable!int ni;
2772760c2415Smrg         this(S2 other)
2773760c2415Smrg         {
2774760c2415Smrg             ni = other.ni;
2775760c2415Smrg         }
2776760c2415Smrg         void opAssign(S2 other)
2777760c2415Smrg         {
2778760c2415Smrg             ni = other.ni;
2779760c2415Smrg         }
2780760c2415Smrg     }
2781760c2415Smrg     foreach (S; AliasSeq!(S1, S2))
2782760c2415Smrg     {
2783760c2415Smrg         S a;
2784760c2415Smrg         S b = a;
2785760c2415Smrg         S c;
2786760c2415Smrg         c = a;
2787760c2415Smrg     }
2788760c2415Smrg }
2789760c2415Smrg @system unittest
2790760c2415Smrg {
2791760c2415Smrg     // Bugzilla 10268
2792760c2415Smrg     import std.json;
2793760c2415Smrg     JSONValue value = null;
2794760c2415Smrg     auto na = Nullable!JSONValue(value);
2795760c2415Smrg 
2796760c2415Smrg     struct S1 { int val; }
2797760c2415Smrg     struct S2 { int* val; }
2798760c2415Smrg     struct S3 { immutable int* val; }
2799760c2415Smrg 
2800760c2415Smrg     {
2801760c2415Smrg         auto sm = S1(1);
2802760c2415Smrg         immutable si = immutable S1(1);
2803760c2415Smrg         auto x1 =           Nullable!S1(sm);
2804760c2415Smrg         auto x2 = immutable Nullable!S1(sm);
2805760c2415Smrg         auto x3 =           Nullable!S1(si);
2806760c2415Smrg         auto x4 = immutable Nullable!S1(si);
2807760c2415Smrg         assert(x1.val == 1);
2808760c2415Smrg         assert(x2.val == 1);
2809760c2415Smrg         assert(x3.val == 1);
2810760c2415Smrg         assert(x4.val == 1);
2811760c2415Smrg     }
2812760c2415Smrg 
2813760c2415Smrg     auto nm = 10;
2814760c2415Smrg     immutable ni = 10;
2815760c2415Smrg 
2816760c2415Smrg     {
2817760c2415Smrg         auto sm = S2(&nm);
2818760c2415Smrg         immutable si = immutable S2(&ni);
2819760c2415Smrg         auto x1 =           Nullable!S2(sm);
2820760c2415Smrg         static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); }));
2821760c2415Smrg         static assert(!__traits(compiles, { auto x3 =           Nullable!S2(si); }));
2822760c2415Smrg         auto x4 = immutable Nullable!S2(si);
2823760c2415Smrg         assert(*x1.val == 10);
2824760c2415Smrg         assert(*x4.val == 10);
2825760c2415Smrg     }
2826760c2415Smrg 
2827760c2415Smrg     {
2828760c2415Smrg         auto sm = S3(&ni);
2829760c2415Smrg         immutable si = immutable S3(&ni);
2830760c2415Smrg         auto x1 =           Nullable!S3(sm);
2831760c2415Smrg         auto x2 = immutable Nullable!S3(sm);
2832760c2415Smrg         auto x3 =           Nullable!S3(si);
2833760c2415Smrg         auto x4 = immutable Nullable!S3(si);
2834760c2415Smrg         assert(*x1.val == 10);
2835760c2415Smrg         assert(*x2.val == 10);
2836760c2415Smrg         assert(*x3.val == 10);
2837760c2415Smrg         assert(*x4.val == 10);
2838760c2415Smrg     }
2839760c2415Smrg }
2840760c2415Smrg @safe unittest
2841760c2415Smrg {
2842760c2415Smrg     // Bugzila 10357
2843760c2415Smrg     import std.datetime;
2844760c2415Smrg     Nullable!SysTime time = SysTime(0);
2845760c2415Smrg }
2846760c2415Smrg @system unittest
2847760c2415Smrg {
2848760c2415Smrg     import std.conv : to;
2849760c2415Smrg     import std.array;
2850760c2415Smrg 
2851760c2415Smrg     // Bugzilla 10915
2852760c2415Smrg     Appender!string buffer;
2853760c2415Smrg 
2854760c2415Smrg     Nullable!int ni;
2855760c2415Smrg     assert(ni.to!string() == "Nullable.null");
2856760c2415Smrg 
2857760c2415Smrg     struct Test { string s; }
2858760c2415Smrg     alias NullableTest = Nullable!Test;
2859760c2415Smrg 
2860760c2415Smrg     NullableTest nt = Test("test");
2861760c2415Smrg     assert(nt.to!string() == `Test("test")`);
2862760c2415Smrg 
2863760c2415Smrg     NullableTest ntn = Test("null");
2864760c2415Smrg     assert(ntn.to!string() == `Test("null")`);
2865760c2415Smrg 
2866760c2415Smrg     class TestToString
2867760c2415Smrg     {
2868760c2415Smrg         double d;
2869760c2415Smrg 
2870760c2415Smrg         this (double d)
2871760c2415Smrg         {
2872760c2415Smrg             this.d = d;
2873760c2415Smrg         }
2874760c2415Smrg 
2875760c2415Smrg         override string toString()
2876760c2415Smrg         {
2877760c2415Smrg             return d.to!string();
2878760c2415Smrg         }
2879760c2415Smrg     }
2880760c2415Smrg     Nullable!TestToString ntts = new TestToString(2.5);
2881760c2415Smrg     assert(ntts.to!string() == "2.5");
2882760c2415Smrg }
2883760c2415Smrg 
2884760c2415Smrg /**
2885760c2415Smrg Just like $(D Nullable!T), except that the null state is defined as a
2886760c2415Smrg particular value. For example, $(D Nullable!(uint, uint.max)) is an
2887760c2415Smrg $(D uint) that sets aside the value $(D uint.max) to denote a null
2888760c2415Smrg state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D
2889760c2415Smrg Nullable!T) because it does not need to store an extra $(D bool).
2890760c2415Smrg 
2891760c2415Smrg Params:
2892760c2415Smrg     T = The wrapped type for which Nullable provides a null value.
2893760c2415Smrg 
2894760c2415Smrg     nullValue = The null value which denotes the null state of this
2895760c2415Smrg                 `Nullable`. Must be of type `T`.
2896760c2415Smrg  */
2897760c2415Smrg struct Nullable(T, T nullValue)
2898760c2415Smrg {
2899760c2415Smrg     private T _value = nullValue;
2900760c2415Smrg 
2901760c2415Smrg /**
2902760c2415Smrg Constructor initializing $(D this) with $(D value).
2903760c2415Smrg 
2904760c2415Smrg Params:
2905760c2415Smrg     value = The value to initialize this `Nullable` with.
2906760c2415Smrg  */
2907760c2415Smrg     this(T value)
2908760c2415Smrg     {
2909760c2415Smrg         _value = value;
2910760c2415Smrg     }
2911760c2415Smrg 
2912760c2415Smrg     template toString()
2913760c2415Smrg     {
2914760c2415Smrg         import std.format : FormatSpec, formatValue;
2915760c2415Smrg         // Needs to be a template because of DMD @@BUG@@ 13737.
2916760c2415Smrg         void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
2917760c2415Smrg         {
2918760c2415Smrg             if (isNull)
2919760c2415Smrg             {
2920760c2415Smrg                 sink.formatValue("Nullable.null", fmt);
2921760c2415Smrg             }
2922760c2415Smrg             else
2923760c2415Smrg             {
2924760c2415Smrg                 sink.formatValue(_value, fmt);
2925760c2415Smrg             }
2926760c2415Smrg         }
2927760c2415Smrg     }
2928760c2415Smrg 
2929760c2415Smrg /**
2930760c2415Smrg Check if `this` is in the null state.
2931760c2415Smrg 
2932760c2415Smrg Returns:
2933760c2415Smrg     true $(B iff) `this` is in the null state, otherwise false.
2934760c2415Smrg  */
2935760c2415Smrg     @property bool isNull() const
2936760c2415Smrg     {
2937760c2415Smrg         //Need to use 'is' if T is a nullable type and
2938760c2415Smrg         //nullValue is null, or it's a compiler error
2939760c2415Smrg         static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null)
2940760c2415Smrg         {
2941760c2415Smrg             return _value is nullValue;
2942760c2415Smrg         }
2943760c2415Smrg         //Need to use 'is' if T is a float type
2944760c2415Smrg         //because NaN != NaN
2945760c2415Smrg         else static if (isFloatingPoint!T)
2946760c2415Smrg         {
2947760c2415Smrg             return _value is nullValue;
2948760c2415Smrg         }
2949760c2415Smrg         else
2950760c2415Smrg         {
2951760c2415Smrg             return _value == nullValue;
2952760c2415Smrg         }
2953760c2415Smrg     }
2954760c2415Smrg 
2955760c2415Smrg ///
2956760c2415Smrg @system unittest
2957760c2415Smrg {
2958760c2415Smrg     Nullable!(int, -1) ni;
2959760c2415Smrg     //Initialized to "null" state
2960760c2415Smrg     assert(ni.isNull);
2961760c2415Smrg 
2962760c2415Smrg     ni = 0;
2963760c2415Smrg     assert(!ni.isNull);
2964760c2415Smrg }
2965760c2415Smrg 
2966760c2415Smrg // https://issues.dlang.org/show_bug.cgi?id=11135
2967760c2415Smrg // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed
2968760c2415Smrg version (none) @system unittest
2969760c2415Smrg {
2970760c2415Smrg     foreach (T; AliasSeq!(float, double, real))
2971760c2415Smrg     {
2972760c2415Smrg         Nullable!(T, T.init) nf;
2973760c2415Smrg         //Initialized to "null" state
2974760c2415Smrg         assert(nf.isNull);
2975760c2415Smrg         assert(nf is typeof(nf).init);
2976760c2415Smrg 
2977760c2415Smrg         nf = 0;
2978760c2415Smrg         assert(!nf.isNull);
2979760c2415Smrg 
2980760c2415Smrg         nf.nullify();
2981760c2415Smrg         assert(nf.isNull);
2982760c2415Smrg     }
2983760c2415Smrg }
2984760c2415Smrg 
2985760c2415Smrg /**
2986760c2415Smrg Forces $(D this) to the null state.
2987760c2415Smrg  */
2988760c2415Smrg     void nullify()()
2989760c2415Smrg     {
2990760c2415Smrg         _value = nullValue;
2991760c2415Smrg     }
2992760c2415Smrg 
2993760c2415Smrg ///
2994760c2415Smrg @system unittest
2995760c2415Smrg {
2996760c2415Smrg     Nullable!(int, -1) ni = 0;
2997760c2415Smrg     assert(!ni.isNull);
2998760c2415Smrg 
2999760c2415Smrg     ni = -1;
3000760c2415Smrg     assert(ni.isNull);
3001760c2415Smrg }
3002760c2415Smrg 
3003760c2415Smrg /**
3004760c2415Smrg Assigns $(D value) to the internally-held state. If the assignment
3005760c2415Smrg succeeds, $(D this) becomes non-null. No null checks are made. Note
3006760c2415Smrg that the assignment may leave $(D this) in the null state.
3007760c2415Smrg 
3008760c2415Smrg Params:
3009760c2415Smrg     value = A value of type `T` to assign to this `Nullable`.
3010760c2415Smrg             If it is `nullvalue`, then the internal state of
3011760c2415Smrg             this `Nullable` will be set to null.
3012760c2415Smrg  */
3013760c2415Smrg     void opAssign()(T value)
3014760c2415Smrg     {
3015760c2415Smrg         _value = value;
3016760c2415Smrg     }
3017760c2415Smrg 
3018760c2415Smrg /**
3019760c2415Smrg     If this `Nullable` wraps a type that already has a null value
3020760c2415Smrg     (such as a pointer), and that null value is not given for
3021760c2415Smrg     `nullValue`, then assigning the null value to this `Nullable`
3022760c2415Smrg     is no different than assigning any other value of type `T`,
3023760c2415Smrg     and the resulting code will look very strange. It is strongly
3024760c2415Smrg     recommended that this be avoided by using `T`'s "built in"
3025760c2415Smrg     null value for `nullValue`.
3026760c2415Smrg  */
3027760c2415Smrg @system unittest
3028760c2415Smrg {
3029760c2415Smrg     //Passes
3030760c2415Smrg     enum nullVal = cast(int*) 0xCAFEBABE;
3031760c2415Smrg     Nullable!(int*, nullVal) npi;
3032760c2415Smrg     assert(npi.isNull);
3033760c2415Smrg 
3034760c2415Smrg     //Passes?!
3035760c2415Smrg     npi = null;
3036760c2415Smrg     assert(!npi.isNull);
3037760c2415Smrg }
3038760c2415Smrg 
3039760c2415Smrg /**
3040760c2415Smrg Gets the value. $(D this) must not be in the null state.
3041760c2415Smrg This function is also called for the implicit conversion to $(D T).
3042760c2415Smrg 
3043760c2415Smrg Returns:
3044760c2415Smrg     The value held internally by this `Nullable`.
3045760c2415Smrg  */
3046760c2415Smrg     @property ref inout(T) get() inout
3047760c2415Smrg     {
3048760c2415Smrg         //@@@6169@@@: We avoid any call that might evaluate nullValue's %s,
3049760c2415Smrg         //Because it might messup get's purity and safety inference.
3050760c2415Smrg         enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue).";
3051760c2415Smrg         assert(!isNull, message);
3052760c2415Smrg         return _value;
3053760c2415Smrg     }
3054760c2415Smrg 
3055760c2415Smrg ///
3056760c2415Smrg @system unittest
3057760c2415Smrg {
3058760c2415Smrg     import std.exception : assertThrown, assertNotThrown;
3059760c2415Smrg 
3060760c2415Smrg     Nullable!(int, -1) ni;
3061760c2415Smrg     //`get` is implicitly called. Will throw
3062760c2415Smrg     //an error in non-release mode
3063760c2415Smrg     assertThrown!Throwable(ni == 0);
3064760c2415Smrg 
3065760c2415Smrg     ni = 0;
3066760c2415Smrg     assertNotThrown!Throwable(ni == 0);
3067760c2415Smrg }
3068760c2415Smrg 
3069760c2415Smrg /**
3070760c2415Smrg Implicitly converts to $(D T).
3071760c2415Smrg $(D this) must not be in the null state.
3072760c2415Smrg  */
3073760c2415Smrg     alias get this;
3074760c2415Smrg }
3075760c2415Smrg 
3076760c2415Smrg /// ditto
3077760c2415Smrg auto nullable(alias nullValue, T)(T t)
3078760c2415Smrg     if (is (typeof(nullValue) == T))
3079760c2415Smrg {
3080760c2415Smrg     return Nullable!(T, nullValue)(t);
3081760c2415Smrg }
3082760c2415Smrg 
3083760c2415Smrg ///
3084760c2415Smrg @safe unittest
3085760c2415Smrg {
3086760c2415Smrg     Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle)
3087760c2415Smrg     {
3088760c2415Smrg         //Find the needle, returning -1 if not found
3089760c2415Smrg 
3090760c2415Smrg         return Nullable!(size_t, size_t.max).init;
3091760c2415Smrg     }
3092760c2415Smrg 
3093760c2415Smrg     void sendLunchInvite(string name)
3094760c2415Smrg     {
3095760c2415Smrg     }
3096760c2415Smrg 
3097760c2415Smrg     //It's safer than C...
3098760c2415Smrg     auto coworkers = ["Jane", "Jim", "Marry", "Fred"];
3099760c2415Smrg     auto pos = indexOf(coworkers, "Bob");
3100760c2415Smrg     if (!pos.isNull)
3101760c2415Smrg     {
3102760c2415Smrg         //Send Bob an invitation to lunch
3103760c2415Smrg         sendLunchInvite(coworkers[pos]);
3104760c2415Smrg     }
3105760c2415Smrg     else
3106760c2415Smrg     {
3107760c2415Smrg         //Bob not found; report the error
3108760c2415Smrg     }
3109760c2415Smrg 
3110760c2415Smrg     //And there's no overhead
3111760c2415Smrg     static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof);
3112760c2415Smrg }
3113760c2415Smrg 
3114760c2415Smrg ///
3115760c2415Smrg @system unittest
3116760c2415Smrg {
3117760c2415Smrg     import std.exception : assertThrown;
3118760c2415Smrg 
3119760c2415Smrg     Nullable!(int, int.min) a;
3120760c2415Smrg     assert(a.isNull);
3121760c2415Smrg     assertThrown!Throwable(a.get);
3122760c2415Smrg     a = 5;
3123760c2415Smrg     assert(!a.isNull);
3124760c2415Smrg     assert(a == 5);
3125760c2415Smrg     static assert(a.sizeof == int.sizeof);
3126760c2415Smrg }
3127760c2415Smrg 
3128760c2415Smrg ///
3129760c2415Smrg @safe unittest
3130760c2415Smrg {
3131760c2415Smrg     auto a = nullable!(int.min)(8);
3132760c2415Smrg     assert(a == 8);
3133760c2415Smrg     a.nullify();
3134760c2415Smrg     assert(a.isNull);
3135760c2415Smrg }
3136760c2415Smrg 
3137760c2415Smrg @safe unittest
3138760c2415Smrg {
3139760c2415Smrg     static int f(in Nullable!(int, int.min) x) {
3140760c2415Smrg         return x.isNull ? 42 : x.get;
3141760c2415Smrg     }
3142760c2415Smrg     Nullable!(int, int.min) a;
3143760c2415Smrg     assert(f(a) == 42);
3144760c2415Smrg     a = 8;
3145760c2415Smrg     assert(f(a) == 8);
3146760c2415Smrg     a.nullify();
3147760c2415Smrg     assert(f(a) == 42);
3148760c2415Smrg }
3149760c2415Smrg @safe unittest
3150760c2415Smrg {
3151760c2415Smrg     // Ensure Nullable can be used in pure/nothrow/@safe environment.
3152760c2415Smrg     function() @safe pure nothrow
3153760c2415Smrg     {
3154760c2415Smrg         Nullable!(int, int.min) n;
3155760c2415Smrg         assert(n.isNull);
3156760c2415Smrg         n = 4;
3157760c2415Smrg         assert(!n.isNull);
3158760c2415Smrg         assert(n == 4);
3159760c2415Smrg         n.nullify();
3160760c2415Smrg         assert(n.isNull);
3161760c2415Smrg     }();
3162760c2415Smrg }
3163760c2415Smrg @system unittest
3164760c2415Smrg {
3165760c2415Smrg     // Ensure Nullable can be used when the value is not pure/nothrow/@system
3166760c2415Smrg     static struct S
3167760c2415Smrg     {
3168760c2415Smrg         int x;
3169760c2415Smrg         bool opEquals(const S s) const @system { return s.x == x; }
3170760c2415Smrg     }
3171760c2415Smrg 
3172760c2415Smrg     Nullable!(S, S(711)) s;
3173760c2415Smrg     assert(s.isNull);
3174760c2415Smrg     s = S(5);
3175760c2415Smrg     assert(!s.isNull);
3176760c2415Smrg     assert(s.x == 5);
3177760c2415Smrg     s.nullify();
3178760c2415Smrg     assert(s.isNull);
3179760c2415Smrg }
3180760c2415Smrg @safe unittest
3181760c2415Smrg {
3182760c2415Smrg     //Check nullable is nicelly embedable in a struct
3183760c2415Smrg     static struct S1
3184760c2415Smrg     {
3185760c2415Smrg         Nullable!(int, 0) ni;
3186760c2415Smrg     }
3187760c2415Smrg     static struct S2 //inspired from 9404
3188760c2415Smrg     {
3189760c2415Smrg         Nullable!(int, 0) ni;
3190760c2415Smrg         this(S2 other)
3191760c2415Smrg         {
3192760c2415Smrg             ni = other.ni;
3193760c2415Smrg         }
3194760c2415Smrg         void opAssign(S2 other)
3195760c2415Smrg         {
3196760c2415Smrg             ni = other.ni;
3197760c2415Smrg         }
3198760c2415Smrg     }
3199760c2415Smrg     foreach (S; AliasSeq!(S1, S2))
3200760c2415Smrg     {
3201760c2415Smrg         S a;
3202760c2415Smrg         S b = a;
3203760c2415Smrg         S c;
3204760c2415Smrg         c = a;
3205760c2415Smrg     }
3206760c2415Smrg }
3207760c2415Smrg @system unittest
3208760c2415Smrg {
3209760c2415Smrg     import std.conv : to;
3210760c2415Smrg 
3211760c2415Smrg     // Bugzilla 10915
3212760c2415Smrg     Nullable!(int, 1) ni = 1;
3213760c2415Smrg     assert(ni.to!string() == "Nullable.null");
3214760c2415Smrg 
3215760c2415Smrg     struct Test { string s; }
3216760c2415Smrg     alias NullableTest = Nullable!(Test, Test("null"));
3217760c2415Smrg 
3218760c2415Smrg     NullableTest nt = Test("test");
3219760c2415Smrg     assert(nt.to!string() == `Test("test")`);
3220760c2415Smrg 
3221760c2415Smrg     NullableTest ntn = Test("null");
3222760c2415Smrg     assert(ntn.to!string() == "Nullable.null");
3223760c2415Smrg 
3224760c2415Smrg     class TestToString
3225760c2415Smrg     {
3226760c2415Smrg         double d;
3227760c2415Smrg 
3228760c2415Smrg         this(double d)
3229760c2415Smrg         {
3230760c2415Smrg             this.d = d;
3231760c2415Smrg         }
3232760c2415Smrg 
3233760c2415Smrg         override string toString()
3234760c2415Smrg         {
3235760c2415Smrg             return d.to!string();
3236760c2415Smrg         }
3237760c2415Smrg     }
3238760c2415Smrg     alias NullableTestToString = Nullable!(TestToString, null);
3239760c2415Smrg 
3240760c2415Smrg     NullableTestToString ntts = new TestToString(2.5);
3241760c2415Smrg     assert(ntts.to!string() == "2.5");
3242760c2415Smrg }
3243760c2415Smrg 
3244760c2415Smrg 
3245760c2415Smrg /**
3246760c2415Smrg Just like $(D Nullable!T), except that the object refers to a value
3247760c2415Smrg sitting elsewhere in memory. This makes assignments overwrite the
3248760c2415Smrg initially assigned value. Internally $(D NullableRef!T) only stores a
3249760c2415Smrg pointer to $(D T) (i.e., $(D Nullable!T.sizeof == (T*).sizeof)).
3250760c2415Smrg  */
3251760c2415Smrg struct NullableRef(T)
3252760c2415Smrg {
3253760c2415Smrg     private T* _value;
3254760c2415Smrg 
3255760c2415Smrg /**
3256760c2415Smrg Constructor binding $(D this) to $(D value).
3257760c2415Smrg 
3258760c2415Smrg Params:
3259760c2415Smrg     value = The value to bind to.
3260760c2415Smrg  */
3261760c2415Smrg     this(T* value) @safe pure nothrow
3262760c2415Smrg     {
3263760c2415Smrg         _value = value;
3264760c2415Smrg     }
3265760c2415Smrg 
3266760c2415Smrg     template toString()
3267760c2415Smrg     {
3268760c2415Smrg         import std.format : FormatSpec, formatValue;
3269760c2415Smrg         // Needs to be a template because of DMD @@BUG@@ 13737.
3270760c2415Smrg         void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
3271760c2415Smrg         {
3272760c2415Smrg             if (isNull)
3273760c2415Smrg             {
3274760c2415Smrg                 sink.formatValue("Nullable.null", fmt);
3275760c2415Smrg             }
3276760c2415Smrg             else
3277760c2415Smrg             {
3278760c2415Smrg                 sink.formatValue(*_value, fmt);
3279760c2415Smrg             }
3280760c2415Smrg         }
3281760c2415Smrg     }
3282760c2415Smrg 
3283760c2415Smrg /**
3284760c2415Smrg Binds the internal state to $(D value).
3285760c2415Smrg 
3286760c2415Smrg Params:
3287760c2415Smrg     value = A pointer to a value of type `T` to bind this `NullableRef` to.
3288760c2415Smrg  */
3289760c2415Smrg     void bind(T* value) @safe pure nothrow
3290760c2415Smrg     {
3291760c2415Smrg         _value = value;
3292760c2415Smrg     }
3293760c2415Smrg 
3294760c2415Smrg     ///
3295760c2415Smrg     @safe unittest
3296760c2415Smrg     {
3297760c2415Smrg         NullableRef!int nr = new int(42);
3298760c2415Smrg         assert(nr == 42);
3299760c2415Smrg 
3300760c2415Smrg         int* n = new int(1);
3301760c2415Smrg         nr.bind(n);
3302760c2415Smrg         assert(nr == 1);
3303760c2415Smrg     }
3304760c2415Smrg 
3305760c2415Smrg /**
3306760c2415Smrg Returns $(D true) if and only if $(D this) is in the null state.
3307760c2415Smrg 
3308760c2415Smrg Returns:
3309760c2415Smrg     true if `this` is in the null state, otherwise false.
3310760c2415Smrg  */
3311760c2415Smrg     @property bool isNull() const @safe pure nothrow
3312760c2415Smrg     {
3313760c2415Smrg         return _value is null;
3314760c2415Smrg     }
3315760c2415Smrg 
3316760c2415Smrg     ///
3317760c2415Smrg     @safe unittest
3318760c2415Smrg     {
3319760c2415Smrg         NullableRef!int nr;
3320760c2415Smrg         assert(nr.isNull);
3321760c2415Smrg 
3322760c2415Smrg         int* n = new int(42);
3323760c2415Smrg         nr.bind(n);
3324760c2415Smrg         assert(!nr.isNull && nr == 42);
3325760c2415Smrg     }
3326760c2415Smrg 
3327760c2415Smrg /**
3328760c2415Smrg Forces $(D this) to the null state.
3329760c2415Smrg  */
3330760c2415Smrg     void nullify() @safe pure nothrow
3331760c2415Smrg     {
3332760c2415Smrg         _value = null;
3333760c2415Smrg     }
3334760c2415Smrg 
3335760c2415Smrg     ///
3336760c2415Smrg     @safe unittest
3337760c2415Smrg     {
3338760c2415Smrg         NullableRef!int nr = new int(42);
3339760c2415Smrg         assert(!nr.isNull);
3340760c2415Smrg 
3341760c2415Smrg         nr.nullify();
3342760c2415Smrg         assert(nr.isNull);
3343760c2415Smrg     }
3344760c2415Smrg 
3345760c2415Smrg /**
3346760c2415Smrg Assigns $(D value) to the internally-held state.
3347760c2415Smrg 
3348760c2415Smrg Params:
3349760c2415Smrg     value = A value of type `T` to assign to this `NullableRef`.
3350760c2415Smrg             If the internal state of this `NullableRef` has not
3351760c2415Smrg             been initialized, an error will be thrown in
3352760c2415Smrg             non-release mode.
3353760c2415Smrg  */
3354760c2415Smrg     void opAssign()(T value)
3355760c2415Smrg         if (isAssignable!T) //@@@9416@@@
3356760c2415Smrg     {
3357760c2415Smrg         enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ ".";
3358760c2415Smrg         assert(!isNull, message);
3359760c2415Smrg         *_value = value;
3360760c2415Smrg     }
3361760c2415Smrg 
3362760c2415Smrg     ///
3363760c2415Smrg     @system unittest
3364760c2415Smrg     {
3365760c2415Smrg         import std.exception : assertThrown, assertNotThrown;
3366760c2415Smrg 
3367760c2415Smrg         NullableRef!int nr;
3368760c2415Smrg         assert(nr.isNull);
3369760c2415Smrg         assertThrown!Throwable(nr = 42);
3370760c2415Smrg 
3371760c2415Smrg         nr.bind(new int(0));
3372760c2415Smrg         assert(!nr.isNull);
3373760c2415Smrg         assertNotThrown!Throwable(nr = 42);
3374760c2415Smrg         assert(nr == 42);
3375760c2415Smrg     }
3376760c2415Smrg 
3377760c2415Smrg /**
3378760c2415Smrg Gets the value. $(D this) must not be in the null state.
3379760c2415Smrg This function is also called for the implicit conversion to $(D T).
3380760c2415Smrg  */
3381760c2415Smrg     @property ref inout(T) get() inout @safe pure nothrow
3382760c2415Smrg     {
3383760c2415Smrg         enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ ".";
3384760c2415Smrg         assert(!isNull, message);
3385760c2415Smrg         return *_value;
3386760c2415Smrg     }
3387760c2415Smrg 
3388760c2415Smrg     ///
3389760c2415Smrg     @system unittest
3390760c2415Smrg     {
3391760c2415Smrg         import std.exception : assertThrown, assertNotThrown;
3392760c2415Smrg 
3393760c2415Smrg         NullableRef!int nr;
3394760c2415Smrg         //`get` is implicitly called. Will throw
3395760c2415Smrg         //an error in non-release mode
3396760c2415Smrg         assertThrown!Throwable(nr == 0);
3397760c2415Smrg 
3398760c2415Smrg         nr.bind(new int(0));
3399760c2415Smrg         assertNotThrown!Throwable(nr == 0);
3400760c2415Smrg     }
3401760c2415Smrg 
3402760c2415Smrg /**
3403760c2415Smrg Implicitly converts to $(D T).
3404760c2415Smrg $(D this) must not be in the null state.
3405760c2415Smrg  */
3406760c2415Smrg     alias get this;
3407760c2415Smrg }
3408760c2415Smrg 
3409760c2415Smrg /// ditto
3410760c2415Smrg auto nullableRef(T)(T* t)
3411760c2415Smrg {
3412760c2415Smrg     return NullableRef!T(t);
3413760c2415Smrg }
3414760c2415Smrg 
3415760c2415Smrg ///
3416760c2415Smrg @system unittest
3417760c2415Smrg {
3418760c2415Smrg     import std.exception : assertThrown;
3419760c2415Smrg 
3420760c2415Smrg     int x = 5, y = 7;
3421760c2415Smrg     auto a = nullableRef(&x);
3422760c2415Smrg     assert(!a.isNull);
3423760c2415Smrg     assert(a == 5);
3424760c2415Smrg     assert(x == 5);
3425760c2415Smrg     a = 42;
3426760c2415Smrg     assert(x == 42);
3427760c2415Smrg     assert(!a.isNull);
3428760c2415Smrg     assert(a == 42);
3429760c2415Smrg     a.nullify();
3430760c2415Smrg     assert(x == 42);
3431760c2415Smrg     assert(a.isNull);
3432760c2415Smrg     assertThrown!Throwable(a.get);
3433760c2415Smrg     assertThrown!Throwable(a = 71);
3434760c2415Smrg     a.bind(&y);
3435760c2415Smrg     assert(a == 7);
3436760c2415Smrg     y = 135;
3437760c2415Smrg     assert(a == 135);
3438760c2415Smrg }
3439760c2415Smrg @system unittest
3440760c2415Smrg {
3441760c2415Smrg     static int f(in NullableRef!int x) {
3442760c2415Smrg         return x.isNull ? 42 : x.get;
3443760c2415Smrg     }
3444760c2415Smrg     int x = 5;
3445760c2415Smrg     auto a = nullableRef(&x);
3446760c2415Smrg     assert(f(a) == 5);
3447760c2415Smrg     a.nullify();
3448760c2415Smrg     assert(f(a) == 42);
3449760c2415Smrg }
3450760c2415Smrg @safe unittest
3451760c2415Smrg {
3452760c2415Smrg     // Ensure NullableRef can be used in pure/nothrow/@safe environment.
3453760c2415Smrg     function() @safe pure nothrow
3454760c2415Smrg     {
3455760c2415Smrg         auto storage = new int;
3456760c2415Smrg         *storage = 19902;
3457760c2415Smrg         NullableRef!int n;
3458760c2415Smrg         assert(n.isNull);
3459760c2415Smrg         n.bind(storage);
3460760c2415Smrg         assert(!n.isNull);
3461760c2415Smrg         assert(n == 19902);
3462760c2415Smrg         n = 2294;
3463760c2415Smrg         assert(n == 2294);
3464760c2415Smrg         assert(*storage == 2294);
3465760c2415Smrg         n.nullify();
3466760c2415Smrg         assert(n.isNull);
3467760c2415Smrg     }();
3468760c2415Smrg }
3469760c2415Smrg @system unittest
3470760c2415Smrg {
3471760c2415Smrg     // Ensure NullableRef can be used when the value is not pure/nothrow/@safe
3472760c2415Smrg     static struct S
3473760c2415Smrg     {
3474760c2415Smrg         int x;
3475760c2415Smrg         this(this) @system {}
3476760c2415Smrg         bool opEquals(const S s) const @system { return s.x == x; }
3477760c2415Smrg     }
3478760c2415Smrg 
3479760c2415Smrg     auto storage = S(5);
3480760c2415Smrg 
3481760c2415Smrg     NullableRef!S s;
3482760c2415Smrg     assert(s.isNull);
3483760c2415Smrg     s.bind(&storage);
3484760c2415Smrg     assert(!s.isNull);
3485760c2415Smrg     assert(s.x == 5);
3486760c2415Smrg     s.nullify();
3487760c2415Smrg     assert(s.isNull);
3488760c2415Smrg }
3489760c2415Smrg @safe unittest
3490760c2415Smrg {
3491760c2415Smrg     //Check nullable is nicelly embedable in a struct
3492760c2415Smrg     static struct S1
3493760c2415Smrg     {
3494760c2415Smrg         NullableRef!int ni;
3495760c2415Smrg     }
3496760c2415Smrg     static struct S2 //inspired from 9404
3497760c2415Smrg     {
3498760c2415Smrg         NullableRef!int ni;
3499760c2415Smrg         this(S2 other)
3500760c2415Smrg         {
3501760c2415Smrg             ni = other.ni;
3502760c2415Smrg         }
3503760c2415Smrg         void opAssign(S2 other)
3504760c2415Smrg         {
3505760c2415Smrg             ni = other.ni;
3506760c2415Smrg         }
3507760c2415Smrg     }
3508760c2415Smrg     foreach (S; AliasSeq!(S1, S2))
3509760c2415Smrg     {
3510760c2415Smrg         S a;
3511760c2415Smrg         S b = a;
3512760c2415Smrg         S c;
3513760c2415Smrg         c = a;
3514760c2415Smrg     }
3515760c2415Smrg }
3516760c2415Smrg @system unittest
3517760c2415Smrg {
3518760c2415Smrg     import std.conv : to;
3519760c2415Smrg 
3520760c2415Smrg     // Bugzilla 10915
3521760c2415Smrg     NullableRef!int nri;
3522760c2415Smrg     assert(nri.to!string() == "Nullable.null");
3523760c2415Smrg 
3524760c2415Smrg     struct Test
3525760c2415Smrg     {
3526760c2415Smrg         string s;
3527760c2415Smrg     }
3528760c2415Smrg     NullableRef!Test nt = new Test("test");
3529760c2415Smrg     assert(nt.to!string() == `Test("test")`);
3530760c2415Smrg 
3531760c2415Smrg     class TestToString
3532760c2415Smrg     {
3533760c2415Smrg         double d;
3534760c2415Smrg 
3535760c2415Smrg         this(double d)
3536760c2415Smrg         {
3537760c2415Smrg             this.d = d;
3538760c2415Smrg         }
3539760c2415Smrg 
3540760c2415Smrg         override string toString()
3541760c2415Smrg         {
3542760c2415Smrg             return d.to!string();
3543760c2415Smrg         }
3544760c2415Smrg     }
3545760c2415Smrg     TestToString tts = new TestToString(2.5);
3546760c2415Smrg     NullableRef!TestToString ntts = &tts;
3547760c2415Smrg     assert(ntts.to!string() == "2.5");
3548760c2415Smrg }
3549760c2415Smrg 
3550760c2415Smrg 
3551760c2415Smrg /**
3552760c2415Smrg $(D BlackHole!Base) is a subclass of $(D Base) which automatically implements
3553760c2415Smrg all abstract member functions in $(D Base) as do-nothing functions.  Each
3554760c2415Smrg auto-implemented function just returns the default value of the return type
3555760c2415Smrg without doing anything.
3556760c2415Smrg 
3557760c2415Smrg The name came from
3558760c2415Smrg $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole)
3559760c2415Smrg Perl module by Sean M. Burke.
3560760c2415Smrg 
3561760c2415Smrg Params:
3562760c2415Smrg     Base = A non-final class for `BlackHole` to inherit from.
3563760c2415Smrg 
3564760c2415Smrg See_Also:
3565760c2415Smrg   $(LREF AutoImplement), $(LREF generateEmptyFunction)
3566760c2415Smrg  */
3567760c2415Smrg alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction);
3568760c2415Smrg 
3569760c2415Smrg ///
3570760c2415Smrg @system unittest
3571760c2415Smrg {
3572760c2415Smrg     import std.math : isNaN;
3573760c2415Smrg 
3574760c2415Smrg     static abstract class C
3575760c2415Smrg     {
3576760c2415Smrg         int m_value;
3577760c2415Smrg         this(int v) { m_value = v; }
3578760c2415Smrg         int value() @property { return m_value; }
3579760c2415Smrg 
3580760c2415Smrg         abstract real realValue() @property;
3581760c2415Smrg         abstract void doSomething();
3582760c2415Smrg     }
3583760c2415Smrg 
3584760c2415Smrg     auto c = new BlackHole!C(42);
3585760c2415Smrg     assert(c.value == 42);
3586760c2415Smrg 
3587760c2415Smrg     // Returns real.init which is NaN
3588760c2415Smrg     assert(c.realValue.isNaN);
3589760c2415Smrg     // Abstract functions are implemented as do-nothing
3590760c2415Smrg     c.doSomething();
3591760c2415Smrg }
3592760c2415Smrg 
3593760c2415Smrg @system unittest
3594760c2415Smrg {
3595760c2415Smrg     import std.math : isNaN;
3596760c2415Smrg 
3597760c2415Smrg     // return default
3598760c2415Smrg     {
3599760c2415Smrg         interface I_1 { real test(); }
3600760c2415Smrg         auto o = new BlackHole!I_1;
3601760c2415Smrg         assert(o.test().isNaN()); // NaN
3602760c2415Smrg     }
3603760c2415Smrg     // doc example
3604760c2415Smrg     {
3605760c2415Smrg         static class C
3606760c2415Smrg         {
3607760c2415Smrg             int m_value;
3608760c2415Smrg             this(int v) { m_value = v; }
3609760c2415Smrg             int value() @property { return m_value; }
3610760c2415Smrg 
3611760c2415Smrg             abstract real realValue() @property;
3612760c2415Smrg             abstract void doSomething();
3613760c2415Smrg         }
3614760c2415Smrg 
3615760c2415Smrg         auto c = new BlackHole!C(42);
3616760c2415Smrg         assert(c.value == 42);
3617760c2415Smrg 
3618760c2415Smrg         assert(c.realValue.isNaN); // NaN
3619760c2415Smrg         c.doSomething();
3620760c2415Smrg     }
3621760c2415Smrg 
3622760c2415Smrg     // Bugzilla 12058
3623760c2415Smrg     interface Foo
3624760c2415Smrg     {
3625760c2415Smrg         inout(Object) foo() inout;
3626760c2415Smrg     }
3627760c2415Smrg     BlackHole!Foo o;
3628760c2415Smrg }
3629760c2415Smrg 
3630760c2415Smrg 
3631760c2415Smrg /**
3632760c2415Smrg $(D WhiteHole!Base) is a subclass of $(D Base) which automatically implements
3633760c2415Smrg all abstract member functions as functions that always fail. These functions
3634760c2415Smrg simply throw an $(D Error) and never return. `Whitehole` is useful for
3635760c2415Smrg trapping the use of class member functions that haven't been implemented.
3636760c2415Smrg 
3637760c2415Smrg The name came from
3638760c2415Smrg $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole)
3639760c2415Smrg Perl module by Michael G Schwern.
3640760c2415Smrg 
3641760c2415Smrg Params:
3642760c2415Smrg     Base = A non-final class for `WhiteHole` to inherit from.
3643760c2415Smrg 
3644760c2415Smrg See_Also:
3645760c2415Smrg   $(LREF AutoImplement), $(LREF generateAssertTrap)
3646760c2415Smrg  */
3647760c2415Smrg alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction);
3648760c2415Smrg 
3649760c2415Smrg ///
3650760c2415Smrg @system unittest
3651760c2415Smrg {
3652760c2415Smrg     import std.exception : assertThrown;
3653760c2415Smrg 
3654760c2415Smrg     static class C
3655760c2415Smrg     {
3656760c2415Smrg         abstract void notYetImplemented();
3657760c2415Smrg     }
3658760c2415Smrg 
3659760c2415Smrg     auto c = new WhiteHole!C;
3660760c2415Smrg     assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error
3661760c2415Smrg }
3662760c2415Smrg 
3663760c2415Smrg // / ditto
3664760c2415Smrg class NotImplementedError : Error
3665760c2415Smrg {
3666760c2415Smrg     this(string method)
3667760c2415Smrg     {
3668760c2415Smrg         super(method ~ " is not implemented");
3669760c2415Smrg     }
3670760c2415Smrg }
3671760c2415Smrg 
3672760c2415Smrg @system unittest
3673760c2415Smrg {
3674760c2415Smrg     import std.exception : assertThrown;
3675760c2415Smrg     // nothrow
3676760c2415Smrg     {
3677760c2415Smrg         interface I_1
3678760c2415Smrg         {
3679760c2415Smrg             void foo();
3680760c2415Smrg             void bar() nothrow;
3681760c2415Smrg         }
3682760c2415Smrg         auto o = new WhiteHole!I_1;
3683760c2415Smrg         assertThrown!NotImplementedError(o.foo());
3684760c2415Smrg         assertThrown!NotImplementedError(o.bar());
3685760c2415Smrg     }
3686760c2415Smrg     // doc example
3687760c2415Smrg     {
3688760c2415Smrg         static class C
3689760c2415Smrg         {
3690760c2415Smrg             abstract void notYetImplemented();
3691760c2415Smrg         }
3692760c2415Smrg 
3693760c2415Smrg         auto c = new WhiteHole!C;
3694760c2415Smrg         try
3695760c2415Smrg         {
3696760c2415Smrg             c.notYetImplemented();
3697760c2415Smrg             assert(0);
3698760c2415Smrg         }
3699760c2415Smrg         catch (Error e) {}
3700760c2415Smrg     }
3701760c2415Smrg }
3702760c2415Smrg 
3703760c2415Smrg 
3704760c2415Smrg /**
3705760c2415Smrg $(D AutoImplement) automatically implements (by default) all abstract member
3706760c2415Smrg functions in the class or interface $(D Base) in specified way.
3707760c2415Smrg 
3708760c2415Smrg The second version of $(D AutoImplement) automatically implements
3709760c2415Smrg $(D Interface), while deriving from $(D BaseClass).
3710760c2415Smrg 
3711760c2415Smrg Params:
3712760c2415Smrg   how  = template which specifies _how functions will be implemented/overridden.
3713760c2415Smrg 
3714760c2415Smrg          Two arguments are passed to $(D how): the type $(D Base) and an alias
3715760c2415Smrg          to an implemented function.  Then $(D how) must return an implemented
3716760c2415Smrg          function body as a string.
3717760c2415Smrg 
3718760c2415Smrg          The generated function body can use these keywords:
3719760c2415Smrg          $(UL
3720760c2415Smrg             $(LI $(D a0), $(D a1), &hellip;: arguments passed to the function;)
3721760c2415Smrg             $(LI $(D args): a tuple of the arguments;)
3722760c2415Smrg             $(LI $(D self): an alias to the function itself;)
3723760c2415Smrg             $(LI $(D parent): an alias to the overridden function (if any).)
3724760c2415Smrg          )
3725760c2415Smrg 
3726760c2415Smrg         You may want to use templated property functions (instead of Implicit
3727760c2415Smrg         Template Properties) to generate complex functions:
3728760c2415Smrg --------------------
3729760c2415Smrg // Prints log messages for each call to overridden functions.
3730760c2415Smrg string generateLogger(C, alias fun)() @property
3731760c2415Smrg {
3732760c2415Smrg     import std.traits;
3733760c2415Smrg     enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
3734760c2415Smrg     string stmt;
3735760c2415Smrg 
3736760c2415Smrg     stmt ~= q{ struct Importer { import std.stdio; } };
3737760c2415Smrg     stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
3738760c2415Smrg     static if (!__traits(isAbstractFunction, fun))
3739760c2415Smrg     {
3740760c2415Smrg         static if (is(ReturnType!fun == void))
3741760c2415Smrg             stmt ~= q{ parent(args); };
3742760c2415Smrg         else
3743760c2415Smrg             stmt ~= q{
3744760c2415Smrg                 auto r = parent(args);
3745760c2415Smrg                 Importer.writeln("--> ", r);
3746760c2415Smrg                 return r;
3747760c2415Smrg             };
3748760c2415Smrg     }
3749760c2415Smrg     return stmt;
3750760c2415Smrg }
3751760c2415Smrg --------------------
3752760c2415Smrg 
3753760c2415Smrg   what = template which determines _what functions should be
3754760c2415Smrg          implemented/overridden.
3755760c2415Smrg 
3756760c2415Smrg          An argument is passed to $(D what): an alias to a non-final member
3757760c2415Smrg          function in $(D Base).  Then $(D what) must return a boolean value.
3758760c2415Smrg          Return $(D true) to indicate that the passed function should be
3759760c2415Smrg          implemented/overridden.
3760760c2415Smrg 
3761760c2415Smrg --------------------
3762760c2415Smrg // Sees if fun returns something.
3763760c2415Smrg enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
3764760c2415Smrg --------------------
3765760c2415Smrg 
3766760c2415Smrg 
3767760c2415Smrg Note:
3768760c2415Smrg 
3769760c2415Smrg Generated code is inserted in the scope of $(D std.typecons) module.  Thus,
3770760c2415Smrg any useful functions outside $(D std.typecons) cannot be used in the generated
3771760c2415Smrg code.  To workaround this problem, you may $(D import) necessary things in a
3772760c2415Smrg local struct, as done in the $(D generateLogger()) template in the above
3773760c2415Smrg example.
3774760c2415Smrg 
3775760c2415Smrg 
3776760c2415Smrg BUGS:
3777760c2415Smrg 
3778760c2415Smrg $(UL
3779760c2415Smrg  $(LI Variadic arguments to constructors are not forwarded to super.)
3780760c2415Smrg  $(LI Deep interface inheritance causes compile error with messages like
3781760c2415Smrg       "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar
3782760c2415Smrg       does not override any function".  [$(BUGZILLA 2525), $(BUGZILLA 3525)] )
3783760c2415Smrg  $(LI The $(D parent) keyword is actually a delegate to the super class'
3784760c2415Smrg       corresponding member function.  [$(BUGZILLA 2540)] )
3785760c2415Smrg  $(LI Using alias template parameter in $(D how) and/or $(D what) may cause
3786760c2415Smrg      strange compile error.  Use template tuple parameter instead to workaround
3787760c2415Smrg      this problem.  [$(BUGZILLA 4217)] )
3788760c2415Smrg )
3789760c2415Smrg  */
3790760c2415Smrg class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base
3791760c2415Smrg     if (!is(how == class))
3792760c2415Smrg {
3793760c2415Smrg     private alias autoImplement_helper_ =
3794760c2415Smrg         AutoImplement_Helper!("autoImplement_helper_", "Base", Base, typeof(this), how, what);
3795760c2415Smrg     mixin(autoImplement_helper_.code);
3796760c2415Smrg }
3797760c2415Smrg 
3798760c2415Smrg /// ditto
3799760c2415Smrg class AutoImplement(
3800760c2415Smrg     Interface, BaseClass, alias how,
3801760c2415Smrg     alias what = isAbstractFunction) : BaseClass, Interface
3802760c2415Smrg     if (is(Interface == interface) && is(BaseClass == class))
3803760c2415Smrg {
3804760c2415Smrg     private alias autoImplement_helper_ = AutoImplement_Helper!(
3805760c2415Smrg             "autoImplement_helper_", "Interface", Interface, typeof(this), how, what);
3806760c2415Smrg     mixin(autoImplement_helper_.code);
3807760c2415Smrg }
3808760c2415Smrg 
3809760c2415Smrg /*
3810760c2415Smrg  * Code-generating stuffs are encupsulated in this helper template so that
3811760c2415Smrg  * namespace pollution, which can cause name confliction with Base's public
3812760c2415Smrg  * members, should be minimized.
3813760c2415Smrg  */
3814760c2415Smrg private template AutoImplement_Helper(string myName, string baseName,
3815760c2415Smrg         Base, Self, alias generateMethodBody, alias cherrypickMethod)
3816760c2415Smrg {
3817760c2415Smrg private static:
3818760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3819760c2415Smrg     // Internal stuffs
3820760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3821760c2415Smrg 
3822760c2415Smrg     // Returns function overload sets in the class C, filtered with pred.
3823760c2415Smrg     template enumerateOverloads(C, alias pred)
3824760c2415Smrg     {
3825760c2415Smrg         template Impl(names...)
3826760c2415Smrg         {
3827760c2415Smrg             import std.meta : Filter;
3828760c2415Smrg             static if (names.length > 0)
3829760c2415Smrg             {
3830760c2415Smrg                 alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0]));
3831760c2415Smrg                 alias next = Impl!(names[1 .. $]);
3832760c2415Smrg 
3833760c2415Smrg                 static if (methods.length > 0)
3834760c2415Smrg                     alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next);
3835760c2415Smrg                 else
3836760c2415Smrg                     alias Impl = next;
3837760c2415Smrg             }
3838760c2415Smrg             else
3839760c2415Smrg                 alias Impl = AliasSeq!();
3840760c2415Smrg         }
3841760c2415Smrg 
3842760c2415Smrg         alias enumerateOverloads = Impl!(__traits(allMembers, C));
3843760c2415Smrg     }
3844760c2415Smrg 
3845760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3846760c2415Smrg     // Target functions
3847760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3848760c2415Smrg 
3849760c2415Smrg     // Add a non-final check to the cherrypickMethod.
3850760c2415Smrg     enum bool canonicalPicker(fun.../+[BUG 4217]+/) =
3851760c2415Smrg         !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun);
3852760c2415Smrg 
3853760c2415Smrg     /*
3854760c2415Smrg      * A tuple of overload sets, each item of which consists of functions to be
3855760c2415Smrg      * implemented by the generated code.
3856760c2415Smrg      */
3857760c2415Smrg     alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker);
3858760c2415Smrg 
3859760c2415Smrg     /*
3860760c2415Smrg      * Super class of this AutoImplement instance
3861760c2415Smrg      */
3862760c2415Smrg     alias Super = BaseTypeTuple!(Self)[0];
3863760c2415Smrg     static assert(is(Super == class));
3864760c2415Smrg     static assert(is(Base == interface) || is(Super == Base));
3865760c2415Smrg 
3866760c2415Smrg     /*
3867760c2415Smrg      * A tuple of the super class' constructors.  Used for forwarding
3868760c2415Smrg      * constructor calls.
3869760c2415Smrg      */
3870760c2415Smrg     static if (__traits(hasMember, Super, "__ctor"))
3871760c2415Smrg         alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Super, "__ctor"));
3872760c2415Smrg     else
3873760c2415Smrg         alias ctorOverloadSet = OverloadSet!("__ctor"); // empty
3874760c2415Smrg 
3875760c2415Smrg 
3876760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3877760c2415Smrg     // Type information
3878760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3879760c2415Smrg 
3880760c2415Smrg     /*
3881760c2415Smrg      * The generated code will be mixed into AutoImplement, which will be
3882760c2415Smrg      * instantiated in this module's scope.  Thus, any user-defined types are
3883760c2415Smrg      * out of scope and cannot be used directly (i.e. by their names).
3884760c2415Smrg      *
3885760c2415Smrg      * We will use FuncInfo instances for accessing return types and parameter
3886760c2415Smrg      * types of the implemented functions.  The instances will be populated to
3887760c2415Smrg      * the AutoImplement's scope in a certain way; see the populate() below.
3888760c2415Smrg      */
3889760c2415Smrg 
3890760c2415Smrg     // Returns the preferred identifier for the FuncInfo instance for the i-th
3891760c2415Smrg     // overloaded function with the name.
3892760c2415Smrg     template INTERNAL_FUNCINFO_ID(string name, size_t i)
3893760c2415Smrg     {
3894760c2415Smrg         import std.format : format;
3895760c2415Smrg 
3896760c2415Smrg         enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i);
3897760c2415Smrg     }
3898760c2415Smrg 
3899760c2415Smrg     /*
3900760c2415Smrg      * Insert FuncInfo instances about all the target functions here.  This
3901760c2415Smrg      * enables the generated code to access type information via, for example,
3902760c2415Smrg      * "autoImplement_helper_.F_foo_1".
3903760c2415Smrg      */
3904760c2415Smrg     template populate(overloads...)
3905760c2415Smrg     {
3906760c2415Smrg         static if (overloads.length > 0)
3907760c2415Smrg         {
3908760c2415Smrg             mixin populate!(overloads[0].name, overloads[0].contents);
3909760c2415Smrg             mixin populate!(overloads[1 .. $]);
3910760c2415Smrg         }
3911760c2415Smrg     }
3912760c2415Smrg     template populate(string name, methods...)
3913760c2415Smrg     {
3914760c2415Smrg         static if (methods.length > 0)
3915760c2415Smrg         {
3916760c2415Smrg             mixin populate!(name, methods[0 .. $ - 1]);
3917760c2415Smrg             //
3918760c2415Smrg             alias target = methods[$ - 1];
3919760c2415Smrg             enum ith = methods.length - 1;
3920760c2415Smrg             mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;");
3921760c2415Smrg         }
3922760c2415Smrg     }
3923760c2415Smrg 
3924760c2415Smrg     public mixin populate!(targetOverloadSets);
3925760c2415Smrg     public mixin populate!(  ctorOverloadSet );
3926760c2415Smrg 
3927760c2415Smrg 
3928760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3929760c2415Smrg     // Code-generating policies
3930760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3931760c2415Smrg 
3932760c2415Smrg     /* Common policy configurations for generating constructors and methods. */
3933760c2415Smrg     template CommonGeneratingPolicy()
3934760c2415Smrg     {
3935760c2415Smrg         // base class identifier which generated code should use
3936760c2415Smrg         enum string BASE_CLASS_ID = baseName;
3937760c2415Smrg 
3938760c2415Smrg         // FuncInfo instance identifier which generated code should use
3939760c2415Smrg         template FUNCINFO_ID(string name, size_t i)
3940760c2415Smrg         {
3941760c2415Smrg             enum string FUNCINFO_ID =
3942760c2415Smrg                 myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i);
3943760c2415Smrg         }
3944760c2415Smrg     }
3945760c2415Smrg 
3946760c2415Smrg     /* Policy configurations for generating constructors. */
3947760c2415Smrg     template ConstructorGeneratingPolicy()
3948760c2415Smrg     {
3949760c2415Smrg         mixin CommonGeneratingPolicy;
3950760c2415Smrg 
3951760c2415Smrg         /* Generates constructor body.  Just forward to the base class' one. */
3952760c2415Smrg         string generateFunctionBody(ctor.../+[BUG 4217]+/)() @property
3953760c2415Smrg         {
3954760c2415Smrg             enum varstyle = variadicFunctionStyle!(typeof(&ctor[0]));
3955760c2415Smrg 
3956760c2415Smrg             static if (varstyle & (Variadic.c | Variadic.d))
3957760c2415Smrg             {
3958760c2415Smrg                 // the argptr-forwarding problem
3959760c2415Smrg                 //pragma(msg, "Warning: AutoImplement!(", Base, ") ",
3960760c2415Smrg                 //        "ignored variadic arguments to the constructor ",
3961760c2415Smrg                 //        FunctionTypeOf!(typeof(&ctor[0])) );
3962760c2415Smrg             }
3963760c2415Smrg             return "super(args);";
3964760c2415Smrg         }
3965760c2415Smrg     }
3966760c2415Smrg 
3967760c2415Smrg     /* Policy configurations for genearting target methods. */
3968760c2415Smrg     template MethodGeneratingPolicy()
3969760c2415Smrg     {
3970760c2415Smrg         mixin CommonGeneratingPolicy;
3971760c2415Smrg 
3972760c2415Smrg         /* Geneartes method body. */
3973760c2415Smrg         string generateFunctionBody(func.../+[BUG 4217]+/)() @property
3974760c2415Smrg         {
3975760c2415Smrg             return generateMethodBody!(Base, func); // given
3976760c2415Smrg         }
3977760c2415Smrg     }
3978760c2415Smrg 
3979760c2415Smrg 
3980760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3981760c2415Smrg     // Generated code
3982760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
3983760c2415Smrg 
3984760c2415Smrg     alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!());
3985760c2415Smrg     alias MethodGenerator      = MemberFunctionGenerator!(MethodGeneratingPolicy!());
3986760c2415Smrg 
3987760c2415Smrg     public enum string code =
3988760c2415Smrg         ConstructorGenerator.generateCode!(  ctorOverloadSet ) ~ "\n" ~
3989760c2415Smrg              MethodGenerator.generateCode!(targetOverloadSets);
3990760c2415Smrg 
3991760c2415Smrg     debug (SHOW_GENERATED_CODE)
3992760c2415Smrg     {
3993760c2415Smrg         pragma(msg, "-------------------- < ", Base, " >");
3994760c2415Smrg         pragma(msg, code);
3995760c2415Smrg         pragma(msg, "--------------------");
3996760c2415Smrg     }
3997760c2415Smrg }
3998760c2415Smrg 
3999760c2415Smrg //debug = SHOW_GENERATED_CODE;
4000760c2415Smrg @system unittest
4001760c2415Smrg {
4002760c2415Smrg     import core.vararg;
4003760c2415Smrg     // no function to implement
4004760c2415Smrg     {
4005760c2415Smrg         interface I_1 {}
4006760c2415Smrg         auto o = new BlackHole!I_1;
4007760c2415Smrg     }
4008760c2415Smrg     // parameters
4009760c2415Smrg     {
4010760c2415Smrg         interface I_3 { void test(int, in int, out int, ref int, lazy int); }
4011760c2415Smrg         auto o = new BlackHole!I_3;
4012760c2415Smrg     }
4013760c2415Smrg     // use of user-defined type
4014760c2415Smrg     {
4015760c2415Smrg         struct S {}
4016760c2415Smrg         interface I_4 { S test(); }
4017760c2415Smrg         auto o = new BlackHole!I_4;
4018760c2415Smrg     }
4019760c2415Smrg     // overloads
4020760c2415Smrg     {
4021760c2415Smrg         interface I_5
4022760c2415Smrg         {
4023760c2415Smrg             void test(string);
4024760c2415Smrg             real test(real);
4025760c2415Smrg             int  test();
4026760c2415Smrg         }
4027760c2415Smrg         auto o = new BlackHole!I_5;
4028760c2415Smrg     }
4029760c2415Smrg     // constructor forwarding
4030760c2415Smrg     {
4031760c2415Smrg         static class C_6
4032760c2415Smrg         {
4033760c2415Smrg             this(int n) { assert(n == 42); }
4034760c2415Smrg             this(string s) { assert(s == "Deeee"); }
4035760c2415Smrg             this(...) {}
4036760c2415Smrg         }
4037760c2415Smrg         auto o1 = new BlackHole!C_6(42);
4038760c2415Smrg         auto o2 = new BlackHole!C_6("Deeee");
4039760c2415Smrg         auto o3 = new BlackHole!C_6(1, 2, 3, 4);
4040760c2415Smrg     }
4041760c2415Smrg     // attributes
4042760c2415Smrg     {
4043760c2415Smrg         interface I_7
4044760c2415Smrg         {
4045760c2415Smrg             ref int test_ref();
4046760c2415Smrg             int test_pure() pure;
4047760c2415Smrg             int test_nothrow() nothrow;
4048760c2415Smrg             int test_property() @property;
4049760c2415Smrg             int test_safe() @safe;
4050760c2415Smrg             int test_trusted() @trusted;
4051760c2415Smrg             int test_system() @system;
4052760c2415Smrg             int test_pure_nothrow() pure nothrow;
4053760c2415Smrg         }
4054760c2415Smrg         auto o = new BlackHole!I_7;
4055760c2415Smrg     }
4056760c2415Smrg     // storage classes
4057760c2415Smrg     {
4058760c2415Smrg         interface I_8
4059760c2415Smrg         {
4060760c2415Smrg             void test_const() const;
4061760c2415Smrg             void test_immutable() immutable;
4062760c2415Smrg             void test_shared() shared;
4063760c2415Smrg             void test_shared_const() shared const;
4064760c2415Smrg         }
4065760c2415Smrg         auto o = new BlackHole!I_8;
4066760c2415Smrg     }
4067760c2415Smrg     // use baseclass
4068760c2415Smrg     {
4069760c2415Smrg         static class C_9
4070760c2415Smrg         {
4071760c2415Smrg             private string foo_;
4072760c2415Smrg 
4073760c2415Smrg             this(string s) {
4074760c2415Smrg                 foo_ = s;
4075760c2415Smrg             }
4076760c2415Smrg 
4077760c2415Smrg             protected string boilerplate() @property
4078760c2415Smrg             {
4079760c2415Smrg                 return "Boilerplate stuff.";
4080760c2415Smrg             }
4081760c2415Smrg 
4082760c2415Smrg             public string foo() @property
4083760c2415Smrg             {
4084760c2415Smrg                 return foo_;
4085760c2415Smrg             }
4086760c2415Smrg         }
4087760c2415Smrg 
4088760c2415Smrg         interface I_10
4089760c2415Smrg         {
4090760c2415Smrg             string testMethod(size_t);
4091760c2415Smrg         }
4092760c2415Smrg 
4093760c2415Smrg         static string generateTestMethod(C, alias fun)() @property
4094760c2415Smrg         {
4095760c2415Smrg             return "return this.boilerplate[0 .. a0];";
4096760c2415Smrg         }
4097760c2415Smrg 
4098760c2415Smrg         auto o = new AutoImplement!(I_10, C_9, generateTestMethod)("Testing");
4099760c2415Smrg         assert(o.testMethod(11) == "Boilerplate");
4100760c2415Smrg         assert(o.foo == "Testing");
4101760c2415Smrg     }
4102760c2415Smrg     /+ // deep inheritance
4103760c2415Smrg     {
4104760c2415Smrg     // XXX [BUG 2525,3525]
4105760c2415Smrg     // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic()
4106760c2415Smrg         interface I { void foo(); }
4107760c2415Smrg         interface J : I {}
4108760c2415Smrg         interface K : J {}
4109760c2415Smrg         static abstract class C_9 : K {}
4110760c2415Smrg         auto o = new BlackHole!C_9;
4111760c2415Smrg     }+/
4112760c2415Smrg }
4113760c2415Smrg 
4114760c2415Smrg // Issue 17177 - AutoImplement fails on function overload sets with "cannot infer type from overloaded function symbol"
4115760c2415Smrg @system unittest
4116760c2415Smrg {
4117760c2415Smrg     static class Issue17177
4118760c2415Smrg     {
4119760c2415Smrg         private string n_;
4120760c2415Smrg 
4121760c2415Smrg         public {
4122760c2415Smrg             Issue17177 overloaded(string n)
4123760c2415Smrg             {
4124760c2415Smrg                 this.n_ = n;
4125760c2415Smrg 
4126760c2415Smrg                 return this;
4127760c2415Smrg             }
4128760c2415Smrg 
4129760c2415Smrg             string overloaded()
4130760c2415Smrg             {
4131760c2415Smrg                 return this.n_;
4132760c2415Smrg             }
4133760c2415Smrg         }
4134760c2415Smrg     }
4135760c2415Smrg 
4136760c2415Smrg     static string how(C, alias fun)()
4137760c2415Smrg     {
4138760c2415Smrg         static if (!is(ReturnType!fun == void))
4139760c2415Smrg         {
4140760c2415Smrg             return q{
4141760c2415Smrg                 return parent(args);
4142760c2415Smrg             };
4143760c2415Smrg         }
4144760c2415Smrg         else
4145760c2415Smrg         {
4146760c2415Smrg             return q{
4147760c2415Smrg                 parent(args);
4148760c2415Smrg             };
4149760c2415Smrg         }
4150760c2415Smrg     }
4151760c2415Smrg 
4152760c2415Smrg     alias Implementation = AutoImplement!(Issue17177, how, templateNot!isFinalFunction);
4153760c2415Smrg }
4154760c2415Smrg 
4155760c2415Smrg version (unittest)
4156760c2415Smrg {
4157760c2415Smrg     // Issue 10647
4158760c2415Smrg     // Add prefix "issue10647_" as a workaround for issue 1238
4159760c2415Smrg     private string issue10647_generateDoNothing(C, alias fun)() @property
4160760c2415Smrg     {
4161760c2415Smrg         string stmt;
4162760c2415Smrg 
4163760c2415Smrg         static if (is(ReturnType!fun == void))
4164760c2415Smrg             stmt ~= "";
4165760c2415Smrg         else
4166760c2415Smrg         {
4167760c2415Smrg             string returnType = ReturnType!fun.stringof;
4168760c2415Smrg             stmt ~= "return "~returnType~".init;";
4169760c2415Smrg         }
4170760c2415Smrg         return stmt;
4171760c2415Smrg     }
4172760c2415Smrg 
4173760c2415Smrg     private template issue10647_isAlwaysTrue(alias fun)
4174760c2415Smrg     {
4175760c2415Smrg         enum issue10647_isAlwaysTrue = true;
4176760c2415Smrg     }
4177760c2415Smrg 
4178760c2415Smrg     // Do nothing template
4179760c2415Smrg     private template issue10647_DoNothing(Base)
4180760c2415Smrg     {
4181760c2415Smrg         alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue);
4182760c2415Smrg     }
4183760c2415Smrg 
4184760c2415Smrg     // A class to be overridden
4185760c2415Smrg     private class issue10647_Foo{
4186760c2415Smrg         void bar(int a) { }
4187760c2415Smrg     }
4188760c2415Smrg }
4189760c2415Smrg @system unittest
4190760c2415Smrg {
4191760c2415Smrg     auto foo = new issue10647_DoNothing!issue10647_Foo();
4192760c2415Smrg     foo.bar(13);
4193760c2415Smrg }
4194760c2415Smrg 
4195760c2415Smrg /*
4196760c2415Smrg Used by MemberFunctionGenerator.
4197760c2415Smrg  */
4198760c2415Smrg package template OverloadSet(string nam, T...)
4199760c2415Smrg {
4200760c2415Smrg     enum string name = nam;
4201760c2415Smrg     alias contents = T;
4202760c2415Smrg }
4203760c2415Smrg 
4204760c2415Smrg /*
4205760c2415Smrg Used by MemberFunctionGenerator.
4206760c2415Smrg  */
4207760c2415Smrg package template FuncInfo(alias func, /+[BUG 4217 ?]+/ T = typeof(&func))
4208760c2415Smrg {
4209760c2415Smrg     alias RT = ReturnType!T;
4210760c2415Smrg     alias PT = Parameters!T;
4211760c2415Smrg }
4212760c2415Smrg package template FuncInfo(Func)
4213760c2415Smrg {
4214760c2415Smrg     alias RT = ReturnType!Func;
4215760c2415Smrg     alias PT = Parameters!Func;
4216760c2415Smrg }
4217760c2415Smrg 
4218760c2415Smrg /*
4219760c2415Smrg General-purpose member function generator.
4220760c2415Smrg --------------------
4221760c2415Smrg template GeneratingPolicy()
4222760c2415Smrg {
4223760c2415Smrg     // [optional] the name of the class where functions are derived
4224760c2415Smrg     enum string BASE_CLASS_ID;
4225760c2415Smrg 
4226760c2415Smrg     // [optional] define this if you have only function types
4227760c2415Smrg     enum bool WITHOUT_SYMBOL;
4228760c2415Smrg 
4229760c2415Smrg     // [optional] Returns preferred identifier for i-th parameter.
4230760c2415Smrg     template PARAMETER_VARIABLE_ID(size_t i);
4231760c2415Smrg 
4232760c2415Smrg     // Returns the identifier of the FuncInfo instance for the i-th overload
4233760c2415Smrg     // of the specified name.  The identifier must be accessible in the scope
4234760c2415Smrg     // where generated code is mixed.
4235760c2415Smrg     template FUNCINFO_ID(string name, size_t i);
4236760c2415Smrg 
4237760c2415Smrg     // Returns implemented function body as a string.  When WITHOUT_SYMBOL is
4238760c2415Smrg     // defined, the latter is used.
4239760c2415Smrg     template generateFunctionBody(alias func);
4240760c2415Smrg     template generateFunctionBody(string name, FuncType);
4241760c2415Smrg }
4242760c2415Smrg --------------------
4243760c2415Smrg  */
4244760c2415Smrg package template MemberFunctionGenerator(alias Policy)
4245760c2415Smrg {
4246760c2415Smrg private static:
4247760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4248760c2415Smrg     // Internal stuffs
4249760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4250760c2415Smrg     import std.format;
4251760c2415Smrg 
4252760c2415Smrg     enum CONSTRUCTOR_NAME = "__ctor";
4253760c2415Smrg 
4254760c2415Smrg     // true if functions are derived from a base class
4255760c2415Smrg     enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID");
4256760c2415Smrg 
4257760c2415Smrg     // true if functions are specified as types, not symbols
4258760c2415Smrg     enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL");
4259760c2415Smrg 
4260760c2415Smrg     // preferred identifier for i-th parameter variable
4261760c2415Smrg     static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID"))
4262760c2415Smrg     {
4263760c2415Smrg         alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID;
4264760c2415Smrg     }
4265760c2415Smrg     else
4266760c2415Smrg     {
4267760c2415Smrg         enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i);
4268760c2415Smrg             // default: a0, a1, ...
4269760c2415Smrg     }
4270760c2415Smrg 
4271760c2415Smrg     // Returns a tuple consisting of 0,1,2,...,n-1.  For static foreach.
4272760c2415Smrg     template CountUp(size_t n)
4273760c2415Smrg     {
4274760c2415Smrg         static if (n > 0)
4275760c2415Smrg             alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1);
4276760c2415Smrg         else
4277760c2415Smrg             alias CountUp = AliasSeq!();
4278760c2415Smrg     }
4279760c2415Smrg 
4280760c2415Smrg 
4281760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4282760c2415Smrg     // Code generator
4283760c2415Smrg     //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
4284760c2415Smrg 
4285760c2415Smrg     /*
4286760c2415Smrg      * Runs through all the target overload sets and generates D code which
4287760c2415Smrg      * implements all the functions in the overload sets.
4288760c2415Smrg      */
4289760c2415Smrg     public string generateCode(overloads...)() @property
4290760c2415Smrg     {
4291760c2415Smrg         string code = "";
4292760c2415Smrg 
4293760c2415Smrg         // run through all the overload sets
4294760c2415Smrg         foreach (i_; CountUp!(0 + overloads.length)) // workaround
4295760c2415Smrg         {
4296760c2415Smrg             enum i = 0 + i_; // workaround
4297760c2415Smrg             alias oset = overloads[i];
4298760c2415Smrg 
4299760c2415Smrg             code ~= generateCodeForOverloadSet!(oset);
4300760c2415Smrg 
4301760c2415Smrg             static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME)
4302760c2415Smrg             {
4303760c2415Smrg                 // The generated function declarations may hide existing ones
4304760c2415Smrg                 // in the base class (cf. HiddenFuncError), so we put an alias
4305760c2415Smrg                 // declaration here to reveal possible hidden functions.
4306760c2415Smrg                 code ~= format("alias %s = %s.%s;\n",
4307760c2415Smrg                             oset.name,
4308760c2415Smrg                             Policy.BASE_CLASS_ID, // [BUG 2540] super.
4309760c2415Smrg                             oset.name);
4310760c2415Smrg             }
4311760c2415Smrg         }
4312760c2415Smrg         return code;
4313760c2415Smrg     }
4314760c2415Smrg 
4315760c2415Smrg     // handle each overload set
4316760c2415Smrg     private string generateCodeForOverloadSet(alias oset)() @property
4317760c2415Smrg     {
4318760c2415Smrg         string code = "";
4319760c2415Smrg 
4320760c2415Smrg         foreach (i_; CountUp!(0 + oset.contents.length)) // workaround
4321760c2415Smrg         {
4322760c2415Smrg             enum i = 0 + i_; // workaround
4323760c2415Smrg             code ~= generateFunction!(
4324760c2415Smrg                     Policy.FUNCINFO_ID!(oset.name, i), oset.name,
4325760c2415Smrg                     oset.contents[i]) ~ "\n";
4326760c2415Smrg         }
4327760c2415Smrg         return code;
4328760c2415Smrg     }
4329760c2415Smrg 
4330760c2415Smrg     /*
4331760c2415Smrg      * Returns D code which implements the function func.  This function
4332760c2415Smrg      * actually generates only the declarator part; the function body part is
4333760c2415Smrg      * generated by the functionGenerator() policy.
4334760c2415Smrg      */
4335760c2415Smrg     public string generateFunction(
4336760c2415Smrg             string myFuncInfo, string name, func... )() @property
4337760c2415Smrg     {
4338760c2415Smrg         import std.format : format;
4339760c2415Smrg 
4340760c2415Smrg         enum isCtor = (name == CONSTRUCTOR_NAME);
4341760c2415Smrg 
4342760c2415Smrg         string code; // the result
4343760c2415Smrg 
4344760c2415Smrg         auto paramsRes = generateParameters!(myFuncInfo, func)();
4345760c2415Smrg         code ~= paramsRes.imports;
4346760c2415Smrg 
4347760c2415Smrg         /*** Function Declarator ***/
4348760c2415Smrg         {
4349760c2415Smrg             alias Func = FunctionTypeOf!(func);
4350760c2415Smrg             alias FA = FunctionAttribute;
4351760c2415Smrg             enum atts     = functionAttributes!(func);
4352760c2415Smrg             enum realName = isCtor ? "this" : name;
4353760c2415Smrg 
4354760c2415Smrg             // FIXME?? Make it so that these aren't CTFE funcs any more, since
4355760c2415Smrg             // Format is deprecated, and format works at compile time?
4356760c2415Smrg             /* Made them CTFE funcs just for the sake of Format!(...) */
4357760c2415Smrg 
4358760c2415Smrg             // return type with optional "ref"
4359760c2415Smrg             static string make_returnType()
4360760c2415Smrg             {
4361760c2415Smrg                 string rtype = "";
4362760c2415Smrg 
4363760c2415Smrg                 if (!isCtor)
4364760c2415Smrg                 {
4365760c2415Smrg                     if (atts & FA.ref_) rtype ~= "ref ";
4366760c2415Smrg                     rtype ~= myFuncInfo ~ ".RT";
4367760c2415Smrg                 }
4368760c2415Smrg                 return rtype;
4369760c2415Smrg             }
4370760c2415Smrg             enum returnType = make_returnType();
4371760c2415Smrg 
4372760c2415Smrg             // function attributes attached after declaration
4373760c2415Smrg             static string make_postAtts()
4374760c2415Smrg             {
4375760c2415Smrg                 string poatts = "";
4376760c2415Smrg                 if (atts & FA.pure_   ) poatts ~= " pure";
4377760c2415Smrg                 if (atts & FA.nothrow_) poatts ~= " nothrow";
4378760c2415Smrg                 if (atts & FA.property) poatts ~= " @property";
4379760c2415Smrg                 if (atts & FA.safe    ) poatts ~= " @safe";
4380760c2415Smrg                 if (atts & FA.trusted ) poatts ~= " @trusted";
4381760c2415Smrg                 return poatts;
4382760c2415Smrg             }
4383760c2415Smrg             enum postAtts = make_postAtts();
4384760c2415Smrg 
4385760c2415Smrg             // function storage class
4386760c2415Smrg             static string make_storageClass()
4387760c2415Smrg             {
4388760c2415Smrg                 string postc = "";
4389760c2415Smrg                 if (is(Func ==    shared)) postc ~= " shared";
4390760c2415Smrg                 if (is(Func ==     const)) postc ~= " const";
4391760c2415Smrg                 if (is(Func ==     inout)) postc ~= " inout";
4392760c2415Smrg                 if (is(Func == immutable)) postc ~= " immutable";
4393760c2415Smrg                 return postc;
4394760c2415Smrg             }
4395760c2415Smrg             enum storageClass = make_storageClass();
4396760c2415Smrg 
4397760c2415Smrg             //
4398760c2415Smrg             if (__traits(isVirtualMethod, func))
4399760c2415Smrg                 code ~= "override ";
4400760c2415Smrg             code ~= format("extern(%s) %s %s(%s) %s %s\n",
4401760c2415Smrg                     functionLinkage!(func),
4402760c2415Smrg                     returnType,
4403760c2415Smrg                     realName,
4404760c2415Smrg                     paramsRes.params,
4405760c2415Smrg                     postAtts, storageClass );
4406760c2415Smrg         }
4407760c2415Smrg 
4408760c2415Smrg         /*** Function Body ***/
4409760c2415Smrg         code ~= "{\n";
4410760c2415Smrg         {
4411760c2415Smrg             enum nparams = Parameters!(func).length;
4412760c2415Smrg 
4413760c2415Smrg             /* Declare keywords: args, self and parent. */
4414760c2415Smrg             string preamble;
4415760c2415Smrg 
4416760c2415Smrg             preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n";
4417760c2415Smrg             if (!isCtor)
4418760c2415Smrg             {
4419760c2415Smrg                 preamble ~= "alias self = " ~ name ~ ";\n";
4420760c2415Smrg                 if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func))
4421760c2415Smrg                     preamble ~= "alias parent = AliasSeq!(__traits(getMember, super, \"" ~ name ~ "\"))[0];";
4422760c2415Smrg             }
4423760c2415Smrg 
4424760c2415Smrg             // Function body
4425760c2415Smrg             static if (WITHOUT_SYMBOL)
4426760c2415Smrg                 enum fbody = Policy.generateFunctionBody!(name, func);
4427760c2415Smrg             else
4428760c2415Smrg                 enum fbody = Policy.generateFunctionBody!(func);
4429760c2415Smrg 
4430760c2415Smrg             code ~= preamble;
4431760c2415Smrg             code ~= fbody;
4432760c2415Smrg         }
4433760c2415Smrg         code ~= "}";
4434760c2415Smrg 
4435760c2415Smrg         return code;
4436760c2415Smrg     }
4437760c2415Smrg 
4438760c2415Smrg     /*
4439760c2415Smrg      * Returns D code which declares function parameters,
4440760c2415Smrg      * and optionally any imports (e.g. core.vararg)
4441760c2415Smrg      * "ref int a0, real a1, ..."
4442760c2415Smrg      */
4443760c2415Smrg     static struct GenParams { string imports, params; }
4444760c2415Smrg     private GenParams generateParameters(string myFuncInfo, func...)()
4445760c2415Smrg     {
4446760c2415Smrg         alias STC = ParameterStorageClass;
4447760c2415Smrg         alias stcs = ParameterStorageClassTuple!(func);
4448760c2415Smrg         enum nparams = stcs.length;
4449760c2415Smrg 
4450760c2415Smrg         string imports = ""; // any imports required
4451760c2415Smrg         string params = ""; // parameters
4452760c2415Smrg 
4453760c2415Smrg         foreach (i, stc; stcs)
4454760c2415Smrg         {
4455760c2415Smrg             if (i > 0) params ~= ", ";
4456760c2415Smrg 
4457760c2415Smrg             // Parameter storage classes.
4458760c2415Smrg             if (stc & STC.scope_) params ~= "scope ";
4459760c2415Smrg             if (stc & STC.out_  ) params ~= "out ";
4460760c2415Smrg             if (stc & STC.ref_  ) params ~= "ref ";
4461760c2415Smrg             if (stc & STC.lazy_ ) params ~= "lazy ";
4462760c2415Smrg 
4463760c2415Smrg             // Take parameter type from the FuncInfo.
4464760c2415Smrg             params ~= format("%s.PT[%s]", myFuncInfo, i);
4465760c2415Smrg 
4466760c2415Smrg             // Declare a parameter variable.
4467760c2415Smrg             params ~= " " ~ PARAMETER_VARIABLE_ID!(i);
4468760c2415Smrg         }
4469760c2415Smrg 
4470760c2415Smrg         // Add some ellipsis part if needed.
4471760c2415Smrg         auto style = variadicFunctionStyle!(func);
4472760c2415Smrg         final switch (style)
4473760c2415Smrg         {
4474760c2415Smrg             case Variadic.no:
4475760c2415Smrg                 break;
4476760c2415Smrg 
4477760c2415Smrg             case Variadic.c, Variadic.d:
4478760c2415Smrg                 imports ~= "import core.vararg;\n";
4479760c2415Smrg                 // (...) or (a, b, ...)
4480760c2415Smrg                 params ~= (nparams == 0) ? "..." : ", ...";
4481760c2415Smrg                 break;
4482760c2415Smrg 
4483760c2415Smrg             case Variadic.typesafe:
4484760c2415Smrg                 params ~= " ...";
4485760c2415Smrg                 break;
4486760c2415Smrg         }
4487760c2415Smrg 
4488760c2415Smrg         return typeof(return)(imports, params);
4489760c2415Smrg     }
4490760c2415Smrg 
4491760c2415Smrg     // Returns D code which enumerates n parameter variables using comma as the
4492760c2415Smrg     // separator.  "a0, a1, a2, a3"
4493760c2415Smrg     private string enumerateParameters(size_t n)() @property
4494760c2415Smrg     {
4495760c2415Smrg         string params = "";
4496760c2415Smrg 
4497760c2415Smrg         foreach (i_; CountUp!(n))
4498760c2415Smrg         {
4499760c2415Smrg             enum i = 0 + i_; // workaround
4500760c2415Smrg             if (i > 0) params ~= ", ";
4501760c2415Smrg             params ~= PARAMETER_VARIABLE_ID!(i);
4502760c2415Smrg         }
4503760c2415Smrg         return params;
4504760c2415Smrg     }
4505760c2415Smrg }
4506760c2415Smrg 
4507760c2415Smrg 
4508760c2415Smrg /**
4509760c2415Smrg Predefined how-policies for $(D AutoImplement).  These templates are also used by
4510760c2415Smrg $(D BlackHole) and $(D WhiteHole), respectively.
4511760c2415Smrg  */
4512760c2415Smrg template generateEmptyFunction(C, func.../+[BUG 4217]+/)
4513760c2415Smrg {
4514760c2415Smrg     static if (is(ReturnType!(func) == void))
4515760c2415Smrg         enum string generateEmptyFunction = q{
4516760c2415Smrg         };
4517760c2415Smrg     else static if (functionAttributes!(func) & FunctionAttribute.ref_)
4518760c2415Smrg         enum string generateEmptyFunction = q{
4519760c2415Smrg             static typeof(return) dummy;
4520760c2415Smrg             return dummy;
4521760c2415Smrg         };
4522760c2415Smrg     else
4523760c2415Smrg         enum string generateEmptyFunction = q{
4524760c2415Smrg             return typeof(return).init;
4525760c2415Smrg         };
4526760c2415Smrg }
4527760c2415Smrg 
4528760c2415Smrg /// ditto
4529760c2415Smrg template generateAssertTrap(C, func...)
4530760c2415Smrg {
4531760c2415Smrg     enum string generateAssertTrap =
4532760c2415Smrg         `throw new NotImplementedError("` ~ C.stringof ~ "."
4533760c2415Smrg                 ~ __traits(identifier, func) ~ `");`;
4534760c2415Smrg }
4535760c2415Smrg 
4536760c2415Smrg private
4537760c2415Smrg {
4538760c2415Smrg     pragma(mangle, "_d_toObject")
4539760c2415Smrg     extern(C) pure nothrow Object typecons_d_toObject(void* p);
4540760c2415Smrg }
4541760c2415Smrg 
4542760c2415Smrg /*
4543760c2415Smrg  * Avoids opCast operator overloading.
4544760c2415Smrg  */
4545760c2415Smrg private template dynamicCast(T)
4546760c2415Smrg if (is(T == class) || is(T == interface))
4547760c2415Smrg {
4548760c2415Smrg     @trusted
4549760c2415Smrg     T dynamicCast(S)(inout S source)
4550760c2415Smrg     if (is(S == class) || is(S == interface))
4551760c2415Smrg     {
4552760c2415Smrg         static if (is(Unqual!S : Unqual!T))
4553760c2415Smrg         {
4554760c2415Smrg             import std.traits : QualifierOf;
4555760c2415Smrg             alias Qual = QualifierOf!S; // SharedOf or MutableOf
4556760c2415Smrg             alias TmpT = Qual!(Unqual!T);
4557760c2415Smrg             inout(TmpT) tmp = source;   // bypass opCast by implicit conversion
4558760c2415Smrg             return *cast(T*)(&tmp);     // + variable pointer cast + dereference
4559760c2415Smrg         }
4560760c2415Smrg         else
4561760c2415Smrg         {
4562760c2415Smrg             return cast(T) typecons_d_toObject(*cast(void**)(&source));
4563760c2415Smrg         }
4564760c2415Smrg     }
4565760c2415Smrg }
4566760c2415Smrg 
4567760c2415Smrg @system unittest
4568760c2415Smrg {
4569760c2415Smrg     class C { @disable opCast(T)() {} }
4570760c2415Smrg     auto c = new C;
4571760c2415Smrg     static assert(!__traits(compiles, cast(Object) c));
4572760c2415Smrg     auto o = dynamicCast!Object(c);
4573760c2415Smrg     assert(c is o);
4574760c2415Smrg 
4575760c2415Smrg     interface I { @disable opCast(T)() {} Object instance(); }
4576760c2415Smrg     interface J { @disable opCast(T)() {} Object instance(); }
4577760c2415Smrg     class D : I, J { Object instance() { return this; } }
4578760c2415Smrg     I i = new D();
4579760c2415Smrg     static assert(!__traits(compiles, cast(J) i));
4580760c2415Smrg     J j = dynamicCast!J(i);
4581760c2415Smrg     assert(i.instance() is j.instance());
4582760c2415Smrg }
4583760c2415Smrg 
4584760c2415Smrg /**
4585760c2415Smrg  * Supports structural based typesafe conversion.
4586760c2415Smrg  *
4587760c2415Smrg  * If $(D Source) has structural conformance with the $(D interface) $(D Targets),
4588760c2415Smrg  * wrap creates internal wrapper class which inherits $(D Targets) and
4589760c2415Smrg  * wrap $(D src) object, then return it.
4590760c2415Smrg  */
4591760c2415Smrg template wrap(Targets...)
4592760c2415Smrg if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
4593760c2415Smrg {
4594760c2415Smrg     import std.meta : staticMap;
4595760c2415Smrg 
4596760c2415Smrg     // strict upcast
4597760c2415Smrg     auto wrap(Source)(inout Source src) @trusted pure nothrow
4598760c2415Smrg     if (Targets.length == 1 && is(Source : Targets[0]))
4599760c2415Smrg     {
4600760c2415Smrg         alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]);
4601760c2415Smrg         return dynamicCast!(inout T)(src);
4602760c2415Smrg     }
4603760c2415Smrg     // structural upcast
4604760c2415Smrg     template wrap(Source)
4605760c2415Smrg     if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets))
4606760c2415Smrg     {
4607760c2415Smrg         auto wrap(inout Source src)
4608760c2415Smrg         {
4609760c2415Smrg             static assert(hasRequireMethods!(),
4610760c2415Smrg                           "Source "~Source.stringof~
4611760c2415Smrg                           " does not have structural conformance to "~
4612760c2415Smrg                           Targets.stringof);
4613760c2415Smrg 
4614760c2415Smrg             alias T = Select!(is(Source == shared), shared Impl, Impl);
4615760c2415Smrg             return new inout T(src);
4616760c2415Smrg         }
4617760c2415Smrg 
4618760c2415Smrg         template FuncInfo(string s, F)
4619760c2415Smrg         {
4620760c2415Smrg             enum name = s;
4621760c2415Smrg             alias type = F;
4622760c2415Smrg         }
4623760c2415Smrg 
4624760c2415Smrg         // Concat all Targets function members into one tuple
4625760c2415Smrg         template Concat(size_t i = 0)
4626760c2415Smrg         {
4627760c2415Smrg             static if (i >= Targets.length)
4628760c2415Smrg                 alias Concat = AliasSeq!();
4629760c2415Smrg             else
4630760c2415Smrg             {
4631760c2415Smrg                 alias Concat = AliasSeq!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1));
4632760c2415Smrg             }
4633760c2415Smrg         }
4634760c2415Smrg         // Remove duplicated functions based on the identifier name and function type covariance
4635760c2415Smrg         template Uniq(members...)
4636760c2415Smrg         {
4637760c2415Smrg             static if (members.length == 0)
4638760c2415Smrg                 alias Uniq = AliasSeq!();
4639760c2415Smrg             else
4640760c2415Smrg             {
4641760c2415Smrg                 alias func = members[0];
4642760c2415Smrg                 enum  name = __traits(identifier, func);
4643760c2415Smrg                 alias type = FunctionTypeOf!func;
4644760c2415Smrg                 template check(size_t i, mem...)
4645760c2415Smrg                 {
4646760c2415Smrg                     static if (i >= mem.length)
4647760c2415Smrg                         enum ptrdiff_t check = -1;
4648760c2415Smrg                     else
4649760c2415Smrg                     {
4650760c2415Smrg                         enum ptrdiff_t check =
4651760c2415Smrg                             __traits(identifier, func) == __traits(identifier, mem[i]) &&
4652760c2415Smrg                             !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void)
4653760c2415Smrg                           ? i : check!(i + 1, mem);
4654760c2415Smrg                     }
4655760c2415Smrg                 }
4656760c2415Smrg                 enum ptrdiff_t x = 1 + check!(0, members[1 .. $]);
4657760c2415Smrg                 static if (x >= 1)
4658760c2415Smrg                 {
4659760c2415Smrg                     alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x]));
4660760c2415Smrg                     alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]);
4661760c2415Smrg 
4662760c2415Smrg                     static if (remain.length >= 1 && remain[0].name == name &&
4663760c2415Smrg                                !is(DerivedFunctionType!(typex, remain[0].type) == void))
4664760c2415Smrg                     {
4665760c2415Smrg                         alias F = DerivedFunctionType!(typex, remain[0].type);
4666760c2415Smrg                         alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]);
4667760c2415Smrg                     }
4668760c2415Smrg                     else
4669760c2415Smrg                         alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain);
4670760c2415Smrg                 }
4671760c2415Smrg                 else
4672760c2415Smrg                 {
4673760c2415Smrg                     alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $]));
4674760c2415Smrg                 }
4675760c2415Smrg             }
4676760c2415Smrg         }
4677760c2415Smrg         alias TargetMembers = Uniq!(Concat!());             // list of FuncInfo
4678760c2415Smrg         alias SourceMembers = GetOverloadedMethods!Source;  // list of function symbols
4679760c2415Smrg 
4680760c2415Smrg         // Check whether all of SourceMembers satisfy covariance target in TargetMembers
4681760c2415Smrg         template hasRequireMethods(size_t i = 0)
4682760c2415Smrg         {
4683760c2415Smrg             static if (i >= TargetMembers.length)
4684760c2415Smrg                 enum hasRequireMethods = true;
4685760c2415Smrg             else
4686760c2415Smrg             {
4687760c2415Smrg                 enum hasRequireMethods =
4688760c2415Smrg                     findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 &&
4689760c2415Smrg                     hasRequireMethods!(i + 1);
4690760c2415Smrg             }
4691760c2415Smrg         }
4692760c2415Smrg 
4693760c2415Smrg         // Internal wrapper class
4694760c2415Smrg         final class Impl : Structural, Targets
4695760c2415Smrg         {
4696760c2415Smrg         private:
4697760c2415Smrg             Source _wrap_source;
4698760c2415Smrg 
4699760c2415Smrg             this(       inout Source s)        inout @safe pure nothrow { _wrap_source = s; }
4700760c2415Smrg             this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; }
4701760c2415Smrg 
4702760c2415Smrg             // BUG: making private should work with NVI.
4703760c2415Smrg             protected final inout(Object) _wrap_getSource() inout @trusted
4704760c2415Smrg             {
4705760c2415Smrg                 return dynamicCast!(inout Object)(_wrap_source);
4706760c2415Smrg             }
4707760c2415Smrg 
4708760c2415Smrg             import std.conv : to;
4709760c2415Smrg             import std.functional : forward;
4710760c2415Smrg             template generateFun(size_t i)
4711760c2415Smrg             {
4712760c2415Smrg                 enum name = TargetMembers[i].name;
4713760c2415Smrg                 enum fa = functionAttributes!(TargetMembers[i].type);
4714760c2415Smrg                 static @property stc()
4715760c2415Smrg                 {
4716760c2415Smrg                     string r;
4717760c2415Smrg                     if (fa & FunctionAttribute.property)    r ~= "@property ";
4718760c2415Smrg                     if (fa & FunctionAttribute.ref_)        r ~= "ref ";
4719760c2415Smrg                     if (fa & FunctionAttribute.pure_)       r ~= "pure ";
4720760c2415Smrg                     if (fa & FunctionAttribute.nothrow_)    r ~= "nothrow ";
4721760c2415Smrg                     if (fa & FunctionAttribute.trusted)     r ~= "@trusted ";
4722760c2415Smrg                     if (fa & FunctionAttribute.safe)        r ~= "@safe ";
4723760c2415Smrg                     return r;
4724760c2415Smrg                 }
4725760c2415Smrg                 static @property mod()
4726760c2415Smrg                 {
4727760c2415Smrg                     alias type = AliasSeq!(TargetMembers[i].type)[0];
4728760c2415Smrg                     string r;
4729760c2415Smrg                     static if (is(type == immutable))       r ~= " immutable";
4730760c2415Smrg                     else
4731760c2415Smrg                     {
4732760c2415Smrg                         static if (is(type == shared))      r ~= " shared";
4733760c2415Smrg                         static if (is(type == const))       r ~= " const";
4734760c2415Smrg                         else static if (is(type == inout))  r ~= " inout";
4735760c2415Smrg                         //else  --> mutable
4736760c2415Smrg                     }
4737760c2415Smrg                     return r;
4738760c2415Smrg                 }
4739760c2415Smrg                 enum n = to!string(i);
4740760c2415Smrg                 static if (fa & FunctionAttribute.property)
4741760c2415Smrg                 {
4742760c2415Smrg                     static if (Parameters!(TargetMembers[i].type).length == 0)
4743760c2415Smrg                         enum fbody = "_wrap_source."~name;
4744760c2415Smrg                     else
4745760c2415Smrg                         enum fbody = "_wrap_source."~name~" = forward!args";
4746760c2415Smrg                 }
4747760c2415Smrg                 else
4748760c2415Smrg                 {
4749760c2415Smrg                         enum fbody = "_wrap_source."~name~"(forward!args)";
4750760c2415Smrg                 }
4751760c2415Smrg                 enum generateFun =
4752760c2415Smrg                     "override "~stc~"ReturnType!(TargetMembers["~n~"].type) "
4753760c2415Smrg                     ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~
4754760c2415Smrg                     "{ return "~fbody~"; }";
4755760c2415Smrg             }
4756760c2415Smrg 
4757760c2415Smrg         public:
4758760c2415Smrg             mixin mixinAll!(
4759760c2415Smrg                 staticMap!(generateFun, staticIota!(0, TargetMembers.length)));
4760760c2415Smrg         }
4761760c2415Smrg     }
4762760c2415Smrg }
4763760c2415Smrg /// ditto
4764760c2415Smrg template wrap(Targets...)
4765760c2415Smrg if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets))
4766760c2415Smrg {
4767760c2415Smrg     import std.meta : staticMap;
4768760c2415Smrg 
4769760c2415Smrg     alias wrap = .wrap!(staticMap!(Unqual, Targets));
4770760c2415Smrg }
4771760c2415Smrg 
4772760c2415Smrg // Internal class to support dynamic cross-casting
4773760c2415Smrg private interface Structural
4774760c2415Smrg {
4775760c2415Smrg     inout(Object) _wrap_getSource() inout @safe pure nothrow;
4776760c2415Smrg }
4777760c2415Smrg 
4778760c2415Smrg /**
4779760c2415Smrg  * Extract object which wrapped by $(D wrap).
4780760c2415Smrg  */
4781760c2415Smrg template unwrap(Target)
4782760c2415Smrg if (isMutable!Target)
4783760c2415Smrg {
4784760c2415Smrg     // strict downcast
4785760c2415Smrg     auto unwrap(Source)(inout Source src) @trusted pure nothrow
4786760c2415Smrg     if (is(Target : Source))
4787760c2415Smrg     {
4788760c2415Smrg         alias T = Select!(is(Source == shared), shared Target, Target);
4789760c2415Smrg         return dynamicCast!(inout T)(src);
4790760c2415Smrg     }
4791760c2415Smrg     // structural downcast
4792760c2415Smrg     auto unwrap(Source)(inout Source src) @trusted pure nothrow
4793760c2415Smrg     if (!is(Target : Source))
4794760c2415Smrg     {
4795760c2415Smrg         alias T = Select!(is(Source == shared), shared Target, Target);
4796760c2415Smrg         Object o = dynamicCast!(Object)(src);   // remove qualifier
4797760c2415Smrg         do
4798760c2415Smrg         {
4799760c2415Smrg             if (auto a = dynamicCast!(Structural)(o))
4800760c2415Smrg             {
4801760c2415Smrg                 if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource()))
4802760c2415Smrg                     return d;
4803760c2415Smrg             }
4804760c2415Smrg             else if (auto d = dynamicCast!(inout T)(o))
4805760c2415Smrg                 return d;
4806760c2415Smrg             else
4807760c2415Smrg                 break;
4808760c2415Smrg         } while (o);
4809760c2415Smrg         return null;
4810760c2415Smrg     }
4811760c2415Smrg }
4812760c2415Smrg /// ditto
4813760c2415Smrg template unwrap(Target)
4814760c2415Smrg if (!isMutable!Target)
4815760c2415Smrg {
4816760c2415Smrg     alias unwrap = .unwrap!(Unqual!Target);
4817760c2415Smrg }
4818760c2415Smrg 
4819760c2415Smrg ///
4820760c2415Smrg @system unittest
4821760c2415Smrg {
4822760c2415Smrg     interface Quack
4823760c2415Smrg     {
4824760c2415Smrg         int quack();
4825760c2415Smrg         @property int height();
4826760c2415Smrg     }
4827760c2415Smrg     interface Flyer
4828760c2415Smrg     {
4829760c2415Smrg         @property int height();
4830760c2415Smrg     }
4831760c2415Smrg     class Duck : Quack
4832760c2415Smrg     {
4833760c2415Smrg         int quack() { return 1; }
4834760c2415Smrg         @property int height() { return 10; }
4835760c2415Smrg     }
4836760c2415Smrg     class Human
4837760c2415Smrg     {
4838760c2415Smrg         int quack() { return 2; }
4839760c2415Smrg         @property int height() { return 20; }
4840760c2415Smrg     }
4841760c2415Smrg 
4842760c2415Smrg     Duck d1 = new Duck();
4843760c2415Smrg     Human h1 = new Human();
4844760c2415Smrg 
4845760c2415Smrg     interface Refleshable
4846760c2415Smrg     {
4847760c2415Smrg         int reflesh();
4848760c2415Smrg     }
4849760c2415Smrg     // does not have structural conformance
4850760c2415Smrg     static assert(!__traits(compiles, d1.wrap!Refleshable));
4851760c2415Smrg     static assert(!__traits(compiles, h1.wrap!Refleshable));
4852760c2415Smrg 
4853760c2415Smrg     // strict upcast
4854760c2415Smrg     Quack qd = d1.wrap!Quack;
4855760c2415Smrg     assert(qd is d1);
4856760c2415Smrg     assert(qd.quack() == 1);    // calls Duck.quack
4857760c2415Smrg     // strict downcast
4858760c2415Smrg     Duck d2 = qd.unwrap!Duck;
4859760c2415Smrg     assert(d2 is d1);
4860760c2415Smrg 
4861760c2415Smrg     // structural upcast
4862760c2415Smrg     Quack qh = h1.wrap!Quack;
4863760c2415Smrg     assert(qh.quack() == 2);    // calls Human.quack
4864760c2415Smrg     // structural downcast
4865760c2415Smrg     Human h2 = qh.unwrap!Human;
4866760c2415Smrg     assert(h2 is h1);
4867760c2415Smrg 
4868760c2415Smrg     // structural upcast (two steps)
4869760c2415Smrg     Quack qx = h1.wrap!Quack;   // Human -> Quack
4870760c2415Smrg     Flyer fx = qx.wrap!Flyer;   // Quack -> Flyer
4871760c2415Smrg     assert(fx.height == 20);    // calls Human.height
4872760c2415Smrg     // strucural downcast (two steps)
4873760c2415Smrg     Quack qy = fx.unwrap!Quack; // Flyer -> Quack
4874760c2415Smrg     Human hy = qy.unwrap!Human; // Quack -> Human
4875760c2415Smrg     assert(hy is h1);
4876760c2415Smrg     // strucural downcast (one step)
4877760c2415Smrg     Human hz = fx.unwrap!Human; // Flyer -> Human
4878760c2415Smrg     assert(hz is h1);
4879760c2415Smrg }
4880760c2415Smrg ///
4881760c2415Smrg @system unittest
4882760c2415Smrg {
4883760c2415Smrg     import std.traits : FunctionAttribute, functionAttributes;
4884760c2415Smrg     interface A { int run(); }
4885760c2415Smrg     interface B { int stop(); @property int status(); }
4886760c2415Smrg     class X
4887760c2415Smrg     {
4888760c2415Smrg         int run() { return 1; }
4889760c2415Smrg         int stop() { return 2; }
4890760c2415Smrg         @property int status() { return 3; }
4891760c2415Smrg     }
4892760c2415Smrg 
4893760c2415Smrg     auto x = new X();
4894760c2415Smrg     auto ab = x.wrap!(A, B);
4895760c2415Smrg     A a = ab;
4896760c2415Smrg     B b = ab;
4897760c2415Smrg     assert(a.run() == 1);
4898760c2415Smrg     assert(b.stop() == 2);
4899760c2415Smrg     assert(b.status == 3);
4900760c2415Smrg     static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
4901760c2415Smrg }
4902760c2415Smrg @system unittest
4903760c2415Smrg {
4904760c2415Smrg     class A
4905760c2415Smrg     {
4906760c2415Smrg         int draw()              { return 1; }
4907760c2415Smrg         int draw(int v)         { return v; }
4908760c2415Smrg 
4909760c2415Smrg         int draw() const        { return 2; }
4910760c2415Smrg         int draw() shared       { return 3; }
4911760c2415Smrg         int draw() shared const { return 4; }
4912760c2415Smrg         int draw() immutable    { return 5; }
4913760c2415Smrg     }
4914760c2415Smrg     interface Drawable
4915760c2415Smrg     {
4916760c2415Smrg         int draw();
4917760c2415Smrg         int draw() const;
4918760c2415Smrg         int draw() shared;
4919760c2415Smrg         int draw() shared const;
4920760c2415Smrg         int draw() immutable;
4921760c2415Smrg     }
4922760c2415Smrg     interface Drawable2
4923760c2415Smrg     {
4924760c2415Smrg         int draw(int v);
4925760c2415Smrg     }
4926760c2415Smrg 
4927760c2415Smrg     auto ma = new A();
4928760c2415Smrg     auto sa = new shared A();
4929760c2415Smrg     auto ia = new immutable A();
4930760c2415Smrg     {
4931760c2415Smrg                      Drawable  md = ma.wrap!Drawable;
4932760c2415Smrg                const Drawable  cd = ma.wrap!Drawable;
4933760c2415Smrg               shared Drawable  sd = sa.wrap!Drawable;
4934760c2415Smrg         shared const Drawable scd = sa.wrap!Drawable;
4935760c2415Smrg            immutable Drawable  id = ia.wrap!Drawable;
4936760c2415Smrg         assert( md.draw() == 1);
4937760c2415Smrg         assert( cd.draw() == 2);
4938760c2415Smrg         assert( sd.draw() == 3);
4939760c2415Smrg         assert(scd.draw() == 4);
4940760c2415Smrg         assert( id.draw() == 5);
4941760c2415Smrg     }
4942760c2415Smrg     {
4943760c2415Smrg         Drawable2 d = ma.wrap!Drawable2;
4944760c2415Smrg         static assert(!__traits(compiles, d.draw()));
4945760c2415Smrg         assert(d.draw(10) == 10);
4946760c2415Smrg     }
4947760c2415Smrg }
4948760c2415Smrg @system unittest
4949760c2415Smrg {
4950760c2415Smrg     // Bugzilla 10377
4951760c2415Smrg     import std.range, std.algorithm;
4952760c2415Smrg 
4953760c2415Smrg     interface MyInputRange(T)
4954760c2415Smrg     {
4955760c2415Smrg         @property T front();
4956760c2415Smrg         void popFront();
4957760c2415Smrg         @property bool empty();
4958760c2415Smrg     }
4959760c2415Smrg 
4960760c2415Smrg     //auto o = iota(0,10,1).inputRangeObject();
4961760c2415Smrg     //pragma(msg, __traits(allMembers, typeof(o)));
4962760c2415Smrg     auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)();
4963760c2415Smrg     assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
4964760c2415Smrg }
4965760c2415Smrg @system unittest
4966760c2415Smrg {
4967760c2415Smrg     // Bugzilla 10536
4968760c2415Smrg     interface Interface
4969760c2415Smrg     {
4970760c2415Smrg         int foo();
4971760c2415Smrg     }
4972760c2415Smrg     class Pluggable
4973760c2415Smrg     {
4974760c2415Smrg         int foo() { return 1; }
4975760c2415Smrg         @disable void opCast(T, this X)();  // !
4976760c2415Smrg     }
4977760c2415Smrg 
4978760c2415Smrg     Interface i = new Pluggable().wrap!Interface;
4979760c2415Smrg     assert(i.foo() == 1);
4980760c2415Smrg }
4981760c2415Smrg @system unittest
4982760c2415Smrg {
4983760c2415Smrg     // Enhancement 10538
4984760c2415Smrg     interface Interface
4985760c2415Smrg     {
4986760c2415Smrg         int foo();
4987760c2415Smrg         int bar(int);
4988760c2415Smrg     }
4989760c2415Smrg     class Pluggable
4990760c2415Smrg     {
4991760c2415Smrg         int opDispatch(string name, A...)(A args) { return 100; }
4992760c2415Smrg     }
4993760c2415Smrg 
4994760c2415Smrg     Interface i = wrap!Interface(new Pluggable());
4995760c2415Smrg     assert(i.foo() == 100);
4996760c2415Smrg     assert(i.bar(10) == 100);
4997760c2415Smrg }
4998760c2415Smrg 
4999760c2415Smrg // Make a tuple of non-static function symbols
5000760c2415Smrg package template GetOverloadedMethods(T)
5001760c2415Smrg {
5002760c2415Smrg     import std.meta : Filter;
5003760c2415Smrg 
5004760c2415Smrg     alias allMembers = AliasSeq!(__traits(allMembers, T));
5005760c2415Smrg     template follows(size_t i = 0)
5006760c2415Smrg     {
5007760c2415Smrg         static if (i >= allMembers.length)
5008760c2415Smrg         {
5009760c2415Smrg             alias follows = AliasSeq!();
5010760c2415Smrg         }
5011760c2415Smrg         else static if (!__traits(compiles, mixin("T."~allMembers[i])))
5012760c2415Smrg         {
5013760c2415Smrg             alias follows = follows!(i + 1);
5014760c2415Smrg         }
5015760c2415Smrg         else
5016760c2415Smrg         {
5017760c2415Smrg             enum name = allMembers[i];
5018760c2415Smrg 
5019760c2415Smrg             template isMethod(alias f)
5020760c2415Smrg             {
5021760c2415Smrg                 static if (is(typeof(&f) F == F*) && is(F == function))
5022760c2415Smrg                     enum isMethod = !__traits(isStaticFunction, f);
5023760c2415Smrg                 else
5024760c2415Smrg                     enum isMethod = false;
5025760c2415Smrg             }
5026760c2415Smrg             alias follows = AliasSeq!(
5027760c2415Smrg                 std.meta.Filter!(isMethod, __traits(getOverloads, T, name)),
5028760c2415Smrg                 follows!(i + 1));
5029760c2415Smrg         }
5030760c2415Smrg     }
5031760c2415Smrg     alias GetOverloadedMethods = follows!();
5032760c2415Smrg }
5033760c2415Smrg // find a function from Fs that has same identifier and covariant type with f
5034760c2415Smrg private template findCovariantFunction(alias finfo, Source, Fs...)
5035760c2415Smrg {
5036760c2415Smrg     template check(size_t i = 0)
5037760c2415Smrg     {
5038760c2415Smrg         static if (i >= Fs.length)
5039760c2415Smrg             enum ptrdiff_t check = -1;
5040760c2415Smrg         else
5041760c2415Smrg         {
5042760c2415Smrg             enum ptrdiff_t check =
5043760c2415Smrg                 (finfo.name == __traits(identifier, Fs[i])) &&
5044760c2415Smrg                 isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type)
5045760c2415Smrg               ? i : check!(i + 1);
5046760c2415Smrg         }
5047760c2415Smrg     }
5048760c2415Smrg     enum x = check!();
5049760c2415Smrg     static if (x == -1 && is(typeof(Source.opDispatch)))
5050760c2415Smrg     {
5051760c2415Smrg         alias Params = Parameters!(finfo.type);
5052760c2415Smrg         enum ptrdiff_t findCovariantFunction =
5053760c2415Smrg             is(typeof((             Source).init.opDispatch!(finfo.name)(Params.init))) ||
5054760c2415Smrg             is(typeof((       const Source).init.opDispatch!(finfo.name)(Params.init))) ||
5055760c2415Smrg             is(typeof((   immutable Source).init.opDispatch!(finfo.name)(Params.init))) ||
5056760c2415Smrg             is(typeof((      shared Source).init.opDispatch!(finfo.name)(Params.init))) ||
5057760c2415Smrg             is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init)))
5058760c2415Smrg           ? ptrdiff_t.max : -1;
5059760c2415Smrg     }
5060760c2415Smrg     else
5061760c2415Smrg         enum ptrdiff_t findCovariantFunction = x;
5062760c2415Smrg }
5063760c2415Smrg 
5064760c2415Smrg private enum TypeModifier
5065760c2415Smrg {
5066760c2415Smrg     mutable     = 0,    // type is mutable
5067760c2415Smrg     const_      = 1,    // type is const
5068760c2415Smrg     immutable_  = 2,    // type is immutable
5069760c2415Smrg     shared_     = 4,    // type is shared
5070760c2415Smrg     inout_      = 8,    // type is wild
5071760c2415Smrg }
5072760c2415Smrg private template TypeMod(T)
5073760c2415Smrg {
5074760c2415Smrg     static if (is(T == immutable))
5075760c2415Smrg     {
5076760c2415Smrg         enum mod1 = TypeModifier.immutable_;
5077760c2415Smrg         enum mod2 = 0;
5078760c2415Smrg     }
5079760c2415Smrg     else
5080760c2415Smrg     {
5081760c2415Smrg         enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0;
5082760c2415Smrg         static if (is(T == const))
5083760c2415Smrg             enum mod2 = TypeModifier.const_;
5084760c2415Smrg         else static if (is(T == inout))
5085760c2415Smrg             enum mod2 = TypeModifier.inout_;
5086760c2415Smrg         else
5087760c2415Smrg             enum mod2 = TypeModifier.mutable;
5088760c2415Smrg     }
5089760c2415Smrg     enum TypeMod = cast(TypeModifier)(mod1 | mod2);
5090760c2415Smrg }
5091760c2415Smrg 
5092760c2415Smrg version (unittest)
5093760c2415Smrg {
5094760c2415Smrg     private template UnittestFuncInfo(alias f)
5095760c2415Smrg     {
5096760c2415Smrg         enum name = __traits(identifier, f);
5097760c2415Smrg         alias type = FunctionTypeOf!f;
5098760c2415Smrg     }
5099760c2415Smrg }
5100760c2415Smrg @system unittest
5101760c2415Smrg {
5102760c2415Smrg     class A
5103760c2415Smrg     {
5104760c2415Smrg         int draw() { return 1; }
5105760c2415Smrg         @property int value() { return 2; }
5106760c2415Smrg         final int run() { return 3; }
5107760c2415Smrg     }
5108760c2415Smrg     alias methods = GetOverloadedMethods!A;
5109760c2415Smrg 
5110760c2415Smrg     alias int F1();
5111760c2415Smrg     alias @property int F2();
5112760c2415Smrg     alias string F3();
5113760c2415Smrg     alias nothrow @trusted uint F4();
5114760c2415Smrg     alias int F5(Object);
5115760c2415Smrg     alias bool F6(Object);
5116760c2415Smrg     static assert(methods.length == 3 + 4);
5117760c2415Smrg     static assert(__traits(identifier, methods[0]) == "draw"     && is(typeof(&methods[0]) == F1*));
5118760c2415Smrg     static assert(__traits(identifier, methods[1]) == "value"    && is(typeof(&methods[1]) == F2*));
5119760c2415Smrg     static assert(__traits(identifier, methods[2]) == "run"      && is(typeof(&methods[2]) == F1*));
5120760c2415Smrg 
5121760c2415Smrg     int draw();
5122760c2415Smrg     @property int value();
5123760c2415Smrg     void opEquals();
5124760c2415Smrg     int nomatch();
5125760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!draw,     A, methods) == 0);
5126760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!value,    A, methods) == 1);
5127760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1);
5128760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!nomatch,  A, methods) == -1);
5129760c2415Smrg 
5130760c2415Smrg     // considering opDispatch
5131760c2415Smrg     class B
5132760c2415Smrg     {
5133760c2415Smrg         void opDispatch(string name, A...)(A) {}
5134760c2415Smrg     }
5135760c2415Smrg     alias methodsB = GetOverloadedMethods!B;
5136760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!draw,     B, methodsB) == ptrdiff_t.max);
5137760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!value,    B, methodsB) == ptrdiff_t.max);
5138760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max);
5139760c2415Smrg     static assert(findCovariantFunction!(UnittestFuncInfo!nomatch,  B, methodsB) == ptrdiff_t.max);
5140760c2415Smrg }
5141760c2415Smrg 
5142760c2415Smrg package template DerivedFunctionType(T...)
5143760c2415Smrg {
5144760c2415Smrg     static if (!T.length)
5145760c2415Smrg     {
5146760c2415Smrg         alias DerivedFunctionType = void;
5147760c2415Smrg     }
5148760c2415Smrg     else static if (T.length == 1)
5149760c2415Smrg     {
5150760c2415Smrg         static if (is(T[0] == function))
5151760c2415Smrg         {
5152760c2415Smrg             alias DerivedFunctionType = T[0];
5153760c2415Smrg         }
5154760c2415Smrg         else
5155760c2415Smrg         {
5156760c2415Smrg             alias DerivedFunctionType = void;
5157760c2415Smrg         }
5158760c2415Smrg     }
5159760c2415Smrg     else static if (is(T[0] P0 == function) && is(T[1] P1 == function))
5160760c2415Smrg     {
5161760c2415Smrg         alias FA = FunctionAttribute;
5162760c2415Smrg 
5163760c2415Smrg         alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0;
5164760c2415Smrg         alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1;
5165760c2415Smrg         enum FA0 = functionAttributes!F0;
5166760c2415Smrg         enum FA1 = functionAttributes!F1;
5167760c2415Smrg 
5168760c2415Smrg         template CheckParams(size_t i = 0)
5169760c2415Smrg         {
5170760c2415Smrg             static if (i >= P0.length)
5171760c2415Smrg                 enum CheckParams = true;
5172760c2415Smrg             else
5173760c2415Smrg             {
5174760c2415Smrg                 enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) &&
5175760c2415Smrg                                    CheckParams!(i + 1);
5176760c2415Smrg             }
5177760c2415Smrg         }
5178760c2415Smrg         static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) &&
5179760c2415Smrg                    P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 &&
5180760c2415Smrg                    variadicFunctionStyle!F0 == variadicFunctionStyle!F1 &&
5181760c2415Smrg                    functionLinkage!F0 == functionLinkage!F1 &&
5182760c2415Smrg                    ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0)
5183760c2415Smrg         {
5184760c2415Smrg             alias R = Select!(is(R0 : R1), R0, R1);
5185760c2415Smrg             alias FX = FunctionTypeOf!(R function(P0));
5186760c2415Smrg             // @system is default
5187760c2415Smrg             alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system);
5188760c2415Smrg             alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]);
5189760c2415Smrg         }
5190760c2415Smrg         else
5191760c2415Smrg             alias DerivedFunctionType = void;
5192760c2415Smrg     }
5193760c2415Smrg     else
5194760c2415Smrg         alias DerivedFunctionType = void;
5195760c2415Smrg }
5196760c2415Smrg @safe unittest
5197760c2415Smrg {
5198760c2415Smrg     // attribute covariance
5199760c2415Smrg     alias int F1();
5200760c2415Smrg     static assert(is(DerivedFunctionType!(F1, F1) == F1));
5201760c2415Smrg     alias int F2() pure nothrow;
5202760c2415Smrg     static assert(is(DerivedFunctionType!(F1, F2) == F2));
5203760c2415Smrg     alias int F3() @safe;
5204760c2415Smrg     alias int F23() @safe pure nothrow;
5205760c2415Smrg     static assert(is(DerivedFunctionType!(F2, F3) == F23));
5206760c2415Smrg 
5207760c2415Smrg     // return type covariance
5208760c2415Smrg     alias long F4();
5209760c2415Smrg     static assert(is(DerivedFunctionType!(F1, F4) == void));
5210760c2415Smrg     class C {}
5211760c2415Smrg     class D : C {}
5212760c2415Smrg     alias C F5();
5213760c2415Smrg     alias D F6();
5214760c2415Smrg     static assert(is(DerivedFunctionType!(F5, F6) == F6));
5215760c2415Smrg     alias typeof(null) F7();
5216760c2415Smrg     alias int[] F8();
5217760c2415Smrg     alias int* F9();
5218760c2415Smrg     static assert(is(DerivedFunctionType!(F5, F7) == F7));
5219760c2415Smrg     static assert(is(DerivedFunctionType!(F7, F8) == void));
5220760c2415Smrg     static assert(is(DerivedFunctionType!(F7, F9) == F7));
5221760c2415Smrg 
5222760c2415Smrg     // variadic type equality
5223760c2415Smrg     alias int F10(int);
5224760c2415Smrg     alias int F11(int...);
5225760c2415Smrg     alias int F12(int, ...);
5226760c2415Smrg     static assert(is(DerivedFunctionType!(F10, F11) == void));
5227760c2415Smrg     static assert(is(DerivedFunctionType!(F10, F12) == void));
5228760c2415Smrg     static assert(is(DerivedFunctionType!(F11, F12) == void));
5229760c2415Smrg 
5230760c2415Smrg     // linkage equality
5231760c2415Smrg     alias extern(C) int F13(int);
5232760c2415Smrg     alias extern(D) int F14(int);
5233760c2415Smrg     alias extern(Windows) int F15(int);
5234760c2415Smrg     static assert(is(DerivedFunctionType!(F13, F14) == void));
5235760c2415Smrg     static assert(is(DerivedFunctionType!(F13, F15) == void));
5236760c2415Smrg     static assert(is(DerivedFunctionType!(F14, F15) == void));
5237760c2415Smrg 
5238760c2415Smrg     // ref & @property equality
5239760c2415Smrg     alias int F16(int);
5240760c2415Smrg     alias ref int F17(int);
5241760c2415Smrg     alias @property int F18(int);
5242760c2415Smrg     static assert(is(DerivedFunctionType!(F16, F17) == void));
5243760c2415Smrg     static assert(is(DerivedFunctionType!(F16, F18) == void));
5244760c2415Smrg     static assert(is(DerivedFunctionType!(F17, F18) == void));
5245760c2415Smrg }
5246760c2415Smrg 
5247760c2415Smrg package template staticIota(int beg, int end)
5248760c2415Smrg {
5249760c2415Smrg     static if (beg + 1 >= end)
5250760c2415Smrg     {
5251760c2415Smrg         static if (beg >= end)
5252760c2415Smrg         {
5253760c2415Smrg             alias staticIota = AliasSeq!();
5254760c2415Smrg         }
5255760c2415Smrg         else
5256760c2415Smrg         {
5257760c2415Smrg             alias staticIota = AliasSeq!(+beg);
5258760c2415Smrg         }
5259760c2415Smrg     }
5260760c2415Smrg     else
5261760c2415Smrg     {
5262760c2415Smrg         enum mid = beg + (end - beg) / 2;
5263760c2415Smrg         alias staticIota = AliasSeq!(staticIota!(beg, mid), staticIota!(mid, end));
5264760c2415Smrg     }
5265760c2415Smrg }
5266760c2415Smrg 
5267760c2415Smrg package template mixinAll(mixins...)
5268760c2415Smrg {
5269760c2415Smrg     static if (mixins.length == 1)
5270760c2415Smrg     {
5271760c2415Smrg         static if (is(typeof(mixins[0]) == string))
5272760c2415Smrg         {
5273760c2415Smrg             mixin(mixins[0]);
5274760c2415Smrg         }
5275760c2415Smrg         else
5276760c2415Smrg         {
5277760c2415Smrg             alias it = mixins[0];
5278760c2415Smrg             mixin it;
5279760c2415Smrg         }
5280760c2415Smrg     }
5281760c2415Smrg     else static if (mixins.length >= 2)
5282760c2415Smrg     {
5283760c2415Smrg         mixin mixinAll!(mixins[ 0 .. $/2]);
5284760c2415Smrg         mixin mixinAll!(mixins[$/2 .. $ ]);
5285760c2415Smrg     }
5286760c2415Smrg }
5287760c2415Smrg 
5288760c2415Smrg package template Bind(alias Template, args1...)
5289760c2415Smrg {
5290760c2415Smrg     alias Bind(args2...) = Template!(args1, args2);
5291760c2415Smrg }
5292760c2415Smrg 
5293760c2415Smrg 
5294760c2415Smrg /**
5295760c2415Smrg Options regarding auto-initialization of a $(D RefCounted) object (see
5296760c2415Smrg the definition of $(D RefCounted) below).
5297760c2415Smrg  */
5298760c2415Smrg enum RefCountedAutoInitialize
5299760c2415Smrg {
5300760c2415Smrg     /// Do not auto-initialize the object
5301760c2415Smrg     no,
5302760c2415Smrg     /// Auto-initialize the object
5303760c2415Smrg     yes,
5304760c2415Smrg }
5305760c2415Smrg 
5306760c2415Smrg /**
5307760c2415Smrg Defines a reference-counted object containing a $(D T) value as
5308760c2415Smrg payload.
5309760c2415Smrg 
5310760c2415Smrg An instance of $(D RefCounted) is a reference to a structure,
5311760c2415Smrg which is referred to as the $(I store), or $(I storage implementation
5312760c2415Smrg struct) in this documentation.  The store contains a reference count
5313760c2415Smrg and the $(D T) payload.  $(D RefCounted) uses $(D malloc) to allocate
5314760c2415Smrg the store.  As instances of $(D RefCounted) are copied or go out of
5315760c2415Smrg scope, they will automatically increment or decrement the reference
5316760c2415Smrg count.  When the reference count goes down to zero, $(D RefCounted)
5317760c2415Smrg will call $(D destroy) against the payload and call $(D free) to
5318760c2415Smrg deallocate the store.  If the $(D T) payload contains any references
5319760c2415Smrg to GC-allocated memory, then `RefCounted` will add it to the GC memory
5320760c2415Smrg that is scanned for pointers, and remove it from GC scanning before
5321760c2415Smrg $(D free) is called on the store.
5322760c2415Smrg 
5323760c2415Smrg One important consequence of $(D destroy) is that it will call the
5324760c2415Smrg destructor of the $(D T) payload.  GC-managed references are not
5325760c2415Smrg guaranteed to be valid during a destructor call, but other members of
5326760c2415Smrg $(D T), such as file handles or pointers to $(D malloc) memory, will
5327760c2415Smrg still be valid during the destructor call.  This allows the $(D T) to
5328760c2415Smrg deallocate or clean up any non-GC resources immediately after the
5329760c2415Smrg reference count has reached zero.
5330760c2415Smrg 
5331760c2415Smrg $(D RefCounted) is unsafe and should be used with care. No references
5332760c2415Smrg to the payload should be escaped outside the $(D RefCounted) object.
5333760c2415Smrg 
5334760c2415Smrg The $(D autoInit) option makes the object ensure the store is
5335760c2415Smrg automatically initialized. Leaving $(D autoInit ==
5336760c2415Smrg RefCountedAutoInitialize.yes) (the default option) is convenient but
5337760c2415Smrg has the cost of a test whenever the payload is accessed. If $(D
5338760c2415Smrg autoInit == RefCountedAutoInitialize.no), user code must call either
5339760c2415Smrg $(D refCountedStore.isInitialized) or $(D refCountedStore.ensureInitialized)
5340760c2415Smrg before attempting to access the payload. Not doing so results in null
5341760c2415Smrg pointer dereference.
5342760c2415Smrg  */
5343760c2415Smrg struct RefCounted(T, RefCountedAutoInitialize autoInit =
5344760c2415Smrg         RefCountedAutoInitialize.yes)
5345760c2415Smrg if (!is(T == class) && !(is(T == interface)))
5346760c2415Smrg {
5347760c2415Smrg     extern(C) private pure nothrow @nogc static // TODO remove pure when https://issues.dlang.org/show_bug.cgi?id=15862 has been fixed
5348760c2415Smrg     {
5349760c2415Smrg         pragma(mangle, "free") void pureFree( void *ptr );
5350760c2415Smrg         pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null );
5351760c2415Smrg         pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p );
5352760c2415Smrg     }
5353760c2415Smrg 
5354760c2415Smrg     /// $(D RefCounted) storage implementation.
5355760c2415Smrg     struct RefCountedStore
5356760c2415Smrg     {
5357760c2415Smrg         import core.memory : pureMalloc;
5358760c2415Smrg         private struct Impl
5359760c2415Smrg         {
5360760c2415Smrg             T _payload;
5361760c2415Smrg             size_t _count;
5362760c2415Smrg         }
5363760c2415Smrg 
5364760c2415Smrg         private Impl* _store;
5365760c2415Smrg 
5366760c2415Smrg         private void initialize(A...)(auto ref A args)
5367760c2415Smrg         {
5368760c2415Smrg             import core.exception : onOutOfMemoryError;
5369760c2415Smrg             import std.conv : emplace;
5370760c2415Smrg 
5371760c2415Smrg             _store = cast(Impl*) pureMalloc(Impl.sizeof);
5372760c2415Smrg             if (_store is null)
5373760c2415Smrg                 onOutOfMemoryError();
5374760c2415Smrg             static if (hasIndirections!T)
5375760c2415Smrg                 pureGcAddRange(&_store._payload, T.sizeof);
5376760c2415Smrg             emplace(&_store._payload, args);
5377760c2415Smrg             _store._count = 1;
5378760c2415Smrg         }
5379760c2415Smrg 
5380760c2415Smrg         private void move(ref T source)
5381760c2415Smrg         {
5382760c2415Smrg             import core.exception : onOutOfMemoryError;
5383760c2415Smrg             import core.stdc.string : memcpy, memset;
5384760c2415Smrg 
5385760c2415Smrg             _store = cast(Impl*) pureMalloc(Impl.sizeof);
5386760c2415Smrg             if (_store is null)
5387760c2415Smrg                 onOutOfMemoryError();
5388760c2415Smrg             static if (hasIndirections!T)
5389760c2415Smrg                 pureGcAddRange(&_store._payload, T.sizeof);
5390760c2415Smrg 
5391760c2415Smrg             // Can't use std.algorithm.move(source, _store._payload)
5392760c2415Smrg             // here because it requires the target to be initialized.
5393760c2415Smrg             // Might be worth to add this as `moveEmplace`
5394760c2415Smrg 
5395760c2415Smrg             // Can avoid destructing result.
5396760c2415Smrg             static if (hasElaborateAssign!T || !isAssignable!T)
5397760c2415Smrg                 memcpy(&_store._payload, &source, T.sizeof);
5398760c2415Smrg             else
5399760c2415Smrg                 _store._payload = source;
5400760c2415Smrg 
5401760c2415Smrg             // If the source defines a destructor or a postblit hook, we must obliterate the
5402760c2415Smrg             // object in order to avoid double freeing and undue aliasing
5403760c2415Smrg             static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)
5404760c2415Smrg             {
5405760c2415Smrg                 // If T is nested struct, keep original context pointer
5406760c2415Smrg                 static if (__traits(isNested, T))
5407760c2415Smrg                     enum sz = T.sizeof - (void*).sizeof;
5408760c2415Smrg                 else
5409760c2415Smrg                     enum sz = T.sizeof;
5410760c2415Smrg 
5411760c2415Smrg                 auto init = typeid(T).initializer();
5412760c2415Smrg                 if (init.ptr is null) // null ptr means initialize to 0s
5413760c2415Smrg                     memset(&source, 0, sz);
5414760c2415Smrg                 else
5415760c2415Smrg                     memcpy(&source, init.ptr, sz);
5416760c2415Smrg             }
5417760c2415Smrg 
5418760c2415Smrg             _store._count = 1;
5419760c2415Smrg         }
5420760c2415Smrg 
5421760c2415Smrg         /**
5422760c2415Smrg            Returns $(D true) if and only if the underlying store has been
5423760c2415Smrg            allocated and initialized.
5424760c2415Smrg         */
5425760c2415Smrg         @property nothrow @safe pure @nogc
5426760c2415Smrg         bool isInitialized() const
5427760c2415Smrg         {
5428760c2415Smrg             return _store !is null;
5429760c2415Smrg         }
5430760c2415Smrg 
5431760c2415Smrg         /**
5432760c2415Smrg            Returns underlying reference count if it is allocated and initialized
5433760c2415Smrg            (a positive integer), and $(D 0) otherwise.
5434760c2415Smrg         */
5435760c2415Smrg         @property nothrow @safe pure @nogc
5436760c2415Smrg         size_t refCount() const
5437760c2415Smrg         {
5438760c2415Smrg             return isInitialized ? _store._count : 0;
5439760c2415Smrg         }
5440760c2415Smrg 
5441760c2415Smrg         /**
5442760c2415Smrg            Makes sure the payload was properly initialized. Such a
5443760c2415Smrg            call is typically inserted before using the payload.
5444760c2415Smrg         */
5445760c2415Smrg         void ensureInitialized()
5446760c2415Smrg         {
5447760c2415Smrg             if (!isInitialized) initialize();
5448760c2415Smrg         }
5449760c2415Smrg 
5450760c2415Smrg     }
5451760c2415Smrg     RefCountedStore _refCounted;
5452760c2415Smrg 
5453760c2415Smrg     /// Returns storage implementation struct.
5454760c2415Smrg     @property nothrow @safe
5455760c2415Smrg     ref inout(RefCountedStore) refCountedStore() inout
5456760c2415Smrg     {
5457760c2415Smrg         return _refCounted;
5458760c2415Smrg     }
5459760c2415Smrg 
5460760c2415Smrg /**
5461760c2415Smrg Constructor that initializes the payload.
5462760c2415Smrg 
5463760c2415Smrg Postcondition: $(D refCountedStore.isInitialized)
5464760c2415Smrg  */
5465760c2415Smrg     this(A...)(auto ref A args) if (A.length > 0)
5466760c2415Smrg     {
5467760c2415Smrg         _refCounted.initialize(args);
5468760c2415Smrg     }
5469760c2415Smrg 
5470760c2415Smrg     /// Ditto
5471760c2415Smrg     this(T val)
5472760c2415Smrg     {
5473760c2415Smrg         _refCounted.move(val);
5474760c2415Smrg     }
5475760c2415Smrg 
5476760c2415Smrg /**
5477760c2415Smrg Constructor that tracks the reference count appropriately. If $(D
5478760c2415Smrg !refCountedStore.isInitialized), does nothing.
5479760c2415Smrg  */
5480760c2415Smrg     this(this) @safe pure nothrow @nogc
5481760c2415Smrg     {
5482760c2415Smrg         if (!_refCounted.isInitialized) return;
5483760c2415Smrg         ++_refCounted._store._count;
5484760c2415Smrg     }
5485760c2415Smrg 
5486760c2415Smrg /**
5487760c2415Smrg Destructor that tracks the reference count appropriately. If $(D
5488760c2415Smrg !refCountedStore.isInitialized), does nothing. When the reference count goes
5489760c2415Smrg down to zero, calls $(D destroy) agaist the payload and calls $(D free)
5490760c2415Smrg to deallocate the corresponding resource.
5491760c2415Smrg  */
5492760c2415Smrg     ~this()
5493760c2415Smrg     {
5494760c2415Smrg         if (!_refCounted.isInitialized) return;
5495760c2415Smrg         assert(_refCounted._store._count > 0);
5496760c2415Smrg         if (--_refCounted._store._count)
5497760c2415Smrg             return;
5498760c2415Smrg         // Done, deallocate
5499760c2415Smrg         .destroy(_refCounted._store._payload);
5500760c2415Smrg         static if (hasIndirections!T)
5501760c2415Smrg         {
5502760c2415Smrg             pureGcRemoveRange(&_refCounted._store._payload);
5503760c2415Smrg         }
5504760c2415Smrg 
5505760c2415Smrg         pureFree(_refCounted._store);
5506760c2415Smrg         _refCounted._store = null;
5507760c2415Smrg     }
5508760c2415Smrg 
5509760c2415Smrg /**
5510760c2415Smrg Assignment operators
5511760c2415Smrg  */
5512760c2415Smrg     void opAssign(typeof(this) rhs)
5513760c2415Smrg     {
5514760c2415Smrg         import std.algorithm.mutation : swap;
5515760c2415Smrg 
5516760c2415Smrg         swap(_refCounted._store, rhs._refCounted._store);
5517760c2415Smrg     }
5518760c2415Smrg 
5519760c2415Smrg /// Ditto
5520760c2415Smrg     void opAssign(T rhs)
5521760c2415Smrg     {
5522760c2415Smrg         import std.algorithm.mutation : move;
5523760c2415Smrg 
5524760c2415Smrg         static if (autoInit == RefCountedAutoInitialize.yes)
5525760c2415Smrg         {
5526760c2415Smrg             _refCounted.ensureInitialized();
5527760c2415Smrg         }
5528760c2415Smrg         else
5529760c2415Smrg         {
5530760c2415Smrg             assert(_refCounted.isInitialized);
5531760c2415Smrg         }
5532760c2415Smrg         move(rhs, _refCounted._store._payload);
5533760c2415Smrg     }
5534760c2415Smrg 
5535760c2415Smrg     //version to have a single properly ddoc'ed function (w/ correct sig)
5536760c2415Smrg     version (StdDdoc)
5537760c2415Smrg     {
5538760c2415Smrg         /**
5539760c2415Smrg         Returns a reference to the payload. If (autoInit ==
5540760c2415Smrg         RefCountedAutoInitialize.yes), calls $(D
5541760c2415Smrg         refCountedStore.ensureInitialized). Otherwise, just issues $(D
5542760c2415Smrg         assert(refCountedStore.isInitialized)). Used with $(D alias
5543760c2415Smrg         refCountedPayload this;), so callers can just use the $(D RefCounted)
5544760c2415Smrg         object as a $(D T).
5545760c2415Smrg 
5546760c2415Smrg         $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
5547760c2415Smrg         So if $(D autoInit == RefCountedAutoInitialize.no)
5548760c2415Smrg         or called for a constant or immutable object, then
5549760c2415Smrg         $(D refCountedPayload) will also be qualified as safe and nothrow
5550760c2415Smrg         (but will still assert if not initialized).
5551760c2415Smrg          */
5552760c2415Smrg         @property
5553760c2415Smrg         ref T refCountedPayload() return;
5554760c2415Smrg 
5555760c2415Smrg         /// ditto
5556760c2415Smrg         @property nothrow @safe pure @nogc
5557760c2415Smrg         ref inout(T) refCountedPayload() inout return;
5558760c2415Smrg     }
5559760c2415Smrg     else
5560760c2415Smrg     {
5561760c2415Smrg         static if (autoInit == RefCountedAutoInitialize.yes)
5562760c2415Smrg         {
5563760c2415Smrg             //Can't use inout here because of potential mutation
5564760c2415Smrg             @property
5565760c2415Smrg             ref T refCountedPayload() return
5566760c2415Smrg             {
5567760c2415Smrg                 _refCounted.ensureInitialized();
5568760c2415Smrg                 return _refCounted._store._payload;
5569760c2415Smrg             }
5570760c2415Smrg         }
5571760c2415Smrg 
5572760c2415Smrg         @property nothrow @safe pure @nogc
5573760c2415Smrg         ref inout(T) refCountedPayload() inout return
5574760c2415Smrg         {
5575760c2415Smrg             assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload.");
5576760c2415Smrg             return _refCounted._store._payload;
5577760c2415Smrg         }
5578760c2415Smrg     }
5579760c2415Smrg 
5580760c2415Smrg /**
5581760c2415Smrg Returns a reference to the payload. If (autoInit ==
5582760c2415Smrg RefCountedAutoInitialize.yes), calls $(D
5583760c2415Smrg refCountedStore.ensureInitialized). Otherwise, just issues $(D
5584760c2415Smrg assert(refCountedStore.isInitialized)).
5585760c2415Smrg  */
5586760c2415Smrg     alias refCountedPayload this;
5587760c2415Smrg }
5588760c2415Smrg 
5589760c2415Smrg ///
5590760c2415Smrg pure @system nothrow @nogc unittest
5591760c2415Smrg {
5592760c2415Smrg     // A pair of an `int` and a `size_t` - the latter being the
5593760c2415Smrg     // reference count - will be dynamically allocated
5594760c2415Smrg     auto rc1 = RefCounted!int(5);
5595760c2415Smrg     assert(rc1 == 5);
5596760c2415Smrg     // No more allocation, add just one extra reference count
5597760c2415Smrg     auto rc2 = rc1;
5598760c2415Smrg     // Reference semantics
5599760c2415Smrg     rc2 = 42;
5600760c2415Smrg     assert(rc1 == 42);
5601760c2415Smrg     // the pair will be freed when rc1 and rc2 go out of scope
5602760c2415Smrg }
5603760c2415Smrg 
5604760c2415Smrg pure @system unittest
5605760c2415Smrg {
5606760c2415Smrg     RefCounted!int* p;
5607760c2415Smrg     {
5608760c2415Smrg         auto rc1 = RefCounted!int(5);
5609760c2415Smrg         p = &rc1;
5610760c2415Smrg         assert(rc1 == 5);
5611760c2415Smrg         assert(rc1._refCounted._store._count == 1);
5612760c2415Smrg         auto rc2 = rc1;
5613760c2415Smrg         assert(rc1._refCounted._store._count == 2);
5614760c2415Smrg         // Reference semantics
5615760c2415Smrg         rc2 = 42;
5616760c2415Smrg         assert(rc1 == 42);
5617760c2415Smrg         rc2 = rc2;
5618760c2415Smrg         assert(rc2._refCounted._store._count == 2);
5619760c2415Smrg         rc1 = rc2;
5620760c2415Smrg         assert(rc1._refCounted._store._count == 2);
5621760c2415Smrg     }
5622760c2415Smrg     assert(p._refCounted._store == null);
5623760c2415Smrg 
5624760c2415Smrg     // RefCounted as a member
5625760c2415Smrg     struct A
5626760c2415Smrg     {
5627760c2415Smrg         RefCounted!int x;
5628760c2415Smrg         this(int y)
5629760c2415Smrg         {
5630760c2415Smrg             x._refCounted.initialize(y);
5631760c2415Smrg         }
5632760c2415Smrg         A copy()
5633760c2415Smrg         {
5634760c2415Smrg             auto another = this;
5635760c2415Smrg             return another;
5636760c2415Smrg         }
5637760c2415Smrg     }
5638760c2415Smrg     auto a = A(4);
5639760c2415Smrg     auto b = a.copy();
5640760c2415Smrg     assert(a.x._refCounted._store._count == 2, "BUG 4356 still unfixed");
5641760c2415Smrg }
5642760c2415Smrg 
5643760c2415Smrg pure @system nothrow @nogc unittest
5644760c2415Smrg {
5645760c2415Smrg     import std.algorithm.mutation : swap;
5646760c2415Smrg 
5647760c2415Smrg     RefCounted!int p1, p2;
5648760c2415Smrg     swap(p1, p2);
5649760c2415Smrg }
5650760c2415Smrg 
5651760c2415Smrg // 6606
5652760c2415Smrg @safe pure nothrow @nogc unittest
5653760c2415Smrg {
5654760c2415Smrg     union U {
5655760c2415Smrg        size_t i;
5656760c2415Smrg        void* p;
5657760c2415Smrg     }
5658760c2415Smrg 
5659760c2415Smrg     struct S {
5660760c2415Smrg        U u;
5661760c2415Smrg     }
5662760c2415Smrg 
5663760c2415Smrg     alias SRC = RefCounted!S;
5664760c2415Smrg }
5665760c2415Smrg 
5666760c2415Smrg // 6436
5667760c2415Smrg @system pure unittest
5668760c2415Smrg {
5669760c2415Smrg     struct S { this(ref int val) { assert(val == 3); ++val; } }
5670760c2415Smrg 
5671760c2415Smrg     int val = 3;
5672760c2415Smrg     auto s = RefCounted!S(val);
5673760c2415Smrg     assert(val == 4);
5674760c2415Smrg }
5675760c2415Smrg 
5676760c2415Smrg // gc_addRange coverage
5677760c2415Smrg @system pure unittest
5678760c2415Smrg {
5679760c2415Smrg     struct S { int* p; }
5680760c2415Smrg 
5681760c2415Smrg     auto s = RefCounted!S(null);
5682760c2415Smrg }
5683760c2415Smrg 
5684760c2415Smrg @system pure nothrow @nogc unittest
5685760c2415Smrg {
5686760c2415Smrg     RefCounted!int a;
5687760c2415Smrg     a = 5; //This should not assert
5688760c2415Smrg     assert(a == 5);
5689760c2415Smrg 
5690760c2415Smrg     RefCounted!int b;
5691760c2415Smrg     b = a; //This should not assert either
5692760c2415Smrg     assert(b == 5);
5693760c2415Smrg 
5694760c2415Smrg     RefCounted!(int*) c;
5695760c2415Smrg }
5696760c2415Smrg 
5697760c2415Smrg /**
5698760c2415Smrg  * Initializes a `RefCounted` with `val`. The template parameter
5699760c2415Smrg  * `T` of `RefCounted` is inferred from `val`.
5700760c2415Smrg  * This function can be used to move non-copyable values to the heap.
5701760c2415Smrg  * It also disables the `autoInit` option of `RefCounted`.
5702760c2415Smrg  *
5703760c2415Smrg  * Params:
5704760c2415Smrg  *   val = The value to be reference counted
5705760c2415Smrg  * Returns:
5706760c2415Smrg  *   An initialized $(D RefCounted) containing $(D val).
5707760c2415Smrg  * See_Also:
5708760c2415Smrg  *   $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared)
5709760c2415Smrg  */
5710760c2415Smrg RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val)
5711760c2415Smrg {
5712760c2415Smrg     typeof(return) res;
5713760c2415Smrg     res._refCounted.move(val);
5714760c2415Smrg     return res;
5715760c2415Smrg }
5716760c2415Smrg 
5717760c2415Smrg ///
5718760c2415Smrg @system unittest
5719760c2415Smrg {
5720760c2415Smrg     static struct File
5721760c2415Smrg     {
5722760c2415Smrg         string name;
5723760c2415Smrg         @disable this(this); // not copyable
5724760c2415Smrg         ~this() { name = null; }
5725760c2415Smrg     }
5726760c2415Smrg 
5727760c2415Smrg     auto file = File("name");
5728760c2415Smrg     assert(file.name == "name");
5729760c2415Smrg     // file cannot be copied and has unique ownership
5730760c2415Smrg     static assert(!__traits(compiles, {auto file2 = file;}));
5731760c2415Smrg 
5732760c2415Smrg     // make the file refcounted to share ownership
5733760c2415Smrg     import std.algorithm.mutation : move;
5734760c2415Smrg     auto rcFile = refCounted(move(file));
5735760c2415Smrg     assert(rcFile.name == "name");
5736760c2415Smrg     assert(file.name == null);
5737760c2415Smrg     auto rcFile2 = rcFile;
5738760c2415Smrg     assert(rcFile.refCountedStore.refCount == 2);
5739760c2415Smrg     // file gets properly closed when last reference is dropped
5740760c2415Smrg }
5741760c2415Smrg 
5742760c2415Smrg /**
5743760c2415Smrg     Creates a proxy for the value `a` that will forward all operations
5744760c2415Smrg     while disabling implicit conversions. The aliased item `a` must be
5745760c2415Smrg     an $(B lvalue). This is useful for creating a new type from the
5746760c2415Smrg     "base" type (though this is $(B not) a subtype-supertype
5747760c2415Smrg     relationship; the new type is not related to the old type in any way,
5748760c2415Smrg     by design).
5749760c2415Smrg 
5750760c2415Smrg     The new type supports all operations that the underlying type does,
5751760c2415Smrg     including all operators such as `+`, `--`, `<`, `[]`, etc.
5752760c2415Smrg 
5753760c2415Smrg     Params:
5754760c2415Smrg         a = The value to act as a proxy for all operations. It must
5755760c2415Smrg             be an lvalue.
5756760c2415Smrg  */
5757760c2415Smrg mixin template Proxy(alias a)
5758760c2415Smrg {
5759760c2415Smrg     private alias ValueType = typeof({ return a; }());
5760760c2415Smrg 
5761760c2415Smrg     /* Determine if 'T.a' can referenced via a const(T).
5762760c2415Smrg      * Use T* as the parameter because 'scope' inference needs a fully
5763760c2415Smrg      * analyzed T, which doesn't work when accessibleFrom() is used in a
5764760c2415Smrg      * 'static if' in the definition of Proxy or T.
5765760c2415Smrg      */
5766760c2415Smrg     private enum bool accessibleFrom(T) =
5767760c2415Smrg         is(typeof((T* self){ cast(void) mixin("(*self)."~__traits(identifier, a)); }));
5768760c2415Smrg 
5769760c2415Smrg     static if (is(typeof(this) == class))
5770760c2415Smrg     {
5771760c2415Smrg         override bool opEquals(Object o)
5772760c2415Smrg         {
5773760c2415Smrg             if (auto b = cast(typeof(this))o)
5774760c2415Smrg             {
5775760c2415Smrg                 return a == mixin("b."~__traits(identifier, a));
5776760c2415Smrg             }
5777760c2415Smrg             return false;
5778760c2415Smrg         }
5779760c2415Smrg 
5780760c2415Smrg         bool opEquals(T)(T b)
5781760c2415Smrg             if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
5782760c2415Smrg         {
5783760c2415Smrg             static if (is(typeof(a.opEquals(b))))
5784760c2415Smrg                 return a.opEquals(b);
5785760c2415Smrg             else static if (is(typeof(b.opEquals(a))))
5786760c2415Smrg                 return b.opEquals(a);
5787760c2415Smrg             else
5788760c2415Smrg                 return a == b;
5789760c2415Smrg         }
5790760c2415Smrg 
5791760c2415Smrg         override int opCmp(Object o)
5792760c2415Smrg         {
5793760c2415Smrg             if (auto b = cast(typeof(this))o)
5794760c2415Smrg             {
5795760c2415Smrg                 return a < mixin("b."~__traits(identifier, a)) ? -1
5796760c2415Smrg                      : a > mixin("b."~__traits(identifier, a)) ? +1 : 0;
5797760c2415Smrg             }
5798760c2415Smrg             static if (is(ValueType == class))
5799760c2415Smrg                 return a.opCmp(o);
5800760c2415Smrg             else
5801760c2415Smrg                 throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString);
5802760c2415Smrg         }
5803760c2415Smrg 
5804760c2415Smrg         int opCmp(T)(auto ref const T b)
5805760c2415Smrg             if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
5806760c2415Smrg         {
5807760c2415Smrg             static if (is(typeof(a.opCmp(b))))
5808760c2415Smrg                 return a.opCmp(b);
5809760c2415Smrg             else static if (is(typeof(b.opCmp(a))))
5810760c2415Smrg                 return -b.opCmp(b);
5811760c2415Smrg             else
5812760c2415Smrg                 return a < b ? -1 : a > b ? +1 : 0;
5813760c2415Smrg         }
5814760c2415Smrg 
5815760c2415Smrg         static if (accessibleFrom!(const typeof(this)))
5816760c2415Smrg         {
5817760c2415Smrg             override hash_t toHash() const nothrow @trusted
5818760c2415Smrg             {
5819760c2415Smrg                 static if (is(typeof(&a) == ValueType*))
5820760c2415Smrg                     alias v = a;
5821760c2415Smrg                 else
5822760c2415Smrg                     auto v = a;     // if a is (property) function
5823760c2415Smrg                 return typeid(ValueType).getHash(cast(const void*)&v);
5824760c2415Smrg             }
5825760c2415Smrg         }
5826760c2415Smrg     }
5827760c2415Smrg     else
5828760c2415Smrg     {
5829760c2415Smrg         auto ref opEquals(this X, B)(auto ref B b)
5830760c2415Smrg         {
5831760c2415Smrg             static if (is(immutable B == immutable typeof(this)))
5832760c2415Smrg             {
5833760c2415Smrg                 return a == mixin("b."~__traits(identifier, a));
5834760c2415Smrg             }
5835760c2415Smrg             else
5836760c2415Smrg                 return a == b;
5837760c2415Smrg         }
5838760c2415Smrg 
5839760c2415Smrg         auto ref opCmp(this X, B)(auto ref B b)
5840760c2415Smrg           if (!is(typeof(a.opCmp(b))) || !is(typeof(b.opCmp(a))))
5841760c2415Smrg         {
5842760c2415Smrg             static if (is(typeof(a.opCmp(b))))
5843760c2415Smrg                 return a.opCmp(b);
5844760c2415Smrg             else static if (is(typeof(b.opCmp(a))))
5845760c2415Smrg                 return -b.opCmp(a);
5846760c2415Smrg             else static if (isFloatingPoint!ValueType || isFloatingPoint!B)
5847760c2415Smrg                 return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan;
5848760c2415Smrg             else
5849760c2415Smrg                 return a < b ? -1 : (a > b);
5850760c2415Smrg         }
5851760c2415Smrg 
5852760c2415Smrg         static if (accessibleFrom!(const typeof(this)))
5853760c2415Smrg         {
5854760c2415Smrg             hash_t toHash() const nothrow @trusted
5855760c2415Smrg             {
5856760c2415Smrg                 static if (is(typeof(&a) == ValueType*))
5857760c2415Smrg                     alias v = a;
5858760c2415Smrg                 else
5859760c2415Smrg                     auto v = a;     // if a is (property) function
5860760c2415Smrg                 return typeid(ValueType).getHash(cast(const void*)&v);
5861760c2415Smrg             }
5862760c2415Smrg         }
5863760c2415Smrg     }
5864760c2415Smrg 
5865760c2415Smrg     auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); }
5866760c2415Smrg 
5867760c2415Smrg     auto ref opCast(T, this X)() { return cast(T) a; }
5868760c2415Smrg 
5869760c2415Smrg     auto ref opIndex(this X, D...)(auto ref D i)               { return a[i]; }
5870760c2415Smrg     auto ref opSlice(this X      )()                           { return a[]; }
5871760c2415Smrg     auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b .. e]; }
5872760c2415Smrg 
5873760c2415Smrg     auto ref opUnary     (string op, this X      )()                           { return mixin(op~"a"); }
5874760c2415Smrg     auto ref opIndexUnary(string op, this X, D...)(auto ref D i)               { return mixin(op~"a[i]"); }
5875760c2415Smrg     auto ref opSliceUnary(string op, this X      )()                           { return mixin(op~"a[]"); }
5876760c2415Smrg     auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b .. e]"); }
5877760c2415Smrg 
5878760c2415Smrg     auto ref opBinary(string op, this X, B)(auto ref B b)
5879760c2415Smrg     if (op == "in" && is(typeof(a in b)) || op != "in")
5880760c2415Smrg     {
5881760c2415Smrg         return mixin("a "~op~" b");
5882760c2415Smrg     }
5883760c2415Smrg     auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); }
5884760c2415Smrg 
5885760c2415Smrg     static if (!is(typeof(this) == class))
5886760c2415Smrg     {
5887760c2415Smrg         import std.traits;
5888760c2415Smrg         static if (isAssignable!ValueType)
5889760c2415Smrg         {
5890760c2415Smrg             auto ref opAssign(this X)(auto ref typeof(this) v)
5891760c2415Smrg             {
5892760c2415Smrg                 a = mixin("v."~__traits(identifier, a));
5893760c2415Smrg                 return this;
5894760c2415Smrg             }
5895760c2415Smrg         }
5896760c2415Smrg         else
5897760c2415Smrg         {
5898760c2415Smrg             @disable void opAssign(this X)(auto ref typeof(this) v);
5899760c2415Smrg         }
5900760c2415Smrg     }
5901760c2415Smrg 
5902760c2415Smrg     auto ref opAssign     (this X, V      )(auto ref V v) if (!is(V == typeof(this))) { return a       = v; }
5903760c2415Smrg     auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i)               { return a[i]    = v; }
5904760c2415Smrg     auto ref opSliceAssign(this X, V      )(auto ref V v)                             { return a[]     = v; }
5905760c2415Smrg     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; }
5906760c2415Smrg 
5907760c2415Smrg     auto ref opOpAssign     (string op, this X, V      )(auto ref V v)
5908760c2415Smrg     {
5909760c2415Smrg         return mixin("a "      ~op~"= v");
5910760c2415Smrg     }
5911760c2415Smrg     auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i)
5912760c2415Smrg     {
5913760c2415Smrg         return mixin("a[i] "   ~op~"= v");
5914760c2415Smrg     }
5915760c2415Smrg     auto ref opSliceOpAssign(string op, this X, V      )(auto ref V v)
5916760c2415Smrg     {
5917760c2415Smrg         return mixin("a[] "    ~op~"= v");
5918760c2415Smrg     }
5919760c2415Smrg     auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e)
5920760c2415Smrg     {
5921760c2415Smrg         return mixin("a[b .. e] "~op~"= v");
5922760c2415Smrg     }
5923760c2415Smrg 
5924760c2415Smrg     template opDispatch(string name)
5925760c2415Smrg     {
5926760c2415Smrg         static if (is(typeof(__traits(getMember, a, name)) == function))
5927760c2415Smrg         {
5928760c2415Smrg             // non template function
5929760c2415Smrg             auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); }
5930760c2415Smrg         }
5931760c2415Smrg         else static if (is(typeof({ enum x = mixin("a."~name); })))
5932760c2415Smrg         {
5933760c2415Smrg             // built-in type field, manifest constant, and static non-mutable field
5934760c2415Smrg             enum opDispatch = mixin("a."~name);
5935760c2415Smrg         }
5936*0bfacb9bSmrg         else static if (__traits(isTemplate, mixin("a."~name)))
5937760c2415Smrg         {
5938760c2415Smrg             // member template
5939760c2415Smrg             template opDispatch(T...)
5940760c2415Smrg             {
5941760c2415Smrg                 enum targs = T.length ? "!T" : "";
5942760c2415Smrg                 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
5943760c2415Smrg             }
5944760c2415Smrg         }
5945*0bfacb9bSmrg         else
5946*0bfacb9bSmrg         {
5947*0bfacb9bSmrg             // field or property function
5948*0bfacb9bSmrg             @property auto ref opDispatch(this X)()                { return mixin("a."~name);        }
5949*0bfacb9bSmrg             @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
5950*0bfacb9bSmrg         }
5951*0bfacb9bSmrg 
5952760c2415Smrg     }
5953760c2415Smrg 
5954760c2415Smrg     import std.traits : isArray;
5955760c2415Smrg 
5956760c2415Smrg     static if (isArray!ValueType)
5957760c2415Smrg     {
5958760c2415Smrg         auto opDollar() const { return a.length; }
5959760c2415Smrg     }
5960760c2415Smrg     else static if (is(typeof(a.opDollar!0)))
5961760c2415Smrg     {
5962760c2415Smrg         auto ref opDollar(size_t pos)() { return a.opDollar!pos(); }
5963760c2415Smrg     }
5964760c2415Smrg     else static if (is(typeof(a.opDollar) == function))
5965760c2415Smrg     {
5966760c2415Smrg         auto ref opDollar() { return a.opDollar(); }
5967760c2415Smrg     }
5968760c2415Smrg     else static if (is(typeof(a.opDollar)))
5969760c2415Smrg     {
5970760c2415Smrg         alias opDollar = a.opDollar;
5971760c2415Smrg     }
5972760c2415Smrg }
5973760c2415Smrg 
5974760c2415Smrg ///
5975760c2415Smrg @safe unittest
5976760c2415Smrg {
5977760c2415Smrg     struct MyInt
5978760c2415Smrg     {
5979760c2415Smrg         private int value;
5980760c2415Smrg         mixin Proxy!value;
5981760c2415Smrg 
5982760c2415Smrg         this(int n){ value = n; }
5983760c2415Smrg     }
5984760c2415Smrg 
5985760c2415Smrg     MyInt n = 10;
5986760c2415Smrg 
5987760c2415Smrg     // Enable operations that original type has.
5988760c2415Smrg     ++n;
5989760c2415Smrg     assert(n == 11);
5990760c2415Smrg     assert(n * 2 == 22);
5991760c2415Smrg 
5992760c2415Smrg     void func(int n) { }
5993760c2415Smrg 
5994760c2415Smrg     // Disable implicit conversions to original type.
5995760c2415Smrg     //int x = n;
5996760c2415Smrg     //func(n);
5997760c2415Smrg }
5998760c2415Smrg 
5999760c2415Smrg ///The proxied value must be an $(B lvalue).
6000760c2415Smrg @safe unittest
6001760c2415Smrg {
6002760c2415Smrg     struct NewIntType
6003760c2415Smrg     {
6004760c2415Smrg         //Won't work; the literal '1'
6005760c2415Smrg         //is an rvalue, not an lvalue
6006760c2415Smrg         //mixin Proxy!1;
6007760c2415Smrg 
6008760c2415Smrg         //Okay, n is an lvalue
6009760c2415Smrg         int n;
6010760c2415Smrg         mixin Proxy!n;
6011760c2415Smrg 
6012760c2415Smrg         this(int n) { this.n = n; }
6013760c2415Smrg     }
6014760c2415Smrg 
6015760c2415Smrg     NewIntType nit = 0;
6016760c2415Smrg     nit++;
6017760c2415Smrg     assert(nit == 1);
6018760c2415Smrg 
6019760c2415Smrg 
6020760c2415Smrg     struct NewObjectType
6021760c2415Smrg     {
6022760c2415Smrg         Object obj;
6023760c2415Smrg         //Ok, obj is an lvalue
6024760c2415Smrg         mixin Proxy!obj;
6025760c2415Smrg 
6026760c2415Smrg         this (Object o) { obj = o; }
6027760c2415Smrg     }
6028760c2415Smrg 
6029760c2415Smrg     NewObjectType not = new Object();
6030760c2415Smrg     assert(__traits(compiles, not.toHash()));
6031760c2415Smrg }
6032760c2415Smrg 
6033760c2415Smrg /**
6034760c2415Smrg     There is one exception to the fact that the new type is not related to the
6035760c2415Smrg     old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member)
6036760c2415Smrg     functions are usable with the new type; they will be forwarded on to the
6037760c2415Smrg     proxied value.
6038760c2415Smrg  */
6039760c2415Smrg @safe unittest
6040760c2415Smrg {
6041760c2415Smrg     import std.math;
6042760c2415Smrg 
6043760c2415Smrg     float f = 1.0;
6044760c2415Smrg     assert(!f.isInfinity);
6045760c2415Smrg 
6046760c2415Smrg     struct NewFloat
6047760c2415Smrg     {
6048760c2415Smrg         float _;
6049760c2415Smrg         mixin Proxy!_;
6050760c2415Smrg 
6051760c2415Smrg         this(float f) { _ = f; }
6052760c2415Smrg     }
6053760c2415Smrg 
6054760c2415Smrg     NewFloat nf = 1.0f;
6055760c2415Smrg     assert(!nf.isInfinity);
6056760c2415Smrg }
6057760c2415Smrg 
6058760c2415Smrg @safe unittest
6059760c2415Smrg {
6060760c2415Smrg     static struct MyInt
6061760c2415Smrg     {
6062760c2415Smrg         private int value;
6063760c2415Smrg         mixin Proxy!value;
6064760c2415Smrg         this(int n) inout { value = n; }
6065760c2415Smrg 
6066760c2415Smrg         enum str = "str";
6067760c2415Smrg         static immutable arr = [1,2,3];
6068760c2415Smrg     }
6069760c2415Smrg 
6070760c2415Smrg     foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt))
6071760c2415Smrg     {
6072760c2415Smrg         T m = 10;
6073760c2415Smrg         static assert(!__traits(compiles, { int x = m; }));
6074760c2415Smrg         static assert(!__traits(compiles, { void func(int n){} func(m); }));
6075760c2415Smrg         assert(m == 10);
6076760c2415Smrg         assert(m != 20);
6077760c2415Smrg         assert(m < 20);
6078760c2415Smrg         assert(+m == 10);
6079760c2415Smrg         assert(-m == -10);
6080760c2415Smrg         assert(cast(double) m == 10.0);
6081760c2415Smrg         assert(m + 10 == 20);
6082760c2415Smrg         assert(m - 5 == 5);
6083760c2415Smrg         assert(m * 20 == 200);
6084760c2415Smrg         assert(m / 2 == 5);
6085760c2415Smrg         assert(10 + m == 20);
6086760c2415Smrg         assert(15 - m == 5);
6087760c2415Smrg         assert(20 * m == 200);
6088760c2415Smrg         assert(50 / m == 5);
6089760c2415Smrg         static if (is(T == MyInt))  // mutable
6090760c2415Smrg         {
6091760c2415Smrg             assert(++m == 11);
6092760c2415Smrg             assert(m++ == 11); assert(m == 12);
6093760c2415Smrg             assert(--m == 11);
6094760c2415Smrg             assert(m-- == 11); assert(m == 10);
6095760c2415Smrg             m = m;
6096760c2415Smrg             m = 20; assert(m == 20);
6097760c2415Smrg         }
6098760c2415Smrg         static assert(T.max == int.max);
6099760c2415Smrg         static assert(T.min == int.min);
6100760c2415Smrg         static assert(T.init == int.init);
6101760c2415Smrg         static assert(T.str == "str");
6102760c2415Smrg         static assert(T.arr == [1,2,3]);
6103760c2415Smrg     }
6104760c2415Smrg }
6105760c2415Smrg @system unittest
6106760c2415Smrg {
6107760c2415Smrg     static struct MyArray
6108760c2415Smrg     {
6109760c2415Smrg         private int[] value;
6110760c2415Smrg         mixin Proxy!value;
6111760c2415Smrg         this(int[] arr) { value = arr; }
6112760c2415Smrg         this(immutable int[] arr) immutable { value = arr; }
6113760c2415Smrg     }
6114760c2415Smrg 
6115760c2415Smrg     foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray))
6116760c2415Smrg     {
6117760c2415Smrg       static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; })))
6118760c2415Smrg         T a = [1,2,3,4].idup;   // workaround until qualified ctor is properly supported
6119760c2415Smrg       else
6120760c2415Smrg         T a = [1,2,3,4];
6121760c2415Smrg         assert(a == [1,2,3,4]);
6122760c2415Smrg         assert(a != [5,6,7,8]);
6123760c2415Smrg         assert(+a[0]    == 1);
6124760c2415Smrg         version (LittleEndian)
6125760c2415Smrg             assert(cast(ulong[]) a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]);
6126760c2415Smrg         else
6127760c2415Smrg             assert(cast(ulong[]) a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]);
6128760c2415Smrg         assert(a ~ [10,11] == [1,2,3,4,10,11]);
6129760c2415Smrg         assert(a[0]    == 1);
6130760c2415Smrg         assert(a[]     == [1,2,3,4]);
6131760c2415Smrg         assert(a[2 .. 4] == [3,4]);
6132760c2415Smrg         static if (is(T == MyArray))    // mutable
6133760c2415Smrg         {
6134760c2415Smrg             a = a;
6135760c2415Smrg             a = [5,6,7,8];  assert(a == [5,6,7,8]);
6136760c2415Smrg             a[0]     = 0;   assert(a == [0,6,7,8]);
6137760c2415Smrg             a[]      = 1;   assert(a == [1,1,1,1]);
6138760c2415Smrg             a[0 .. 3]  = 2;   assert(a == [2,2,2,1]);
6139760c2415Smrg             a[0]    += 2;   assert(a == [4,2,2,1]);
6140760c2415Smrg             a[]     *= 2;   assert(a == [8,4,4,2]);
6141760c2415Smrg             a[0 .. 2] /= 2;   assert(a == [4,2,4,2]);
6142760c2415Smrg         }
6143760c2415Smrg     }
6144760c2415Smrg }
6145760c2415Smrg @system unittest
6146760c2415Smrg {
6147760c2415Smrg     class Foo
6148760c2415Smrg     {
6149760c2415Smrg         int field;
6150760c2415Smrg 
6151760c2415Smrg         @property int val1() const { return field; }
6152760c2415Smrg         @property void val1(int n) { field = n; }
6153760c2415Smrg 
6154760c2415Smrg         @property ref int val2() { return field; }
6155760c2415Smrg 
6156760c2415Smrg         int func(int x, int y) const { return x; }
6157760c2415Smrg         void func1(ref int a) { a = 9; }
6158760c2415Smrg 
6159760c2415Smrg         T ifti1(T)(T t) { return t; }
6160760c2415Smrg         void ifti2(Args...)(Args args) { }
6161760c2415Smrg         void ifti3(T, Args...)(Args args) { }
6162760c2415Smrg 
6163760c2415Smrg         T opCast(T)(){ return T.init; }
6164760c2415Smrg 
6165760c2415Smrg         T tempfunc(T)() { return T.init; }
6166760c2415Smrg     }
6167760c2415Smrg     class Hoge
6168760c2415Smrg     {
6169760c2415Smrg         Foo foo;
6170760c2415Smrg         mixin Proxy!foo;
6171760c2415Smrg         this(Foo f) { foo = f; }
6172760c2415Smrg     }
6173760c2415Smrg 
6174760c2415Smrg     auto h = new Hoge(new Foo());
6175760c2415Smrg     int n;
6176760c2415Smrg 
6177760c2415Smrg     static assert(!__traits(compiles, { Foo f = h; }));
6178760c2415Smrg 
6179760c2415Smrg     // field
6180760c2415Smrg     h.field = 1;            // lhs of assign
6181760c2415Smrg     n = h.field;            // rhs of assign
6182760c2415Smrg     assert(h.field == 1);   // lhs of BinExp
6183760c2415Smrg     assert(1 == h.field);   // rhs of BinExp
6184760c2415Smrg     assert(n == 1);
6185760c2415Smrg 
6186760c2415Smrg     // getter/setter property function
6187760c2415Smrg     h.val1 = 4;
6188760c2415Smrg     n = h.val1;
6189760c2415Smrg     assert(h.val1 == 4);
6190760c2415Smrg     assert(4 == h.val1);
6191760c2415Smrg     assert(n == 4);
6192760c2415Smrg 
6193760c2415Smrg     // ref getter property function
6194760c2415Smrg     h.val2 = 8;
6195760c2415Smrg     n = h.val2;
6196760c2415Smrg     assert(h.val2 == 8);
6197760c2415Smrg     assert(8 == h.val2);
6198760c2415Smrg     assert(n == 8);
6199760c2415Smrg 
6200760c2415Smrg     // member function
6201760c2415Smrg     assert(h.func(2,4) == 2);
6202760c2415Smrg     h.func1(n);
6203760c2415Smrg     assert(n == 9);
6204760c2415Smrg 
6205760c2415Smrg     // IFTI
6206760c2415Smrg     assert(h.ifti1(4) == 4);
6207760c2415Smrg     h.ifti2(4);
6208760c2415Smrg     h.ifti3!int(4, 3);
6209760c2415Smrg 
6210760c2415Smrg     // bug5896 test
6211760c2415Smrg     assert(h.opCast!int() == 0);
6212760c2415Smrg     assert(cast(int) h == 0);
6213760c2415Smrg     const ih = new const Hoge(new Foo());
6214760c2415Smrg     static assert(!__traits(compiles, ih.opCast!int()));
6215760c2415Smrg     static assert(!__traits(compiles, cast(int) ih));
6216760c2415Smrg 
6217760c2415Smrg     // template member function
6218760c2415Smrg     assert(h.tempfunc!int() == 0);
6219760c2415Smrg }
6220760c2415Smrg 
6221760c2415Smrg @system unittest // about Proxy inside a class
6222760c2415Smrg {
6223760c2415Smrg     class MyClass
6224760c2415Smrg     {
6225760c2415Smrg         int payload;
6226760c2415Smrg         mixin Proxy!payload;
6227760c2415Smrg         this(int i){ payload = i; }
6228760c2415Smrg         string opCall(string msg){ return msg; }
6229760c2415Smrg         int pow(int i){ return payload ^^ i; }
6230760c2415Smrg     }
6231760c2415Smrg 
6232760c2415Smrg     class MyClass2
6233760c2415Smrg     {
6234760c2415Smrg         MyClass payload;
6235760c2415Smrg         mixin Proxy!payload;
6236760c2415Smrg         this(int i){ payload = new MyClass(i); }
6237760c2415Smrg     }
6238760c2415Smrg 
6239760c2415Smrg     class MyClass3
6240760c2415Smrg     {
6241760c2415Smrg         int payload;
6242760c2415Smrg         mixin Proxy!payload;
6243760c2415Smrg         this(int i){ payload = i; }
6244760c2415Smrg     }
6245760c2415Smrg 
6246760c2415Smrg     // opEquals
6247760c2415Smrg     Object a = new MyClass(5);
6248760c2415Smrg     Object b = new MyClass(5);
6249760c2415Smrg     Object c = new MyClass2(5);
6250760c2415Smrg     Object d = new MyClass3(5);
6251760c2415Smrg     assert(a == b);
6252760c2415Smrg     assert((cast(MyClass) a) == 5);
6253760c2415Smrg     assert(5 == (cast(MyClass) b));
6254760c2415Smrg     assert(5 == cast(MyClass2) c);
6255760c2415Smrg     assert(a != d);
6256760c2415Smrg 
6257760c2415Smrg     assert(c != a);
6258760c2415Smrg     // oops! above line is unexpected, isn't it?
6259760c2415Smrg     // the reason is below.
6260760c2415Smrg     // MyClass2.opEquals knows MyClass but,
6261760c2415Smrg     // MyClass.opEquals doesn't know MyClass2.
6262760c2415Smrg     // so, c.opEquals(a) is true, but a.opEquals(c) is false.
6263760c2415Smrg     // furthermore, opEquals(T) couldn't be invoked.
6264760c2415Smrg     assert((cast(MyClass2) c) != (cast(MyClass) a));
6265760c2415Smrg 
6266760c2415Smrg     // opCmp
6267760c2415Smrg     Object e = new MyClass2(7);
6268760c2415Smrg     assert(a < cast(MyClass2) e); // OK. and
6269760c2415Smrg     assert(e > a); // OK, but...
6270760c2415Smrg     // assert(a < e); // RUNTIME ERROR!
6271760c2415Smrg     // assert((cast(MyClass) a) < e); // RUNTIME ERROR!
6272760c2415Smrg     assert(3 < cast(MyClass) a);
6273760c2415Smrg     assert((cast(MyClass2) e) < 11);
6274760c2415Smrg 
6275760c2415Smrg     // opCall
6276760c2415Smrg     assert((cast(MyClass2) e)("hello") == "hello");
6277760c2415Smrg 
6278760c2415Smrg     // opCast
6279760c2415Smrg     assert((cast(MyClass)(cast(MyClass2) c)) == a);
6280760c2415Smrg     assert((cast(int)(cast(MyClass2) c)) == 5);
6281760c2415Smrg 
6282760c2415Smrg     // opIndex
6283760c2415Smrg     class MyClass4
6284760c2415Smrg     {
6285760c2415Smrg         string payload;
6286760c2415Smrg         mixin Proxy!payload;
6287760c2415Smrg         this(string s){ payload = s; }
6288760c2415Smrg     }
6289760c2415Smrg     class MyClass5
6290760c2415Smrg     {
6291760c2415Smrg         MyClass4 payload;
6292760c2415Smrg         mixin Proxy!payload;
6293760c2415Smrg         this(string s){ payload = new MyClass4(s); }
6294760c2415Smrg     }
6295760c2415Smrg     auto f = new MyClass4("hello");
6296760c2415Smrg     assert(f[1] == 'e');
6297760c2415Smrg     auto g = new MyClass5("hello");
6298760c2415Smrg     assert(f[1] == 'e');
6299760c2415Smrg 
6300760c2415Smrg     // opSlice
6301760c2415Smrg     assert(f[2 .. 4] == "ll");
6302760c2415Smrg 
6303760c2415Smrg     // opUnary
6304760c2415Smrg     assert(-(cast(MyClass2) c) == -5);
6305760c2415Smrg 
6306760c2415Smrg     // opBinary
6307760c2415Smrg     assert((cast(MyClass) a) + (cast(MyClass2) c) == 10);
6308760c2415Smrg     assert(5 + cast(MyClass) a == 10);
6309760c2415Smrg 
6310760c2415Smrg     // opAssign
6311760c2415Smrg     (cast(MyClass2) c) = 11;
6312760c2415Smrg     assert((cast(MyClass2) c) == 11);
6313760c2415Smrg     (cast(MyClass2) c) = new MyClass(13);
6314760c2415Smrg     assert((cast(MyClass2) c) == 13);
6315760c2415Smrg 
6316760c2415Smrg     // opOpAssign
6317760c2415Smrg     assert((cast(MyClass2) c) += 4);
6318760c2415Smrg     assert((cast(MyClass2) c) == 17);
6319760c2415Smrg 
6320760c2415Smrg     // opDispatch
6321760c2415Smrg     assert((cast(MyClass2) c).pow(2) == 289);
6322760c2415Smrg 
6323760c2415Smrg     // opDollar
6324760c2415Smrg     assert(f[2..$-1] == "ll");
6325760c2415Smrg 
6326760c2415Smrg     // toHash
6327760c2415Smrg     int[Object] hash;
6328760c2415Smrg     hash[a] = 19;
6329760c2415Smrg     hash[c] = 21;
6330760c2415Smrg     assert(hash[b] == 19);
6331760c2415Smrg     assert(hash[c] == 21);
6332760c2415Smrg }
6333760c2415Smrg 
6334760c2415Smrg @safe unittest
6335760c2415Smrg {
6336760c2415Smrg     struct MyInt
6337760c2415Smrg     {
6338760c2415Smrg         int payload;
6339760c2415Smrg 
6340760c2415Smrg         mixin Proxy!payload;
6341760c2415Smrg     }
6342760c2415Smrg 
6343760c2415Smrg     MyInt v;
6344760c2415Smrg     v = v;
6345760c2415Smrg 
6346760c2415Smrg     struct Foo
6347760c2415Smrg     {
6348760c2415Smrg         @disable void opAssign(typeof(this));
6349760c2415Smrg     }
6350760c2415Smrg     struct MyFoo
6351760c2415Smrg     {
6352760c2415Smrg         Foo payload;
6353760c2415Smrg 
6354760c2415Smrg         mixin Proxy!payload;
6355760c2415Smrg     }
6356760c2415Smrg     MyFoo f;
6357760c2415Smrg     static assert(!__traits(compiles, f = f));
6358760c2415Smrg 
6359760c2415Smrg     struct MyFoo2
6360760c2415Smrg     {
6361760c2415Smrg         Foo payload;
6362760c2415Smrg 
6363760c2415Smrg         mixin Proxy!payload;
6364760c2415Smrg 
6365760c2415Smrg         // override default Proxy behavior
6366760c2415Smrg         void opAssign(typeof(this) rhs){}
6367760c2415Smrg     }
6368760c2415Smrg     MyFoo2 f2;
6369760c2415Smrg     f2 = f2;
6370760c2415Smrg }
6371760c2415Smrg @safe unittest
6372760c2415Smrg {
6373760c2415Smrg     // bug8613
6374760c2415Smrg     static struct Name
6375760c2415Smrg     {
6376760c2415Smrg         mixin Proxy!val;
6377760c2415Smrg         private string val;
6378760c2415Smrg         this(string s) { val = s; }
6379760c2415Smrg     }
6380760c2415Smrg 
6381760c2415Smrg     bool[Name] names;
6382760c2415Smrg     names[Name("a")] = true;
6383760c2415Smrg     bool* b = Name("a") in names;
6384760c2415Smrg }
6385760c2415Smrg 
6386760c2415Smrg @system unittest
6387760c2415Smrg {
6388760c2415Smrg     // bug14213, using function for the payload
6389760c2415Smrg     static struct S
6390760c2415Smrg     {
6391760c2415Smrg         int foo() { return 12; }
6392760c2415Smrg         mixin Proxy!foo;
6393760c2415Smrg     }
6394760c2415Smrg     static class C
6395760c2415Smrg     {
6396760c2415Smrg         int foo() { return 12; }
6397760c2415Smrg         mixin Proxy!foo;
6398760c2415Smrg     }
6399760c2415Smrg     S s;
6400760c2415Smrg     assert(s + 1 == 13);
6401760c2415Smrg     C c = new C();
6402760c2415Smrg     assert(s * 2 == 24);
6403760c2415Smrg }
6404760c2415Smrg 
6405760c2415Smrg // Check all floating point comparisons for both Proxy and Typedef,
6406760c2415Smrg // also against int and a Typedef!int, to be as regression-proof
6407760c2415Smrg // as possible. bug 15561
6408760c2415Smrg @safe unittest
6409760c2415Smrg {
6410760c2415Smrg     static struct MyFloatImpl
6411760c2415Smrg     {
6412760c2415Smrg         float value;
6413760c2415Smrg         mixin Proxy!value;
6414760c2415Smrg     }
6415760c2415Smrg     static void allFail(T0, T1)(T0 a, T1 b)
6416760c2415Smrg     {
6417760c2415Smrg         assert(!(a == b));
6418760c2415Smrg         assert(!(a<b));
6419760c2415Smrg         assert(!(a <= b));
6420760c2415Smrg         assert(!(a>b));
6421760c2415Smrg         assert(!(a >= b));
6422760c2415Smrg     }
6423760c2415Smrg     foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double,
6424760c2415Smrg         float, real, Typedef!int, int))
6425760c2415Smrg     {
6426760c2415Smrg         foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float))
6427760c2415Smrg         {
6428760c2415Smrg             T1 a;
6429760c2415Smrg             T2 b;
6430760c2415Smrg 
6431760c2415Smrg             static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1))
6432760c2415Smrg                 allFail(a, b);
6433760c2415Smrg             a = 3;
6434760c2415Smrg             allFail(a, b);
6435760c2415Smrg 
6436760c2415Smrg             b = 4;
6437760c2415Smrg             assert(a != b);
6438760c2415Smrg             assert(a<b);
6439760c2415Smrg             assert(a <= b);
6440760c2415Smrg             assert(!(a>b));
6441760c2415Smrg             assert(!(a >= b));
6442760c2415Smrg 
6443760c2415Smrg             a = 4;
6444760c2415Smrg             assert(a == b);
6445760c2415Smrg             assert(!(a<b));
6446760c2415Smrg             assert(a <= b);
6447760c2415Smrg             assert(!(a>b));
6448760c2415Smrg             assert(a >= b);
6449760c2415Smrg         }
6450760c2415Smrg     }
6451760c2415Smrg }
6452760c2415Smrg 
6453760c2415Smrg /**
6454760c2415Smrg $(B Typedef) allows the creation of a unique type which is
6455760c2415Smrg based on an existing type. Unlike the $(D alias) feature,
6456760c2415Smrg $(B Typedef) ensures the two types are not considered as equals.
6457760c2415Smrg 
6458760c2415Smrg Example:
6459760c2415Smrg ----
6460760c2415Smrg alias MyInt = Typedef!int;
6461760c2415Smrg static void takeInt(int) { }
6462760c2415Smrg static void takeMyInt(MyInt) { }
6463760c2415Smrg 
6464760c2415Smrg int i;
6465760c2415Smrg takeInt(i);    // ok
6466760c2415Smrg takeMyInt(i);  // fails
6467760c2415Smrg 
6468760c2415Smrg MyInt myInt;
6469760c2415Smrg takeInt(myInt);    // fails
6470760c2415Smrg takeMyInt(myInt);  // ok
6471760c2415Smrg ----
6472760c2415Smrg 
6473760c2415Smrg Params:
6474760c2415Smrg 
6475760c2415Smrg init = Optional initial value for the new type. For example:
6476760c2415Smrg 
6477760c2415Smrg ----
6478760c2415Smrg alias MyInt = Typedef!(int, 10);
6479760c2415Smrg MyInt myInt;
6480760c2415Smrg assert(myInt == 10);  // default-initialized to 10
6481760c2415Smrg ----
6482760c2415Smrg 
6483760c2415Smrg cookie = Optional, used to create multiple unique types which are
6484760c2415Smrg based on the same origin type $(D T). For example:
6485760c2415Smrg 
6486760c2415Smrg ----
6487760c2415Smrg alias TypeInt1 = Typedef!int;
6488760c2415Smrg alias TypeInt2 = Typedef!int;
6489760c2415Smrg 
6490760c2415Smrg // The two Typedefs are the same type.
6491760c2415Smrg static assert(is(TypeInt1 == TypeInt2));
6492760c2415Smrg 
6493760c2415Smrg alias MoneyEuros = Typedef!(float, float.init, "euros");
6494760c2415Smrg alias MoneyDollars = Typedef!(float, float.init, "dollars");
6495760c2415Smrg 
6496760c2415Smrg // The two Typedefs are _not_ the same type.
6497760c2415Smrg static assert(!is(MoneyEuros == MoneyDollars));
6498760c2415Smrg ----
6499760c2415Smrg 
6500760c2415Smrg Note: If a library routine cannot handle the Typedef type,
6501760c2415Smrg you can use the $(D TypedefType) template to extract the
6502760c2415Smrg type which the Typedef wraps.
6503760c2415Smrg  */
6504760c2415Smrg struct Typedef(T, T init = T.init, string cookie=null)
6505760c2415Smrg {
6506760c2415Smrg     private T Typedef_payload = init;
6507760c2415Smrg 
6508760c2415Smrg     this(T init)
6509760c2415Smrg     {
6510760c2415Smrg         Typedef_payload = init;
6511760c2415Smrg     }
6512760c2415Smrg 
6513760c2415Smrg     this(Typedef tdef)
6514760c2415Smrg     {
6515760c2415Smrg         this(tdef.Typedef_payload);
6516760c2415Smrg     }
6517760c2415Smrg 
6518760c2415Smrg     // We need to add special overload for cast(Typedef!X) exp,
6519760c2415Smrg     // thus we can't simply inherit Proxy!Typedef_payload
6520760c2415Smrg     T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)()
6521760c2415Smrg     {
6522760c2415Smrg         return T2(cast(T) Typedef_payload);
6523760c2415Smrg     }
6524760c2415Smrg 
6525760c2415Smrg     auto ref opCast(T2, this X)()
6526760c2415Smrg     {
6527760c2415Smrg         return cast(T2) Typedef_payload;
6528760c2415Smrg     }
6529760c2415Smrg 
6530760c2415Smrg     mixin Proxy!Typedef_payload;
6531760c2415Smrg 
6532760c2415Smrg     pure nothrow @nogc @safe @property
6533760c2415Smrg     {
6534760c2415Smrg         alias TD = typeof(this);
6535760c2415Smrg         static if (isIntegral!T)
6536760c2415Smrg         {
6537760c2415Smrg             static TD min() {return TD(T.min);}
6538760c2415Smrg             static TD max() {return TD(T.max);}
6539760c2415Smrg         }
6540760c2415Smrg         else static if (isFloatingPoint!T)
6541760c2415Smrg         {
6542760c2415Smrg             static TD infinity() {return TD(T.infinity);}
6543760c2415Smrg             static TD nan() {return TD(T.nan);}
6544760c2415Smrg             static TD dig() {return TD(T.dig);}
6545760c2415Smrg             static TD epsilon() {return TD(T.epsilon);}
6546760c2415Smrg             static TD mant_dig() {return TD(T.mant_dig);}
6547760c2415Smrg             static TD max_10_exp() {return TD(T.max_10_exp);}
6548760c2415Smrg             static TD max_exp()  {return TD(T.max_exp);}
6549760c2415Smrg             static TD min_10_exp() {return TD(T.min_10_exp);}
6550760c2415Smrg             static TD min_exp() {return TD(T.min_exp);}
6551760c2415Smrg             static TD max() {return TD(T.max);}
6552760c2415Smrg             static TD min_normal() {return TD(T.min_normal);}
6553760c2415Smrg             TD re() {return TD(Typedef_payload.re);}
6554760c2415Smrg             TD im() {return TD(Typedef_payload.im);}
6555760c2415Smrg         }
6556760c2415Smrg     }
6557760c2415Smrg }
6558760c2415Smrg 
6559760c2415Smrg /**
6560760c2415Smrg Get the underlying type which a $(D Typedef) wraps.
6561760c2415Smrg If $(D T) is not a $(D Typedef) it will alias itself to $(D T).
6562760c2415Smrg */
6563760c2415Smrg template TypedefType(T)
6564760c2415Smrg {
6565760c2415Smrg     static if (is(T : Typedef!Arg, Arg))
6566760c2415Smrg         alias TypedefType = Arg;
6567760c2415Smrg     else
6568760c2415Smrg         alias TypedefType = T;
6569760c2415Smrg }
6570760c2415Smrg 
6571760c2415Smrg ///
6572760c2415Smrg @safe unittest
6573760c2415Smrg {
6574760c2415Smrg     import std.typecons : Typedef, TypedefType;
6575760c2415Smrg     import std.conv : to;
6576760c2415Smrg 
6577760c2415Smrg     alias MyInt = Typedef!int;
6578760c2415Smrg     static assert(is(TypedefType!MyInt == int));
6579760c2415Smrg 
6580760c2415Smrg     /// Instantiating with a non-Typedef will return that type
6581760c2415Smrg     static assert(is(TypedefType!int == int));
6582760c2415Smrg 
6583760c2415Smrg     string num = "5";
6584760c2415Smrg 
6585760c2415Smrg     // extract the needed type
6586760c2415Smrg     MyInt myInt = MyInt( num.to!(TypedefType!MyInt) );
6587760c2415Smrg     assert(myInt == 5);
6588760c2415Smrg 
6589760c2415Smrg     // cast to the underlying type to get the value that's being wrapped
6590760c2415Smrg     int x = cast(TypedefType!MyInt) myInt;
6591760c2415Smrg 
6592760c2415Smrg     alias MyIntInit = Typedef!(int, 42);
6593760c2415Smrg     static assert(is(TypedefType!MyIntInit == int));
6594760c2415Smrg     static assert(MyIntInit() == 42);
6595760c2415Smrg }
6596760c2415Smrg 
6597760c2415Smrg @safe unittest
6598760c2415Smrg {
6599760c2415Smrg     Typedef!int x = 10;
6600760c2415Smrg     static assert(!__traits(compiles, { int y = x; }));
6601760c2415Smrg     static assert(!__traits(compiles, { long z = x; }));
6602760c2415Smrg 
6603760c2415Smrg     Typedef!int y = 10;
6604760c2415Smrg     assert(x == y);
6605760c2415Smrg 
6606760c2415Smrg     static assert(Typedef!int.init == int.init);
6607760c2415Smrg 
6608760c2415Smrg     Typedef!(float, 1.0) z; // specifies the init
6609760c2415Smrg     assert(z == 1.0);
6610760c2415Smrg 
6611760c2415Smrg     static assert(typeof(z).init == 1.0);
6612760c2415Smrg 
6613760c2415Smrg     alias Dollar = Typedef!(int, 0, "dollar");
6614760c2415Smrg     alias Yen    = Typedef!(int, 0, "yen");
6615760c2415Smrg     static assert(!is(Dollar == Yen));
6616760c2415Smrg 
6617760c2415Smrg     Typedef!(int[3]) sa;
6618760c2415Smrg     static assert(sa.length == 3);
6619760c2415Smrg     static assert(typeof(sa).length == 3);
6620760c2415Smrg 
6621760c2415Smrg     Typedef!(int[3]) dollar1;
6622760c2415Smrg     assert(dollar1[0..$] is dollar1[0 .. 3]);
6623760c2415Smrg 
6624760c2415Smrg     Typedef!(int[]) dollar2;
6625760c2415Smrg     dollar2.length = 3;
6626760c2415Smrg     assert(dollar2[0..$] is dollar2[0 .. 3]);
6627760c2415Smrg 
6628760c2415Smrg     static struct Dollar1
6629760c2415Smrg     {
6630760c2415Smrg         static struct DollarToken {}
6631760c2415Smrg         enum opDollar = DollarToken.init;
6632760c2415Smrg         auto opSlice(size_t, DollarToken) { return 1; }
6633760c2415Smrg         auto opSlice(size_t, size_t) { return 2; }
6634760c2415Smrg     }
6635760c2415Smrg 
6636760c2415Smrg     Typedef!Dollar1 drange1;
6637760c2415Smrg     assert(drange1[0..$] == 1);
6638760c2415Smrg     assert(drange1[0 .. 1] == 2);
6639760c2415Smrg 
6640760c2415Smrg     static struct Dollar2
6641760c2415Smrg     {
6642760c2415Smrg         size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; }
6643760c2415Smrg         size_t opIndex(size_t i, size_t j) { return i + j; }
6644760c2415Smrg     }
6645760c2415Smrg 
6646760c2415Smrg     Typedef!Dollar2 drange2;
6647760c2415Smrg     assert(drange2[$, $] == 101);
6648760c2415Smrg 
6649760c2415Smrg     static struct Dollar3
6650760c2415Smrg     {
6651760c2415Smrg         size_t opDollar() { return 123; }
6652760c2415Smrg         size_t opIndex(size_t i) { return i; }
6653760c2415Smrg     }
6654760c2415Smrg 
6655760c2415Smrg     Typedef!Dollar3 drange3;
6656760c2415Smrg     assert(drange3[$] == 123);
6657760c2415Smrg }
6658760c2415Smrg 
6659760c2415Smrg @safe @nogc pure nothrow unittest // Bugzilla 11703
6660760c2415Smrg {
6661760c2415Smrg     alias I = Typedef!int;
6662760c2415Smrg     static assert(is(typeof(I.min) == I));
6663760c2415Smrg     static assert(is(typeof(I.max) == I));
6664760c2415Smrg 
6665760c2415Smrg     alias F = Typedef!double;
6666760c2415Smrg     static assert(is(typeof(F.infinity) == F));
6667760c2415Smrg     static assert(is(typeof(F.epsilon) == F));
6668760c2415Smrg 
6669760c2415Smrg     F f;
6670760c2415Smrg     assert(!is(typeof(F.re).stringof == double));
6671760c2415Smrg     assert(!is(typeof(F.im).stringof == double));
6672760c2415Smrg }
6673760c2415Smrg 
6674760c2415Smrg @safe unittest
6675760c2415Smrg {
6676760c2415Smrg     // bug8655
6677760c2415Smrg     import std.typecons;
6678760c2415Smrg     import std.bitmanip;
6679760c2415Smrg     static import core.stdc.config;
6680760c2415Smrg 
6681760c2415Smrg     alias c_ulong = Typedef!(core.stdc.config.c_ulong);
6682760c2415Smrg 
6683760c2415Smrg     static struct Foo
6684760c2415Smrg     {
6685760c2415Smrg         mixin(bitfields!(
6686760c2415Smrg             c_ulong, "NameOffset", 31,
6687760c2415Smrg             c_ulong, "NameIsString", 1
6688760c2415Smrg         ));
6689760c2415Smrg     }
6690760c2415Smrg }
6691760c2415Smrg 
6692760c2415Smrg @safe unittest // Issue 12596
6693760c2415Smrg {
6694760c2415Smrg     import std.typecons;
6695760c2415Smrg     alias TD = Typedef!int;
6696760c2415Smrg     TD x = TD(1);
6697760c2415Smrg     TD y = TD(x);
6698760c2415Smrg     assert(x == y);
6699760c2415Smrg }
6700760c2415Smrg 
6701760c2415Smrg @safe unittest // about toHash
6702760c2415Smrg {
6703760c2415Smrg     import std.typecons;
6704760c2415Smrg     {
6705760c2415Smrg         alias TD = Typedef!int;
6706760c2415Smrg         int[TD] td;
6707760c2415Smrg         td[TD(1)] = 1;
6708760c2415Smrg         assert(td[TD(1)] == 1);
6709760c2415Smrg     }
6710760c2415Smrg 
6711760c2415Smrg     {
6712760c2415Smrg         alias TD = Typedef!(int[]);
6713760c2415Smrg         int[TD] td;
6714760c2415Smrg         td[TD([1,2,3,4])] = 2;
6715760c2415Smrg         assert(td[TD([1,2,3,4])] == 2);
6716760c2415Smrg     }
6717760c2415Smrg 
6718760c2415Smrg     {
6719760c2415Smrg         alias TD = Typedef!(int[][]);
6720760c2415Smrg         int[TD] td;
6721760c2415Smrg         td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3;
6722760c2415Smrg         assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3);
6723760c2415Smrg     }
6724760c2415Smrg 
6725760c2415Smrg     {
6726760c2415Smrg         struct MyStruct{ int x; }
6727760c2415Smrg         alias TD = Typedef!MyStruct;
6728760c2415Smrg         int[TD] td;
6729760c2415Smrg         td[TD(MyStruct(10))] = 4;
6730760c2415Smrg         assert(TD(MyStruct(20)) !in td);
6731760c2415Smrg         assert(td[TD(MyStruct(10))] == 4);
6732760c2415Smrg     }
6733760c2415Smrg 
6734760c2415Smrg     {
6735760c2415Smrg         static struct MyStruct2
6736760c2415Smrg         {
6737760c2415Smrg             int x;
6738760c2415Smrg             size_t toHash() const nothrow @safe { return x; }
6739760c2415Smrg             bool opEquals(ref const MyStruct2 r) const { return r.x == x; }
6740760c2415Smrg         }
6741760c2415Smrg 
6742760c2415Smrg         alias TD = Typedef!MyStruct2;
6743760c2415Smrg         int[TD] td;
6744760c2415Smrg         td[TD(MyStruct2(50))] = 5;
6745760c2415Smrg         assert(td[TD(MyStruct2(50))] == 5);
6746760c2415Smrg     }
6747760c2415Smrg 
6748760c2415Smrg     {
6749760c2415Smrg         class MyClass{}
6750760c2415Smrg         alias TD = Typedef!MyClass;
6751760c2415Smrg         int[TD] td;
6752760c2415Smrg         auto c = new MyClass;
6753760c2415Smrg         td[TD(c)] = 6;
6754760c2415Smrg         assert(TD(new MyClass) !in td);
6755760c2415Smrg         assert(td[TD(c)] == 6);
6756760c2415Smrg     }
6757760c2415Smrg }
6758760c2415Smrg 
6759760c2415Smrg @system unittest
6760760c2415Smrg {
6761760c2415Smrg     alias String = Typedef!(char[]);
6762760c2415Smrg     alias CString = Typedef!(const(char)[]);
6763760c2415Smrg     CString cs = "fubar";
6764760c2415Smrg     String s = cast(String) cs;
6765760c2415Smrg     assert(cs == s);
6766760c2415Smrg     char[] s2 = cast(char[]) cs;
6767760c2415Smrg     const(char)[] cs2 = cast(const(char)[])s;
6768760c2415Smrg     assert(s2 == cs2);
6769760c2415Smrg }
6770760c2415Smrg 
6771760c2415Smrg /**
6772760c2415Smrg Allocates a $(D class) object right inside the current scope,
6773760c2415Smrg therefore avoiding the overhead of $(D new). This facility is unsafe;
6774760c2415Smrg it is the responsibility of the user to not escape a reference to the
6775760c2415Smrg object outside the scope.
6776760c2415Smrg 
6777760c2415Smrg The class destructor will be called when the result of `scoped()` is
6778760c2415Smrg itself destroyed.
6779760c2415Smrg 
6780760c2415Smrg Scoped class instances can be embedded in a parent `class` or `struct`,
6781760c2415Smrg just like a child struct instance. Scoped member variables must have
6782760c2415Smrg type `typeof(scoped!Class(args))`, and be initialized with a call to
6783760c2415Smrg scoped. See below for an example.
6784760c2415Smrg 
6785760c2415Smrg Note:
6786760c2415Smrg It's illegal to move a class instance even if you are sure there
6787760c2415Smrg are no pointers to it. As such, it is illegal to move a scoped object.
6788760c2415Smrg  */
6789760c2415Smrg template scoped(T)
6790760c2415Smrg     if (is(T == class))
6791760c2415Smrg {
6792760c2415Smrg     // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for
6793760c2415Smrg     // small objects). We will just use the maximum of filed alignments.
6794760c2415Smrg     alias alignment = classInstanceAlignment!T;
6795760c2415Smrg     alias aligned = _alignUp!alignment;
6796760c2415Smrg 
6797760c2415Smrg     static struct Scoped
6798760c2415Smrg     {
6799760c2415Smrg         // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory.
6800760c2415Smrg         private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void;
6801760c2415Smrg 
6802760c2415Smrg         @property inout(T) Scoped_payload() inout
6803760c2415Smrg         {
6804760c2415Smrg             void* alignedStore = cast(void*) aligned(cast(uintptr_t) Scoped_store.ptr);
6805760c2415Smrg             // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly.
6806760c2415Smrg             immutable size_t d = alignedStore - Scoped_store.ptr;
6807760c2415Smrg             size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof];
6808760c2415Smrg             if (d != *currD)
6809760c2415Smrg             {
6810760c2415Smrg                 import core.stdc.string : memmove;
6811760c2415Smrg                 memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T));
6812760c2415Smrg                 *currD = d;
6813760c2415Smrg             }
6814760c2415Smrg             return cast(inout(T)) alignedStore;
6815760c2415Smrg         }
6816760c2415Smrg         alias Scoped_payload this;
6817760c2415Smrg 
6818760c2415Smrg         @disable this();
6819760c2415Smrg         @disable this(this);
6820760c2415Smrg 
6821760c2415Smrg         ~this()
6822760c2415Smrg         {
6823760c2415Smrg             // `destroy` will also write .init but we have no functions in druntime
6824760c2415Smrg             // for deterministic finalization and memory releasing for now.
6825760c2415Smrg             .destroy(Scoped_payload);
6826760c2415Smrg         }
6827760c2415Smrg     }
6828760c2415Smrg 
6829760c2415Smrg     /** Returns the _scoped object.
6830760c2415Smrg     Params: args = Arguments to pass to $(D T)'s constructor.
6831760c2415Smrg     */
6832760c2415Smrg     @system auto scoped(Args...)(auto ref Args args)
6833760c2415Smrg     {
6834760c2415Smrg         import std.conv : emplace;
6835760c2415Smrg 
6836760c2415Smrg         Scoped result = void;
6837760c2415Smrg         void* alignedStore = cast(void*) aligned(cast(uintptr_t) result.Scoped_store.ptr);
6838760c2415Smrg         immutable size_t d = alignedStore - result.Scoped_store.ptr;
6839760c2415Smrg         *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d;
6840760c2415Smrg         emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], args);
6841760c2415Smrg         return result;
6842760c2415Smrg     }
6843760c2415Smrg }
6844760c2415Smrg 
6845760c2415Smrg ///
6846760c2415Smrg @system unittest
6847760c2415Smrg {
6848760c2415Smrg     class A
6849760c2415Smrg     {
6850760c2415Smrg         int x;
6851760c2415Smrg         this()     {x = 0;}
6852760c2415Smrg         this(int i){x = i;}
6853760c2415Smrg         ~this()    {}
6854760c2415Smrg     }
6855760c2415Smrg 
6856760c2415Smrg     // Standard usage, constructing A on the stack
6857760c2415Smrg     auto a1 = scoped!A();
6858760c2415Smrg     a1.x = 42;
6859760c2415Smrg 
6860760c2415Smrg     // Result of `scoped` call implicitly converts to a class reference
6861760c2415Smrg     A aRef = a1;
6862760c2415Smrg     assert(aRef.x == 42);
6863760c2415Smrg 
6864760c2415Smrg     // Scoped destruction
6865760c2415Smrg     {
6866760c2415Smrg         auto a2 = scoped!A(1);
6867760c2415Smrg         assert(a2.x == 1);
6868760c2415Smrg         aRef = a2;
6869760c2415Smrg         // a2 is destroyed here, calling A's destructor
6870760c2415Smrg     }
6871760c2415Smrg     // aRef is now an invalid reference
6872760c2415Smrg 
6873760c2415Smrg     // Here the temporary scoped A is immediately destroyed.
6874760c2415Smrg     // This means the reference is then invalid.
6875760c2415Smrg     version (Bug)
6876760c2415Smrg     {
6877760c2415Smrg         // Wrong, should use `auto`
6878760c2415Smrg         A invalid = scoped!A();
6879760c2415Smrg     }
6880760c2415Smrg 
6881760c2415Smrg     // Restrictions
6882760c2415Smrg     version (Bug)
6883760c2415Smrg     {
6884760c2415Smrg         import std.algorithm.mutation : move;
6885760c2415Smrg         auto invalid = a1.move; // illegal, scoped objects can't be moved
6886760c2415Smrg     }
6887760c2415Smrg     static assert(!is(typeof({
6888760c2415Smrg         auto e1 = a1; // illegal, scoped objects can't be copied
6889760c2415Smrg         assert([a1][0].x == 42); // ditto
6890760c2415Smrg     })));
6891760c2415Smrg     static assert(!is(typeof({
6892760c2415Smrg         alias ScopedObject = typeof(a1);
6893760c2415Smrg         auto e2 = ScopedObject();  // illegal, must be built via scoped!A
6894760c2415Smrg         auto e3 = ScopedObject(1); // ditto
6895760c2415Smrg     })));
6896760c2415Smrg 
6897760c2415Smrg     // Use with alias
6898760c2415Smrg     alias makeScopedA = scoped!A;
6899760c2415Smrg     auto a3 = makeScopedA();
6900760c2415Smrg     auto a4 = makeScopedA(1);
6901760c2415Smrg 
6902760c2415Smrg     // Use as member variable
6903760c2415Smrg     struct B
6904760c2415Smrg     {
6905760c2415Smrg         typeof(scoped!A()) a; // note the trailing parentheses
6906760c2415Smrg 
6907760c2415Smrg         this(int i)
6908760c2415Smrg         {
6909760c2415Smrg             // construct member
6910760c2415Smrg             a = scoped!A(i);
6911760c2415Smrg         }
6912760c2415Smrg     }
6913760c2415Smrg 
6914760c2415Smrg     // Stack-allocate
6915760c2415Smrg     auto b1 = B(5);
6916760c2415Smrg     aRef = b1.a;
6917760c2415Smrg     assert(aRef.x == 5);
6918760c2415Smrg     destroy(b1); // calls A's destructor for b1.a
6919760c2415Smrg     // aRef is now an invalid reference
6920760c2415Smrg 
6921760c2415Smrg     // Heap-allocate
6922760c2415Smrg     auto b2 = new B(6);
6923760c2415Smrg     assert(b2.a.x == 6);
6924760c2415Smrg     destroy(*b2); // calls A's destructor for b2.a
6925760c2415Smrg }
6926760c2415Smrg 
6927760c2415Smrg private uintptr_t _alignUp(uintptr_t alignment)(uintptr_t n)
6928760c2415Smrg     if (alignment > 0 && !((alignment - 1) & alignment))
6929760c2415Smrg {
6930760c2415Smrg     enum badEnd = alignment - 1; // 0b11, 0b111, ...
6931760c2415Smrg     return (n + badEnd) & ~badEnd;
6932760c2415Smrg }
6933760c2415Smrg 
6934760c2415Smrg @system unittest // Issue 6580 testcase
6935760c2415Smrg {
6936760c2415Smrg     enum alignment = (void*).alignof;
6937760c2415Smrg 
6938760c2415Smrg     static class C0 { }
6939760c2415Smrg     static class C1 { byte b; }
6940760c2415Smrg     static class C2 { byte[2] b; }
6941760c2415Smrg     static class C3 { byte[3] b; }
6942760c2415Smrg     static class C7 { byte[7] b; }
6943760c2415Smrg     static assert(scoped!C0().sizeof % alignment == 0);
6944760c2415Smrg     static assert(scoped!C1().sizeof % alignment == 0);
6945760c2415Smrg     static assert(scoped!C2().sizeof % alignment == 0);
6946760c2415Smrg     static assert(scoped!C3().sizeof % alignment == 0);
6947760c2415Smrg     static assert(scoped!C7().sizeof % alignment == 0);
6948760c2415Smrg 
6949760c2415Smrg     enum longAlignment = long.alignof;
6950760c2415Smrg     static class C1long
6951760c2415Smrg     {
6952760c2415Smrg         long long_; byte byte_ = 4;
6953760c2415Smrg         this() { }
6954760c2415Smrg         this(long _long, ref int i) { long_ = _long; ++i; }
6955760c2415Smrg     }
6956760c2415Smrg     static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; }
6957760c2415Smrg     static assert(scoped!C1long().sizeof % longAlignment == 0);
6958760c2415Smrg     static assert(scoped!C2long().sizeof % longAlignment == 0);
6959760c2415Smrg 
6960760c2415Smrg     void alignmentTest()
6961760c2415Smrg     {
6962760c2415Smrg         int var = 5;
6963760c2415Smrg         auto c1long = scoped!C1long(3, var);
6964760c2415Smrg         assert(var == 6);
6965760c2415Smrg         auto c2long = scoped!C2long();
6966760c2415Smrg         assert(cast(uint)&c1long.long_ % longAlignment == 0);
6967760c2415Smrg         assert(cast(uint)&c2long.long_ % longAlignment == 0);
6968760c2415Smrg         assert(c1long.long_ == 3 && c1long.byte_ == 4);
6969760c2415Smrg         assert(c2long.byte_ == [5, 6] && c2long.long_ == 7);
6970760c2415Smrg     }
6971760c2415Smrg 
6972760c2415Smrg     alignmentTest();
6973760c2415Smrg 
6974760c2415Smrg     version (DigitalMars)
6975760c2415Smrg     {
6976760c2415Smrg         void test(size_t size)
6977760c2415Smrg         {
6978760c2415Smrg             import core.stdc.stdlib;
6979760c2415Smrg             alloca(size);
6980760c2415Smrg             alignmentTest();
6981760c2415Smrg         }
6982760c2415Smrg         foreach (i; 0 .. 10)
6983760c2415Smrg             test(i);
6984760c2415Smrg     }
6985760c2415Smrg     else
6986760c2415Smrg     {
6987760c2415Smrg         void test(size_t size)()
6988760c2415Smrg         {
6989760c2415Smrg             byte[size] arr;
6990760c2415Smrg             alignmentTest();
6991760c2415Smrg         }
6992760c2415Smrg         foreach (i; AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
6993760c2415Smrg             test!i();
6994760c2415Smrg     }
6995760c2415Smrg }
6996760c2415Smrg 
6997760c2415Smrg @system unittest // Original Issue 6580 testcase
6998760c2415Smrg {
6999760c2415Smrg     class C { int i; byte b; }
7000760c2415Smrg 
7001760c2415Smrg     auto sa = [scoped!C(), scoped!C()];
7002760c2415Smrg     assert(cast(uint)&sa[0].i % int.alignof == 0);
7003760c2415Smrg     assert(cast(uint)&sa[1].i % int.alignof == 0); // fails
7004760c2415Smrg }
7005760c2415Smrg 
7006760c2415Smrg @system unittest
7007760c2415Smrg {
7008760c2415Smrg     class A { int x = 1; }
7009760c2415Smrg     auto a1 = scoped!A();
7010760c2415Smrg     assert(a1.x == 1);
7011760c2415Smrg     auto a2 = scoped!A();
7012760c2415Smrg     a1.x = 42;
7013760c2415Smrg     a2.x = 53;
7014760c2415Smrg     assert(a1.x == 42);
7015760c2415Smrg }
7016760c2415Smrg 
7017760c2415Smrg @system unittest
7018760c2415Smrg {
7019760c2415Smrg     class A { int x = 1; this() { x = 2; } }
7020760c2415Smrg     auto a1 = scoped!A();
7021760c2415Smrg     assert(a1.x == 2);
7022760c2415Smrg     auto a2 = scoped!A();
7023760c2415Smrg     a1.x = 42;
7024760c2415Smrg     a2.x = 53;
7025760c2415Smrg     assert(a1.x == 42);
7026760c2415Smrg }
7027760c2415Smrg 
7028760c2415Smrg @system unittest
7029760c2415Smrg {
7030760c2415Smrg     class A { int x = 1; this(int y) { x = y; } ~this() {} }
7031760c2415Smrg     auto a1 = scoped!A(5);
7032760c2415Smrg     assert(a1.x == 5);
7033760c2415Smrg     auto a2 = scoped!A(42);
7034760c2415Smrg     a1.x = 42;
7035760c2415Smrg     a2.x = 53;
7036760c2415Smrg     assert(a1.x == 42);
7037760c2415Smrg }
7038760c2415Smrg 
7039760c2415Smrg @system unittest
7040760c2415Smrg {
7041760c2415Smrg     class A { static bool dead; ~this() { dead = true; } }
7042760c2415Smrg     class B : A { static bool dead; ~this() { dead = true; } }
7043760c2415Smrg     {
7044760c2415Smrg         auto b = scoped!B();
7045760c2415Smrg     }
7046760c2415Smrg     assert(B.dead, "asdasd");
7047760c2415Smrg     assert(A.dead, "asdasd");
7048760c2415Smrg }
7049760c2415Smrg 
7050760c2415Smrg @system unittest // Issue 8039 testcase
7051760c2415Smrg {
7052760c2415Smrg     static int dels;
7053760c2415Smrg     static struct S { ~this(){ ++dels; } }
7054760c2415Smrg 
7055760c2415Smrg     static class A { S s; }
7056760c2415Smrg     dels = 0; { scoped!A(); }
7057760c2415Smrg     assert(dels == 1);
7058760c2415Smrg 
7059760c2415Smrg     static class B { S[2] s; }
7060760c2415Smrg     dels = 0; { scoped!B(); }
7061760c2415Smrg     assert(dels == 2);
7062760c2415Smrg 
7063760c2415Smrg     static struct S2 { S[3] s; }
7064760c2415Smrg     static class C { S2[2] s; }
7065760c2415Smrg     dels = 0; { scoped!C(); }
7066760c2415Smrg     assert(dels == 6);
7067760c2415Smrg 
7068760c2415Smrg     static class D: A { S2[2] s; }
7069760c2415Smrg     dels = 0; { scoped!D(); }
7070760c2415Smrg     assert(dels == 1+6);
7071760c2415Smrg }
7072760c2415Smrg 
7073760c2415Smrg @system unittest
7074760c2415Smrg {
7075760c2415Smrg     // bug4500
7076760c2415Smrg     class A
7077760c2415Smrg     {
7078760c2415Smrg         this() { a = this; }
7079760c2415Smrg         this(int i) { a = this; }
7080760c2415Smrg         A a;
7081760c2415Smrg         bool check() { return this is a; }
7082760c2415Smrg     }
7083760c2415Smrg 
7084760c2415Smrg     auto a1 = scoped!A();
7085760c2415Smrg     assert(a1.check());
7086760c2415Smrg 
7087760c2415Smrg     auto a2 = scoped!A(1);
7088760c2415Smrg     assert(a2.check());
7089760c2415Smrg 
7090760c2415Smrg     a1.a = a1;
7091760c2415Smrg     assert(a1.check());
7092760c2415Smrg }
7093760c2415Smrg 
7094760c2415Smrg @system unittest
7095760c2415Smrg {
7096760c2415Smrg     static class A
7097760c2415Smrg     {
7098760c2415Smrg         static int sdtor;
7099760c2415Smrg 
7100760c2415Smrg         this() { ++sdtor; assert(sdtor == 1); }
7101760c2415Smrg         ~this() { assert(sdtor == 1); --sdtor; }
7102760c2415Smrg     }
7103760c2415Smrg 
7104760c2415Smrg     interface Bob {}
7105760c2415Smrg 
7106760c2415Smrg     static class ABob : A, Bob
7107760c2415Smrg     {
7108760c2415Smrg         this() { ++sdtor; assert(sdtor == 2); }
7109760c2415Smrg         ~this() { assert(sdtor == 2); --sdtor; }
7110760c2415Smrg     }
7111760c2415Smrg 
7112760c2415Smrg     A.sdtor = 0;
7113760c2415Smrg     scope(exit) assert(A.sdtor == 0);
7114760c2415Smrg     auto abob = scoped!ABob();
7115760c2415Smrg }
7116760c2415Smrg 
7117760c2415Smrg @safe unittest
7118760c2415Smrg {
7119760c2415Smrg     static class A { this(int) {} }
7120760c2415Smrg     static assert(!__traits(compiles, scoped!A()));
7121760c2415Smrg }
7122760c2415Smrg 
7123760c2415Smrg @system unittest
7124760c2415Smrg {
7125760c2415Smrg     static class A { @property inout(int) foo() inout { return 1; } }
7126760c2415Smrg 
7127760c2415Smrg     auto a1 = scoped!A();
7128760c2415Smrg     assert(a1.foo == 1);
7129760c2415Smrg     static assert(is(typeof(a1.foo) == int));
7130760c2415Smrg 
7131760c2415Smrg     auto a2 = scoped!(const(A))();
7132760c2415Smrg     assert(a2.foo == 1);
7133760c2415Smrg     static assert(is(typeof(a2.foo) == const(int)));
7134760c2415Smrg 
7135760c2415Smrg     auto a3 = scoped!(immutable(A))();
7136760c2415Smrg     assert(a3.foo == 1);
7137760c2415Smrg     static assert(is(typeof(a3.foo) == immutable(int)));
7138760c2415Smrg 
7139760c2415Smrg     const c1 = scoped!A();
7140760c2415Smrg     assert(c1.foo == 1);
7141760c2415Smrg     static assert(is(typeof(c1.foo) == const(int)));
7142760c2415Smrg 
7143760c2415Smrg     const c2 = scoped!(const(A))();
7144760c2415Smrg     assert(c2.foo == 1);
7145760c2415Smrg     static assert(is(typeof(c2.foo) == const(int)));
7146760c2415Smrg 
7147760c2415Smrg     const c3 = scoped!(immutable(A))();
7148760c2415Smrg     assert(c3.foo == 1);
7149760c2415Smrg     static assert(is(typeof(c3.foo) == immutable(int)));
7150760c2415Smrg }
7151760c2415Smrg 
7152760c2415Smrg @system unittest
7153760c2415Smrg {
7154760c2415Smrg     class C { this(ref int val) { assert(val == 3); ++val; } }
7155760c2415Smrg 
7156760c2415Smrg     int val = 3;
7157760c2415Smrg     auto s = scoped!C(val);
7158760c2415Smrg     assert(val == 4);
7159760c2415Smrg }
7160760c2415Smrg 
7161760c2415Smrg @system unittest
7162760c2415Smrg {
7163760c2415Smrg     class C
7164760c2415Smrg     {
7165760c2415Smrg         this(){}
7166760c2415Smrg         this(int){}
7167760c2415Smrg         this(int, int){}
7168760c2415Smrg     }
7169760c2415Smrg     alias makeScopedC = scoped!C;
7170760c2415Smrg 
7171760c2415Smrg     auto a = makeScopedC();
7172760c2415Smrg     auto b = makeScopedC(1);
7173760c2415Smrg     auto c = makeScopedC(1, 1);
7174760c2415Smrg 
7175760c2415Smrg     static assert(is(typeof(a) == typeof(b)));
7176760c2415Smrg     static assert(is(typeof(b) == typeof(c)));
7177760c2415Smrg }
7178760c2415Smrg 
7179760c2415Smrg /**
7180760c2415Smrg Defines a simple, self-documenting yes/no flag. This makes it easy for
7181760c2415Smrg APIs to define functions accepting flags without resorting to $(D
7182760c2415Smrg bool), which is opaque in calls, and without needing to define an
7183760c2415Smrg enumerated type separately. Using $(D Flag!"Name") instead of $(D
7184760c2415Smrg bool) makes the flag's meaning visible in calls. Each yes/no flag has
7185760c2415Smrg its own type, which makes confusions and mix-ups impossible.
7186760c2415Smrg 
7187760c2415Smrg Example:
7188760c2415Smrg 
7189760c2415Smrg Code calling $(D getLine) (usually far away from its definition) can't be
7190760c2415Smrg understood without looking at the documentation, even by users familiar with
7191760c2415Smrg the API:
7192760c2415Smrg ----
7193760c2415Smrg string getLine(bool keepTerminator)
7194760c2415Smrg {
7195760c2415Smrg     ...
7196760c2415Smrg     if (keepTerminator) ...
7197760c2415Smrg     ...
7198760c2415Smrg }
7199760c2415Smrg ...
7200760c2415Smrg auto line = getLine(false);
7201760c2415Smrg ----
7202760c2415Smrg 
7203760c2415Smrg Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong
7204760c2415Smrg code compiles and runs with erroneous results.
7205760c2415Smrg 
7206760c2415Smrg After replacing the boolean parameter with an instantiation of $(D Flag), code
7207760c2415Smrg calling $(D getLine) can be easily read and understood even by people not
7208760c2415Smrg fluent with the API:
7209760c2415Smrg 
7210760c2415Smrg ----
7211760c2415Smrg string getLine(Flag!"keepTerminator" keepTerminator)
7212760c2415Smrg {
7213760c2415Smrg     ...
7214760c2415Smrg     if (keepTerminator) ...
7215760c2415Smrg     ...
7216760c2415Smrg }
7217760c2415Smrg ...
7218760c2415Smrg auto line = getLine(Yes.keepTerminator);
7219760c2415Smrg ----
7220760c2415Smrg 
7221760c2415Smrg The structs $(D Yes) and $(D No) are provided as shorthand for
7222760c2415Smrg $(D Flag!"Name".yes) and $(D Flag!"Name".no) and are preferred for brevity and
7223760c2415Smrg readability. These convenience structs mean it is usually unnecessary and
7224760c2415Smrg counterproductive to create an alias of a $(D Flag) as a way of avoiding typing
7225760c2415Smrg out the full type while specifying the affirmative or negative options.
7226760c2415Smrg 
7227760c2415Smrg Passing categorical data by means of unstructured $(D bool)
7228760c2415Smrg parameters is classified under "simple-data coupling" by Steve
7229760c2415Smrg McConnell in the $(LUCKY Code Complete) book, along with three other
7230760c2415Smrg kinds of coupling. The author argues citing several studies that
7231760c2415Smrg coupling has a negative effect on code quality. $(D Flag) offers a
7232760c2415Smrg simple structuring method for passing yes/no flags to APIs.
7233760c2415Smrg  */
7234760c2415Smrg template Flag(string name) {
7235760c2415Smrg     ///
7236760c2415Smrg     enum Flag : bool
7237760c2415Smrg     {
7238760c2415Smrg         /**
7239760c2415Smrg          When creating a value of type $(D Flag!"Name"), use $(D
7240760c2415Smrg          Flag!"Name".no) for the negative option. When using a value
7241760c2415Smrg          of type $(D Flag!"Name"), compare it against $(D
7242760c2415Smrg          Flag!"Name".no) or just $(D false) or $(D 0).  */
7243760c2415Smrg         no = false,
7244760c2415Smrg 
7245760c2415Smrg         /** When creating a value of type $(D Flag!"Name"), use $(D
7246760c2415Smrg          Flag!"Name".yes) for the affirmative option. When using a
7247760c2415Smrg          value of type $(D Flag!"Name"), compare it against $(D
7248760c2415Smrg          Flag!"Name".yes).
7249760c2415Smrg         */
7250760c2415Smrg         yes = true
7251760c2415Smrg     }
7252760c2415Smrg }
7253760c2415Smrg 
7254760c2415Smrg /**
7255760c2415Smrg Convenience names that allow using e.g. $(D Yes.encryption) instead of
7256760c2415Smrg $(D Flag!"encryption".yes) and $(D No.encryption) instead of $(D
7257760c2415Smrg Flag!"encryption".no).
7258760c2415Smrg */
7259760c2415Smrg struct Yes
7260760c2415Smrg {
7261760c2415Smrg     template opDispatch(string name)
7262760c2415Smrg     {
7263760c2415Smrg         enum opDispatch = Flag!name.yes;
7264760c2415Smrg     }
7265760c2415Smrg }
7266760c2415Smrg //template yes(string name) { enum Flag!name yes = Flag!name.yes; }
7267760c2415Smrg 
7268760c2415Smrg /// Ditto
7269760c2415Smrg struct No
7270760c2415Smrg {
7271760c2415Smrg     template opDispatch(string name)
7272760c2415Smrg     {
7273760c2415Smrg         enum opDispatch = Flag!name.no;
7274760c2415Smrg     }
7275760c2415Smrg }
7276760c2415Smrg 
7277760c2415Smrg ///
7278760c2415Smrg @safe unittest
7279760c2415Smrg {
7280760c2415Smrg     Flag!"abc" flag1;
7281760c2415Smrg     assert(flag1 == Flag!"abc".no);
7282760c2415Smrg     assert(flag1 == No.abc);
7283760c2415Smrg     assert(!flag1);
7284760c2415Smrg     if (flag1) assert(false);
7285760c2415Smrg     flag1 = Yes.abc;
7286760c2415Smrg     assert(flag1);
7287760c2415Smrg     if (!flag1) assert(false);
7288760c2415Smrg     if (flag1) {} else assert(false);
7289760c2415Smrg     assert(flag1 == Yes.abc);
7290760c2415Smrg }
7291760c2415Smrg 
7292760c2415Smrg /**
7293760c2415Smrg Detect whether an enum is of integral type and has only "flag" values
7294760c2415Smrg (i.e. values with a bit count of exactly 1).
7295760c2415Smrg Additionally, a zero value is allowed for compatibility with enums including
7296760c2415Smrg a "None" value.
7297760c2415Smrg */
7298760c2415Smrg template isBitFlagEnum(E)
7299760c2415Smrg {
7300760c2415Smrg     static if (is(E Base == enum) && isIntegral!Base)
7301760c2415Smrg     {
7302760c2415Smrg         enum isBitFlagEnum = (E.min >= 0) &&
7303760c2415Smrg         {
7304760c2415Smrg             foreach (immutable flag; EnumMembers!E)
7305760c2415Smrg             {
7306760c2415Smrg                 Base value = flag;
7307760c2415Smrg                 value &= value - 1;
7308760c2415Smrg                 if (value != 0) return false;
7309760c2415Smrg             }
7310760c2415Smrg             return true;
7311760c2415Smrg         }();
7312760c2415Smrg     }
7313760c2415Smrg     else
7314760c2415Smrg     {
7315760c2415Smrg         enum isBitFlagEnum = false;
7316760c2415Smrg     }
7317760c2415Smrg }
7318760c2415Smrg 
7319760c2415Smrg ///
7320760c2415Smrg @safe pure nothrow unittest
7321760c2415Smrg {
7322760c2415Smrg     enum A
7323760c2415Smrg     {
7324760c2415Smrg         None,
7325760c2415Smrg         A = 1 << 0,
7326760c2415Smrg         B = 1 << 1,
7327760c2415Smrg         C = 1 << 2,
7328760c2415Smrg         D = 1 << 3,
7329760c2415Smrg     }
7330760c2415Smrg 
7331760c2415Smrg     static assert(isBitFlagEnum!A);
7332760c2415Smrg 
7333760c2415Smrg     enum B
7334760c2415Smrg     {
7335760c2415Smrg         A,
7336760c2415Smrg         B,
7337760c2415Smrg         C,
7338760c2415Smrg         D // D == 3
7339760c2415Smrg     }
7340760c2415Smrg 
7341760c2415Smrg     static assert(!isBitFlagEnum!B);
7342760c2415Smrg 
7343760c2415Smrg     enum C: double
7344760c2415Smrg     {
7345760c2415Smrg         A = 1 << 0,
7346760c2415Smrg         B = 1 << 1
7347760c2415Smrg     }
7348760c2415Smrg 
7349760c2415Smrg     static assert(!isBitFlagEnum!C);
7350760c2415Smrg }
7351760c2415Smrg 
7352760c2415Smrg /**
7353760c2415Smrg A typesafe structure for storing combinations of enum values.
7354760c2415Smrg 
7355760c2415Smrg This template defines a simple struct to represent bitwise OR combinations of
7356760c2415Smrg enum values. It can be used if all the enum values are integral constants with
7357760c2415Smrg a bit count of at most 1, or if the $(D unsafe) parameter is explicitly set to
7358760c2415Smrg Yes.
7359760c2415Smrg This is much safer than using the enum itself to store
7360760c2415Smrg the OR combination, which can produce surprising effects like this:
7361760c2415Smrg ----
7362760c2415Smrg enum E
7363760c2415Smrg {
7364760c2415Smrg     A = 1 << 0,
7365760c2415Smrg     B = 1 << 1
7366760c2415Smrg }
7367760c2415Smrg E e = E.A | E.B;
7368760c2415Smrg // will throw SwitchError
7369760c2415Smrg final switch (e)
7370760c2415Smrg {
7371760c2415Smrg     case E.A:
7372760c2415Smrg         return;
7373760c2415Smrg     case E.B:
7374760c2415Smrg         return;
7375760c2415Smrg }
7376760c2415Smrg ----
7377760c2415Smrg */
7378760c2415Smrg struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe) if (unsafe || isBitFlagEnum!(E))
7379760c2415Smrg {
7380760c2415Smrg @safe @nogc pure nothrow:
7381760c2415Smrg private:
7382760c2415Smrg     enum isBaseEnumType(T) = is(E == T);
7383760c2415Smrg     alias Base = OriginalType!E;
7384760c2415Smrg     Base mValue;
7385760c2415Smrg     static struct Negation
7386760c2415Smrg     {
7387760c2415Smrg     @safe @nogc pure nothrow:
7388760c2415Smrg     private:
7389760c2415Smrg         Base mValue;
7390760c2415Smrg 
7391760c2415Smrg         // Prevent non-copy construction outside the module.
7392760c2415Smrg         @disable this();
7393760c2415Smrg         this(Base value)
7394760c2415Smrg         {
7395760c2415Smrg             mValue = value;
7396760c2415Smrg         }
7397760c2415Smrg     }
7398760c2415Smrg 
7399760c2415Smrg public:
7400760c2415Smrg     this(E flag)
7401760c2415Smrg     {
7402760c2415Smrg         this = flag;
7403760c2415Smrg     }
7404760c2415Smrg 
7405760c2415Smrg     this(T...)(T flags)
7406760c2415Smrg         if (allSatisfy!(isBaseEnumType, T))
7407760c2415Smrg     {
7408760c2415Smrg         this = flags;
7409760c2415Smrg     }
7410760c2415Smrg 
7411760c2415Smrg     bool opCast(B: bool)() const
7412760c2415Smrg     {
7413760c2415Smrg         return mValue != 0;
7414760c2415Smrg     }
7415760c2415Smrg 
7416760c2415Smrg     Base opCast(B)() const
7417760c2415Smrg         if (isImplicitlyConvertible!(Base, B))
7418760c2415Smrg     {
7419760c2415Smrg         return mValue;
7420760c2415Smrg     }
7421760c2415Smrg 
7422760c2415Smrg     Negation opUnary(string op)() const
7423760c2415Smrg         if (op == "~")
7424760c2415Smrg     {
7425760c2415Smrg         return Negation(~mValue);
7426760c2415Smrg     }
7427760c2415Smrg 
7428760c2415Smrg     auto ref opAssign(T...)(T flags)
7429760c2415Smrg         if (allSatisfy!(isBaseEnumType, T))
7430760c2415Smrg     {
7431760c2415Smrg         mValue = 0;
7432760c2415Smrg         foreach (E flag; flags)
7433760c2415Smrg         {
7434760c2415Smrg             mValue |= flag;
7435760c2415Smrg         }
7436760c2415Smrg         return this;
7437760c2415Smrg     }
7438760c2415Smrg 
7439760c2415Smrg     auto ref opAssign(E flag)
7440760c2415Smrg     {
7441760c2415Smrg         mValue = flag;
7442760c2415Smrg         return this;
7443760c2415Smrg     }
7444760c2415Smrg 
7445760c2415Smrg     auto ref opOpAssign(string op: "|")(BitFlags flags)
7446760c2415Smrg     {
7447760c2415Smrg         mValue |= flags.mValue;
7448760c2415Smrg         return this;
7449760c2415Smrg     }
7450760c2415Smrg 
7451760c2415Smrg     auto ref opOpAssign(string op: "&")(BitFlags  flags)
7452760c2415Smrg     {
7453760c2415Smrg         mValue &= flags.mValue;
7454760c2415Smrg         return this;
7455760c2415Smrg     }
7456760c2415Smrg 
7457760c2415Smrg     auto ref opOpAssign(string op: "|")(E flag)
7458760c2415Smrg     {
7459760c2415Smrg         mValue |= flag;
7460760c2415Smrg         return this;
7461760c2415Smrg     }
7462760c2415Smrg 
7463760c2415Smrg     auto ref opOpAssign(string op: "&")(E flag)
7464760c2415Smrg     {
7465760c2415Smrg         mValue &= flag;
7466760c2415Smrg         return this;
7467760c2415Smrg     }
7468760c2415Smrg 
7469760c2415Smrg     auto ref opOpAssign(string op: "&")(Negation negatedFlags)
7470760c2415Smrg     {
7471760c2415Smrg         mValue &= negatedFlags.mValue;
7472760c2415Smrg         return this;
7473760c2415Smrg     }
7474760c2415Smrg 
7475760c2415Smrg     auto opBinary(string op)(BitFlags flags) const
7476760c2415Smrg         if (op == "|" || op == "&")
7477760c2415Smrg     {
7478760c2415Smrg         BitFlags result = this;
7479760c2415Smrg         result.opOpAssign!op(flags);
7480760c2415Smrg         return result;
7481760c2415Smrg     }
7482760c2415Smrg 
7483760c2415Smrg     auto opBinary(string op)(E flag) const
7484760c2415Smrg         if (op == "|" || op == "&")
7485760c2415Smrg     {
7486760c2415Smrg         BitFlags result = this;
7487760c2415Smrg         result.opOpAssign!op(flag);
7488760c2415Smrg         return result;
7489760c2415Smrg     }
7490760c2415Smrg 
7491760c2415Smrg     auto opBinary(string op: "&")(Negation negatedFlags) const
7492760c2415Smrg     {
7493760c2415Smrg         BitFlags result = this;
7494760c2415Smrg         result.opOpAssign!op(negatedFlags);
7495760c2415Smrg         return result;
7496760c2415Smrg     }
7497760c2415Smrg 
7498760c2415Smrg     auto opBinaryRight(string op)(E flag) const
7499760c2415Smrg         if (op == "|" || op == "&")
7500760c2415Smrg     {
7501760c2415Smrg         return opBinary!op(flag);
7502760c2415Smrg     }
7503760c2415Smrg }
7504760c2415Smrg 
7505760c2415Smrg /// BitFlags can be manipulated with the usual operators
7506760c2415Smrg @safe @nogc pure nothrow unittest
7507760c2415Smrg {
7508760c2415Smrg     import std.traits : EnumMembers;
7509760c2415Smrg 
7510760c2415Smrg     // You can use such an enum with BitFlags straight away
7511760c2415Smrg     enum Enum
7512760c2415Smrg     {
7513760c2415Smrg         None,
7514760c2415Smrg         A = 1 << 0,
7515760c2415Smrg         B = 1 << 1,
7516760c2415Smrg         C = 1 << 2
7517760c2415Smrg     }
7518760c2415Smrg     BitFlags!Enum flags1;
7519760c2415Smrg     assert(!(flags1 & (Enum.A | Enum.B | Enum.C)));
7520760c2415Smrg 
7521760c2415Smrg     // You need to specify the `unsafe` parameter for enum with custom values
7522760c2415Smrg     enum UnsafeEnum
7523760c2415Smrg     {
7524760c2415Smrg         A,
7525760c2415Smrg         B,
7526760c2415Smrg         C,
7527760c2415Smrg         D = B|C
7528760c2415Smrg     }
7529760c2415Smrg     static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags2; }));
7530760c2415Smrg     BitFlags!(UnsafeEnum, Yes.unsafe) flags3;
7531760c2415Smrg 
7532760c2415Smrg     immutable BitFlags!Enum flags_empty;
7533760c2415Smrg     // A default constructed BitFlags has no value set
7534760c2415Smrg     assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C));
7535760c2415Smrg 
7536760c2415Smrg     // Value can be set with the | operator
7537760c2415Smrg     immutable BitFlags!Enum flags_A = flags_empty | Enum.A;
7538760c2415Smrg 
7539760c2415Smrg     // And tested with the & operator
7540760c2415Smrg     assert(flags_A & Enum.A);
7541760c2415Smrg 
7542760c2415Smrg     // Which commutes
7543760c2415Smrg     assert(Enum.A & flags_A);
7544760c2415Smrg 
7545760c2415Smrg     // BitFlags can be variadically initialized
7546760c2415Smrg     immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
7547760c2415Smrg     assert((flags_AB & Enum.A) && (flags_AB & Enum.B) && !(flags_AB & Enum.C));
7548760c2415Smrg 
7549760c2415Smrg     // Use the ~ operator for subtracting flags
7550760c2415Smrg     immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A);
7551760c2415Smrg     assert(!(flags_B & Enum.A) && (flags_B & Enum.B) && !(flags_B & Enum.C));
7552760c2415Smrg 
7553760c2415Smrg     // You can use the EnumMembers template to set all flags
7554760c2415Smrg     immutable BitFlags!Enum flags_all = EnumMembers!Enum;
7555760c2415Smrg 
7556760c2415Smrg     // use & between BitFlags for intersection
7557760c2415Smrg     immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C);
7558760c2415Smrg     assert(flags_B == (flags_BC & flags_AB));
7559760c2415Smrg 
7560760c2415Smrg     // All the binary operators work in their assignment version
7561760c2415Smrg     BitFlags!Enum temp = flags_empty;
7562760c2415Smrg     temp |= flags_AB;
7563760c2415Smrg     assert(temp == (flags_empty | flags_AB));
7564760c2415Smrg     temp = flags_empty;
7565760c2415Smrg     temp |= Enum.B;
7566760c2415Smrg     assert(temp == (flags_empty | Enum.B));
7567760c2415Smrg     temp = flags_empty;
7568760c2415Smrg     temp &= flags_AB;
7569760c2415Smrg     assert(temp == (flags_empty & flags_AB));
7570760c2415Smrg     temp = flags_empty;
7571760c2415Smrg     temp &= Enum.A;
7572760c2415Smrg     assert(temp == (flags_empty & Enum.A));
7573760c2415Smrg 
7574760c2415Smrg     // BitFlags with no value set evaluate to false
7575760c2415Smrg     assert(!flags_empty);
7576760c2415Smrg 
7577760c2415Smrg     // BitFlags with at least one value set evaluate to true
7578760c2415Smrg     assert(flags_A);
7579760c2415Smrg 
7580760c2415Smrg     // This can be useful to check intersection between BitFlags
7581760c2415Smrg     assert(flags_A & flags_AB);
7582760c2415Smrg     assert(flags_AB & Enum.A);
7583760c2415Smrg 
7584760c2415Smrg     // Finally, you can of course get you raw value out of flags
7585760c2415Smrg     auto value = cast(int) flags_A;
7586760c2415Smrg     assert(value == Enum.A);
7587760c2415Smrg }
7588760c2415Smrg 
7589760c2415Smrg // ReplaceType
7590760c2415Smrg /**
7591760c2415Smrg Replaces all occurrences of `From` into `To`, in one or more types `T`. For
7592760c2415Smrg example, $(D ReplaceType!(int, uint, Tuple!(int, float)[string])) yields
7593760c2415Smrg $(D Tuple!(uint, float)[string]). The types in which replacement is performed
7594760c2415Smrg may be arbitrarily complex, including qualifiers, built-in type constructors
7595760c2415Smrg (pointers, arrays, associative arrays, functions, and delegates), and template
7596760c2415Smrg instantiations; replacement proceeds transitively through the type definition.
7597760c2415Smrg However, member types in `struct`s or `class`es are not replaced because there
7598760c2415Smrg are no ways to express the types resulting after replacement.
7599760c2415Smrg 
7600760c2415Smrg This is an advanced type manipulation necessary e.g. for replacing the
7601760c2415Smrg placeholder type `This` in $(REF Algebraic, std,variant).
7602760c2415Smrg 
7603760c2415Smrg Returns: `ReplaceType` aliases itself to the type(s) that result after
7604760c2415Smrg replacement.
7605760c2415Smrg */
7606760c2415Smrg template ReplaceType(From, To, T...)
7607760c2415Smrg {
7608760c2415Smrg     static if (T.length == 1)
7609760c2415Smrg     {
7610760c2415Smrg         static if (is(T[0] == From))
7611760c2415Smrg             alias ReplaceType = To;
7612760c2415Smrg         else static if (is(T[0] == const(U), U))
7613760c2415Smrg             alias ReplaceType = const(ReplaceType!(From, To, U));
7614760c2415Smrg         else static if (is(T[0] == immutable(U), U))
7615760c2415Smrg             alias ReplaceType = immutable(ReplaceType!(From, To, U));
7616760c2415Smrg         else static if (is(T[0] == shared(U), U))
7617760c2415Smrg             alias ReplaceType = shared(ReplaceType!(From, To, U));
7618760c2415Smrg         else static if (is(T[0] == U*, U))
7619760c2415Smrg         {
7620760c2415Smrg             static if (is(U == function))
7621760c2415Smrg                 alias ReplaceType = replaceTypeInFunctionType!(From, To, T[0]);
7622760c2415Smrg             else
7623760c2415Smrg                 alias ReplaceType = ReplaceType!(From, To, U)*;
7624760c2415Smrg         }
7625760c2415Smrg         else static if (is(T[0] == delegate))
7626760c2415Smrg         {
7627760c2415Smrg             alias ReplaceType = replaceTypeInFunctionType!(From, To, T[0]);
7628760c2415Smrg         }
7629760c2415Smrg         else static if (is(T[0] == function))
7630760c2415Smrg         {
7631760c2415Smrg             static assert(0, "Function types not supported," ~
7632760c2415Smrg                 " use a function pointer type instead of " ~ T[0].stringof);
7633760c2415Smrg         }
7634760c2415Smrg         else static if (is(T[0] : U!V, alias U, V...))
7635760c2415Smrg         {
7636760c2415Smrg             template replaceTemplateArgs(T...)
7637760c2415Smrg             {
7638760c2415Smrg                 static if (is(typeof(T[0])))    // template argument is value or symbol
7639760c2415Smrg                     enum replaceTemplateArgs = T[0];
7640760c2415Smrg                 else
7641760c2415Smrg                     alias replaceTemplateArgs = ReplaceType!(From, To, T[0]);
7642760c2415Smrg             }
7643760c2415Smrg             alias ReplaceType = U!(staticMap!(replaceTemplateArgs, V));
7644760c2415Smrg         }
7645760c2415Smrg         else static if (is(T[0] == struct))
7646760c2415Smrg             // don't match with alias this struct below (Issue 15168)
7647760c2415Smrg             alias ReplaceType = T[0];
7648760c2415Smrg         else static if (is(T[0] == U[], U))
7649760c2415Smrg             alias ReplaceType = ReplaceType!(From, To, U)[];
7650760c2415Smrg         else static if (is(T[0] == U[n], U, size_t n))
7651760c2415Smrg             alias ReplaceType = ReplaceType!(From, To, U)[n];
7652760c2415Smrg         else static if (is(T[0] == U[V], U, V))
7653760c2415Smrg             alias ReplaceType =
7654760c2415Smrg                 ReplaceType!(From, To, U)[ReplaceType!(From, To, V)];
7655760c2415Smrg         else
7656760c2415Smrg             alias ReplaceType = T[0];
7657760c2415Smrg     }
7658760c2415Smrg     else static if (T.length > 1)
7659760c2415Smrg     {
7660760c2415Smrg         alias ReplaceType = AliasSeq!(ReplaceType!(From, To, T[0]),
7661760c2415Smrg             ReplaceType!(From, To, T[1 .. $]));
7662760c2415Smrg     }
7663760c2415Smrg     else
7664760c2415Smrg     {
7665760c2415Smrg         alias ReplaceType = AliasSeq!();
7666760c2415Smrg     }
7667760c2415Smrg }
7668760c2415Smrg 
7669760c2415Smrg ///
7670760c2415Smrg @safe unittest
7671760c2415Smrg {
7672760c2415Smrg     static assert(
7673760c2415Smrg         is(ReplaceType!(int, string, int[]) == string[]) &&
7674760c2415Smrg         is(ReplaceType!(int, string, int[int]) == string[string]) &&
7675760c2415Smrg         is(ReplaceType!(int, string, const(int)[]) == const(string)[]) &&
7676760c2415Smrg         is(ReplaceType!(int, string, Tuple!(int[], float))
7677760c2415Smrg             == Tuple!(string[], float))
7678760c2415Smrg     );
7679760c2415Smrg }
7680760c2415Smrg 
7681760c2415Smrg private template replaceTypeInFunctionType(From, To, fun)
7682760c2415Smrg {
7683760c2415Smrg     alias RX = ReplaceType!(From, To, ReturnType!fun);
7684760c2415Smrg     alias PX = AliasSeq!(ReplaceType!(From, To, Parameters!fun));
7685760c2415Smrg     // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return
7686760c2415Smrg     // tuple if Parameters!fun.length == 1
7687760c2415Smrg 
7688760c2415Smrg     string gen()
7689760c2415Smrg     {
7690760c2415Smrg         enum  linkage = functionLinkage!fun;
7691760c2415Smrg         alias attributes = functionAttributes!fun;
7692760c2415Smrg         enum  variadicStyle = variadicFunctionStyle!fun;
7693760c2415Smrg         alias storageClasses = ParameterStorageClassTuple!fun;
7694760c2415Smrg 
7695760c2415Smrg         string result;
7696760c2415Smrg 
7697760c2415Smrg         result ~= "extern(" ~ linkage ~ ") ";
7698760c2415Smrg         static if (attributes & FunctionAttribute.ref_)
7699760c2415Smrg         {
7700760c2415Smrg             result ~= "ref ";
7701760c2415Smrg         }
7702760c2415Smrg 
7703760c2415Smrg         result ~= "RX";
7704760c2415Smrg         static if (is(fun == delegate))
7705760c2415Smrg             result ~= " delegate";
7706760c2415Smrg         else
7707760c2415Smrg             result ~= " function";
7708760c2415Smrg 
7709760c2415Smrg         result ~= "(";
7710760c2415Smrg         foreach (i, _; PX)
7711760c2415Smrg         {
7712760c2415Smrg             if (i)
7713760c2415Smrg                 result ~= ", ";
7714760c2415Smrg             if (storageClasses[i] & ParameterStorageClass.scope_)
7715760c2415Smrg                 result ~= "scope ";
7716760c2415Smrg             if (storageClasses[i] & ParameterStorageClass.out_)
7717760c2415Smrg                 result ~= "out ";
7718760c2415Smrg             if (storageClasses[i] & ParameterStorageClass.ref_)
7719760c2415Smrg                 result ~= "ref ";
7720760c2415Smrg             if (storageClasses[i] & ParameterStorageClass.lazy_)
7721760c2415Smrg                 result ~= "lazy ";
7722760c2415Smrg             if (storageClasses[i] & ParameterStorageClass.return_)
7723760c2415Smrg                 result ~= "return ";
7724760c2415Smrg 
7725760c2415Smrg             result ~= "PX[" ~ i.stringof ~ "]";
7726760c2415Smrg         }
7727760c2415Smrg         static if (variadicStyle == Variadic.typesafe)
7728760c2415Smrg             result ~= " ...";
7729760c2415Smrg         else static if (variadicStyle != Variadic.no)
7730760c2415Smrg             result ~= ", ...";
7731760c2415Smrg         result ~= ")";
7732760c2415Smrg 
7733760c2415Smrg         static if (attributes & FunctionAttribute.pure_)
7734760c2415Smrg             result ~= " pure";
7735760c2415Smrg         static if (attributes & FunctionAttribute.nothrow_)
7736760c2415Smrg             result ~= " nothrow";
7737760c2415Smrg         static if (attributes & FunctionAttribute.property)
7738760c2415Smrg             result ~= " @property";
7739760c2415Smrg         static if (attributes & FunctionAttribute.trusted)
7740760c2415Smrg             result ~= " @trusted";
7741760c2415Smrg         static if (attributes & FunctionAttribute.safe)
7742760c2415Smrg             result ~= " @safe";
7743760c2415Smrg         static if (attributes & FunctionAttribute.nogc)
7744760c2415Smrg             result ~= " @nogc";
7745760c2415Smrg         static if (attributes & FunctionAttribute.system)
7746760c2415Smrg             result ~= " @system";
7747760c2415Smrg         static if (attributes & FunctionAttribute.const_)
7748760c2415Smrg             result ~= " const";
7749760c2415Smrg         static if (attributes & FunctionAttribute.immutable_)
7750760c2415Smrg             result ~= " immutable";
7751760c2415Smrg         static if (attributes & FunctionAttribute.inout_)
7752760c2415Smrg             result ~= " inout";
7753760c2415Smrg         static if (attributes & FunctionAttribute.shared_)
7754760c2415Smrg             result ~= " shared";
7755760c2415Smrg         static if (attributes & FunctionAttribute.return_)
7756760c2415Smrg             result ~= " return";
7757760c2415Smrg 
7758760c2415Smrg         return result;
7759760c2415Smrg     }
7760760c2415Smrg     //pragma(msg, "gen ==> ", gen());
7761760c2415Smrg 
7762760c2415Smrg     mixin("alias replaceTypeInFunctionType = " ~ gen() ~ ";");
7763760c2415Smrg }
7764760c2415Smrg 
7765760c2415Smrg @safe unittest
7766760c2415Smrg {
7767760c2415Smrg     template Test(Ts...)
7768760c2415Smrg     {
7769760c2415Smrg         static if (Ts.length)
7770760c2415Smrg         {
7771760c2415Smrg             //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", "
7772760c2415Smrg             //    ~Ts[1].stringof~", "~Ts[2].stringof~")");
7773760c2415Smrg             static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]),
7774760c2415Smrg                 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", "
7775760c2415Smrg                     ~Ts[2].stringof~") == "
7776760c2415Smrg                     ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof);
7777760c2415Smrg             alias Test = Test!(Ts[4 .. $]);
7778760c2415Smrg         }
7779760c2415Smrg         else alias Test = void;
7780760c2415Smrg     }
7781760c2415Smrg 
7782760c2415Smrg     //import core.stdc.stdio;
7783760c2415Smrg     alias RefFun1 = ref int function(float, long);
7784760c2415Smrg     alias RefFun2 = ref float function(float, long);
7785760c2415Smrg     extern(C) int printf(const char*, ...) nothrow @nogc @system;
7786760c2415Smrg     extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system;
7787760c2415Smrg     int func(float);
7788760c2415Smrg 
7789760c2415Smrg     int x;
7790760c2415Smrg     struct S1 { void foo() { x = 1; } }
7791760c2415Smrg     struct S2 { void bar() { x = 2; } }
7792760c2415Smrg 
7793760c2415Smrg     alias Pass = Test!(
7794760c2415Smrg         int, float, typeof(&func), float delegate(float),
7795760c2415Smrg         int, float, typeof(&printf), typeof(&floatPrintf),
7796760c2415Smrg         int, float, int function(out long, ...),
7797760c2415Smrg             float function(out long, ...),
7798760c2415Smrg         int, float, int function(ref float, long),
7799760c2415Smrg             float function(ref float, long),
7800760c2415Smrg         int, float, int function(ref int, long),
7801760c2415Smrg             float function(ref float, long),
7802760c2415Smrg         int, float, int function(out int, long),
7803760c2415Smrg             float function(out float, long),
7804760c2415Smrg         int, float, int function(lazy int, long),
7805760c2415Smrg             float function(lazy float, long),
7806760c2415Smrg         int, float, int function(out long, ref const int),
7807760c2415Smrg             float function(out long, ref const float),
7808760c2415Smrg         int, int, int, int,
7809760c2415Smrg         int, float, int, float,
7810760c2415Smrg         int, float, const int, const float,
7811760c2415Smrg         int, float, immutable int, immutable float,
7812760c2415Smrg         int, float, shared int, shared float,
7813760c2415Smrg         int, float, int*, float*,
7814760c2415Smrg         int, float, const(int)*, const(float)*,
7815760c2415Smrg         int, float, const(int*), const(float*),
7816760c2415Smrg         const(int)*, float, const(int*), const(float),
7817760c2415Smrg         int*, float, const(int)*, const(int)*,
7818760c2415Smrg         int, float, int[], float[],
7819760c2415Smrg         int, float, int[42], float[42],
7820760c2415Smrg         int, float, const(int)[42], const(float)[42],
7821760c2415Smrg         int, float, const(int[42]), const(float[42]),
7822760c2415Smrg         int, float, int[int], float[float],
7823760c2415Smrg         int, float, int[double], float[double],
7824760c2415Smrg         int, float, double[int], double[float],
7825760c2415Smrg         int, float, int function(float, long), float function(float, long),
7826760c2415Smrg         int, float, int function(float), float function(float),
7827760c2415Smrg         int, float, int function(float, int), float function(float, float),
7828760c2415Smrg         int, float, int delegate(float, long), float delegate(float, long),
7829760c2415Smrg         int, float, int delegate(float), float delegate(float),
7830760c2415Smrg         int, float, int delegate(float, int), float delegate(float, float),
7831760c2415Smrg         int, float, Unique!int, Unique!float,
7832760c2415Smrg         int, float, Tuple!(float, int), Tuple!(float, float),
7833760c2415Smrg         int, float, RefFun1, RefFun2,
7834760c2415Smrg         S1, S2,
7835760c2415Smrg             S1[1][][S1]* function(),
7836760c2415Smrg             S2[1][][S2]* function(),
7837760c2415Smrg         int, string,
7838760c2415Smrg                int[3] function(   int[] arr,    int[2] ...) pure @trusted,
7839760c2415Smrg             string[3] function(string[] arr, string[2] ...) pure @trusted,
7840760c2415Smrg     );
7841760c2415Smrg 
7842760c2415Smrg     // Bugzilla 15168
7843760c2415Smrg     static struct T1 { string s; alias s this; }
7844760c2415Smrg     static struct T2 { char[10] s; alias s this; }
7845760c2415Smrg     static struct T3 { string[string] s; alias s this; }
7846760c2415Smrg     alias Pass2 = Test!(
7847760c2415Smrg         ubyte, ubyte, T1, T1,
7848760c2415Smrg         ubyte, ubyte, T2, T2,
7849760c2415Smrg         ubyte, ubyte, T3, T3,
7850760c2415Smrg     );
7851760c2415Smrg }
7852760c2415Smrg 
7853760c2415Smrg @safe unittest // Bugzilla 17116
7854760c2415Smrg {
7855760c2415Smrg     alias ConstDg = void delegate(float) const;
7856760c2415Smrg     alias B = void delegate(int) const;
7857760c2415Smrg     alias A = ReplaceType!(float, int, ConstDg);
7858760c2415Smrg     static assert(is(B == A));
7859760c2415Smrg }
7860760c2415Smrg 
7861760c2415Smrg /**
7862760c2415Smrg Ternary type with three truth values:
7863760c2415Smrg 
7864760c2415Smrg $(UL
7865760c2415Smrg     $(LI `Ternary.yes` for `true`)
7866760c2415Smrg     $(LI `Ternary.no` for `false`)
7867760c2415Smrg     $(LI `Ternary.unknown` as an unknown state)
7868760c2415Smrg )
7869760c2415Smrg 
7870760c2415Smrg Also known as trinary, trivalent, or trilean.
7871760c2415Smrg 
7872760c2415Smrg See_Also:
7873760c2415Smrg     $(HTTP en.wikipedia.org/wiki/Three-valued_logic,
7874760c2415Smrg         Three Valued Logic on Wikipedia)
7875760c2415Smrg */
7876760c2415Smrg struct Ternary
7877760c2415Smrg {
7878760c2415Smrg     @safe @nogc nothrow pure:
7879760c2415Smrg 
7880760c2415Smrg     private ubyte value = 6;
7881760c2415Smrg     private static Ternary make(ubyte b)
7882760c2415Smrg     {
7883760c2415Smrg         Ternary r = void;
7884760c2415Smrg         r.value = b;
7885760c2415Smrg         return r;
7886760c2415Smrg     }
7887760c2415Smrg 
7888760c2415Smrg     /**
7889760c2415Smrg         The possible states of the `Ternary`
7890760c2415Smrg     */
7891760c2415Smrg     enum no = make(0);
7892760c2415Smrg     /// ditto
7893760c2415Smrg     enum yes = make(2);
7894760c2415Smrg     /// ditto
7895760c2415Smrg     enum unknown = make(6);
7896760c2415Smrg 
7897760c2415Smrg     /**
7898760c2415Smrg      Construct and assign from a `bool`, receiving `no` for `false` and `yes`
7899760c2415Smrg      for `true`.
7900760c2415Smrg     */
7901760c2415Smrg     this(bool b) { value = b << 1; }
7902760c2415Smrg 
7903760c2415Smrg     /// ditto
7904760c2415Smrg     void opAssign(bool b) { value = b << 1; }
7905760c2415Smrg 
7906760c2415Smrg     /**
7907760c2415Smrg     Construct a ternary value from another ternary value
7908760c2415Smrg     */
7909760c2415Smrg     this(const Ternary b) { value = b.value; }
7910760c2415Smrg 
7911760c2415Smrg     /**
7912760c2415Smrg     $(TABLE Truth table for logical operations,
7913760c2415Smrg       $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`))
7914760c2415Smrg       $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`))
7915760c2415Smrg       $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`))
7916760c2415Smrg       $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
7917760c2415Smrg       $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`))
7918760c2415Smrg       $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`))
7919760c2415Smrg       $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
7920760c2415Smrg       $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`))
7921760c2415Smrg       $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`))
7922760c2415Smrg       $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`))
7923760c2415Smrg     )
7924760c2415Smrg     */
7925760c2415Smrg     Ternary opUnary(string s)() if (s == "~")
7926760c2415Smrg     {
7927760c2415Smrg         return make((386 >> value) & 6);
7928760c2415Smrg     }
7929760c2415Smrg 
7930760c2415Smrg     /// ditto
7931760c2415Smrg     Ternary opBinary(string s)(Ternary rhs) if (s == "|")
7932760c2415Smrg     {
7933760c2415Smrg         return make((25_512 >> (value + rhs.value)) & 6);
7934760c2415Smrg     }
7935760c2415Smrg 
7936760c2415Smrg     /// ditto
7937760c2415Smrg     Ternary opBinary(string s)(Ternary rhs) if (s == "&")
7938760c2415Smrg     {
7939760c2415Smrg         return make((26_144 >> (value + rhs.value)) & 6);
7940760c2415Smrg     }
7941760c2415Smrg 
7942760c2415Smrg     /// ditto
7943760c2415Smrg     Ternary opBinary(string s)(Ternary rhs) if (s == "^")
7944760c2415Smrg     {
7945760c2415Smrg         return make((26_504 >> (value + rhs.value)) & 6);
7946760c2415Smrg     }
7947760c2415Smrg }
7948760c2415Smrg 
7949760c2415Smrg ///
7950760c2415Smrg @safe @nogc nothrow pure
7951760c2415Smrg unittest
7952760c2415Smrg {
7953760c2415Smrg     Ternary a;
7954760c2415Smrg     assert(a == Ternary.unknown);
7955760c2415Smrg 
7956760c2415Smrg     assert(~Ternary.yes == Ternary.no);
7957760c2415Smrg     assert(~Ternary.no == Ternary.yes);
7958760c2415Smrg     assert(~Ternary.unknown == Ternary.unknown);
7959760c2415Smrg }
7960760c2415Smrg 
7961760c2415Smrg @safe @nogc nothrow pure
7962760c2415Smrg unittest
7963760c2415Smrg {
7964760c2415Smrg     alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown;
7965760c2415Smrg     Ternary[27] truthTableAnd =
7966760c2415Smrg     [
7967760c2415Smrg         t, t, t,
7968760c2415Smrg         t, u, u,
7969760c2415Smrg         t, f, f,
7970760c2415Smrg         u, t, u,
7971760c2415Smrg         u, u, u,
7972760c2415Smrg         u, f, f,
7973760c2415Smrg         f, t, f,
7974760c2415Smrg         f, u, f,
7975760c2415Smrg         f, f, f,
7976760c2415Smrg     ];
7977760c2415Smrg 
7978760c2415Smrg     Ternary[27] truthTableOr =
7979760c2415Smrg     [
7980760c2415Smrg         t, t, t,
7981760c2415Smrg         t, u, t,
7982760c2415Smrg         t, f, t,
7983760c2415Smrg         u, t, t,
7984760c2415Smrg         u, u, u,
7985760c2415Smrg         u, f, u,
7986760c2415Smrg         f, t, t,
7987760c2415Smrg         f, u, u,
7988760c2415Smrg         f, f, f,
7989760c2415Smrg     ];
7990760c2415Smrg 
7991760c2415Smrg     Ternary[27] truthTableXor =
7992760c2415Smrg     [
7993760c2415Smrg         t, t, f,
7994760c2415Smrg         t, u, u,
7995760c2415Smrg         t, f, t,
7996760c2415Smrg         u, t, u,
7997760c2415Smrg         u, u, u,
7998760c2415Smrg         u, f, u,
7999760c2415Smrg         f, t, t,
8000760c2415Smrg         f, u, u,
8001760c2415Smrg         f, f, f,
8002760c2415Smrg     ];
8003760c2415Smrg 
8004760c2415Smrg     for (auto i = 0; i != truthTableAnd.length; i += 3)
8005760c2415Smrg     {
8006760c2415Smrg         assert((truthTableAnd[i] & truthTableAnd[i + 1])
8007760c2415Smrg             == truthTableAnd[i + 2]);
8008760c2415Smrg         assert((truthTableOr[i] | truthTableOr[i + 1])
8009760c2415Smrg             == truthTableOr[i + 2]);
8010760c2415Smrg         assert((truthTableXor[i] ^ truthTableXor[i + 1])
8011760c2415Smrg             == truthTableXor[i + 2]);
8012760c2415Smrg     }
8013760c2415Smrg 
8014760c2415Smrg     Ternary a;
8015760c2415Smrg     assert(a == Ternary.unknown);
8016760c2415Smrg     static assert(!is(typeof({ if (a) {} })));
8017760c2415Smrg     assert(!is(typeof({ auto b = Ternary(3); })));
8018760c2415Smrg     a = true;
8019760c2415Smrg     assert(a == Ternary.yes);
8020760c2415Smrg     a = false;
8021760c2415Smrg     assert(a == Ternary.no);
8022760c2415Smrg     a = Ternary.unknown;
8023760c2415Smrg     assert(a == Ternary.unknown);
8024760c2415Smrg     Ternary b;
8025760c2415Smrg     b = a;
8026760c2415Smrg     assert(b == a);
8027760c2415Smrg     assert(~Ternary.yes == Ternary.no);
8028760c2415Smrg     assert(~Ternary.no == Ternary.yes);
8029760c2415Smrg     assert(~Ternary.unknown == Ternary.unknown);
8030760c2415Smrg }
8031