xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/src/std/variant.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1*627f7eb2Smrg // Written in the D programming language.
2*627f7eb2Smrg 
3*627f7eb2Smrg /**
4*627f7eb2Smrg This module implements a
5*627f7eb2Smrg $(HTTP erdani.org/publications/cuj-04-2002.html,discriminated union)
6*627f7eb2Smrg type (a.k.a.
7*627f7eb2Smrg $(HTTP en.wikipedia.org/wiki/Tagged_union,tagged union),
8*627f7eb2Smrg $(HTTP en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)).
9*627f7eb2Smrg Such types are useful
10*627f7eb2Smrg for type-uniform binary interfaces, interfacing with scripting
11*627f7eb2Smrg languages, and comfortable exploratory programming.
12*627f7eb2Smrg 
13*627f7eb2Smrg A $(LREF Variant) object can hold a value of any type, with very few
14*627f7eb2Smrg restrictions (such as `shared` types and noncopyable types). Setting the value
15*627f7eb2Smrg is as immediate as assigning to the `Variant` object. To read back the value of
16*627f7eb2Smrg the appropriate type `T`, use the $(LREF get!T) call. To query whether a
17*627f7eb2Smrg `Variant` currently holds a value of type `T`, use $(LREF peek!T). To fetch the
18*627f7eb2Smrg exact type currently held, call $(LREF type), which returns the `TypeInfo` of
19*627f7eb2Smrg the current value.
20*627f7eb2Smrg 
21*627f7eb2Smrg In addition to $(LREF Variant), this module also defines the $(LREF Algebraic)
22*627f7eb2Smrg type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of
23*627f7eb2Smrg types, which are specified in the instantiation (e.g. $(D Algebraic!(int,
24*627f7eb2Smrg string)) may only hold an `int` or a `string`).
25*627f7eb2Smrg 
26*627f7eb2Smrg Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
27*627f7eb2Smrg prompting the following improvements: (1) better support for arrays; (2) support
28*627f7eb2Smrg for associative arrays; (3) friendlier behavior towards the garbage collector.
29*627f7eb2Smrg Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
30*627f7eb2Smrg License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
31*627f7eb2Smrg Authors:   $(HTTP erdani.org, Andrei Alexandrescu)
32*627f7eb2Smrg Source:    $(PHOBOSSRC std/_variant.d)
33*627f7eb2Smrg */
34*627f7eb2Smrg module std.variant;
35*627f7eb2Smrg 
36*627f7eb2Smrg import std.meta, std.traits, std.typecons;
37*627f7eb2Smrg 
38*627f7eb2Smrg ///
39*627f7eb2Smrg @system unittest
40*627f7eb2Smrg {
41*627f7eb2Smrg     Variant a; // Must assign before use, otherwise exception ensues
42*627f7eb2Smrg     // Initialize with an integer; make the type int
43*627f7eb2Smrg     Variant b = 42;
44*627f7eb2Smrg     assert(b.type == typeid(int));
45*627f7eb2Smrg     // Peek at the value
46*627f7eb2Smrg     assert(b.peek!(int) !is null && *b.peek!(int) == 42);
47*627f7eb2Smrg     // Automatically convert per language rules
48*627f7eb2Smrg     auto x = b.get!(real);
49*627f7eb2Smrg 
50*627f7eb2Smrg     // Assign any other type, including other variants
51*627f7eb2Smrg     a = b;
52*627f7eb2Smrg     a = 3.14;
53*627f7eb2Smrg     assert(a.type == typeid(double));
54*627f7eb2Smrg     // Implicit conversions work just as with built-in types
55*627f7eb2Smrg     assert(a < b);
56*627f7eb2Smrg     // Check for convertibility
57*627f7eb2Smrg     assert(!a.convertsTo!(int)); // double not convertible to int
58*627f7eb2Smrg     // Strings and all other arrays are supported
59*627f7eb2Smrg     a = "now I'm a string";
60*627f7eb2Smrg     assert(a == "now I'm a string");
61*627f7eb2Smrg 
62*627f7eb2Smrg     // can also assign arrays
63*627f7eb2Smrg     a = new int[42];
64*627f7eb2Smrg     assert(a.length == 42);
65*627f7eb2Smrg     a[5] = 7;
66*627f7eb2Smrg     assert(a[5] == 7);
67*627f7eb2Smrg 
68*627f7eb2Smrg     // Can also assign class values
69*627f7eb2Smrg     class Foo {}
70*627f7eb2Smrg     auto foo = new Foo;
71*627f7eb2Smrg     a = foo;
72*627f7eb2Smrg     assert(*a.peek!(Foo) == foo); // and full type information is preserved
73*627f7eb2Smrg }
74*627f7eb2Smrg 
75*627f7eb2Smrg /++
76*627f7eb2Smrg     Gives the $(D sizeof) the largest type given.
77*627f7eb2Smrg   +/
maxSize(T...)78*627f7eb2Smrg template maxSize(T...)
79*627f7eb2Smrg {
80*627f7eb2Smrg     static if (T.length == 1)
81*627f7eb2Smrg     {
82*627f7eb2Smrg         enum size_t maxSize = T[0].sizeof;
83*627f7eb2Smrg     }
84*627f7eb2Smrg     else
85*627f7eb2Smrg     {
86*627f7eb2Smrg         import std.algorithm.comparison : max;
87*627f7eb2Smrg         enum size_t maxSize = max(T[0].sizeof, maxSize!(T[1 .. $]));
88*627f7eb2Smrg     }
89*627f7eb2Smrg }
90*627f7eb2Smrg 
91*627f7eb2Smrg ///
92*627f7eb2Smrg @safe unittest
93*627f7eb2Smrg {
94*627f7eb2Smrg     static assert(maxSize!(int, long) == 8);
95*627f7eb2Smrg     static assert(maxSize!(bool, byte) == 1);
96*627f7eb2Smrg 
97*627f7eb2Smrg     struct Cat { int a, b, c; }
98*627f7eb2Smrg     static assert(maxSize!(bool, Cat) == 12);
99*627f7eb2Smrg }
100*627f7eb2Smrg 
101*627f7eb2Smrg struct This;
102*627f7eb2Smrg 
103*627f7eb2Smrg private alias This2Variant(V, T...) = AliasSeq!(ReplaceType!(This, V, T));
104*627f7eb2Smrg 
105*627f7eb2Smrg /**
106*627f7eb2Smrg  * Back-end type seldom used directly by user
107*627f7eb2Smrg  * code. Two commonly-used types using $(D VariantN) are:
108*627f7eb2Smrg  *
109*627f7eb2Smrg  * $(OL $(LI $(LREF Algebraic): A closed discriminated union with a
110*627f7eb2Smrg  * limited type universe (e.g., $(D Algebraic!(int, double,
111*627f7eb2Smrg  * string)) only accepts these three types and rejects anything
112*627f7eb2Smrg  * else).) $(LI $(LREF Variant): An open discriminated union allowing an
113*627f7eb2Smrg  * unbounded set of types. If any of the types in the $(D Variant)
114*627f7eb2Smrg  * are larger than the largest built-in type, they will automatically
115*627f7eb2Smrg  * be boxed. This means that even large types will only be the size
116*627f7eb2Smrg  * of a pointer within the $(D Variant), but this also implies some
117*627f7eb2Smrg  * overhead. $(D Variant) can accommodate all primitive types and
118*627f7eb2Smrg  * all user-defined types.))
119*627f7eb2Smrg  *
120*627f7eb2Smrg  * Both $(D Algebraic) and $(D Variant) share $(D
121*627f7eb2Smrg  * VariantN)'s interface. (See their respective documentations below.)
122*627f7eb2Smrg  *
123*627f7eb2Smrg  * $(D VariantN) is a discriminated union type parameterized
124*627f7eb2Smrg  * with the largest size of the types stored ($(D maxDataSize))
125*627f7eb2Smrg  * and with the list of allowed types ($(D AllowedTypes)). If
126*627f7eb2Smrg  * the list is empty, then any type up of size up to $(D
127*627f7eb2Smrg  * maxDataSize) (rounded up for alignment) can be stored in a
128*627f7eb2Smrg  * $(D VariantN) object without being boxed (types larger
129*627f7eb2Smrg  * than this will be boxed).
130*627f7eb2Smrg  *
131*627f7eb2Smrg  */
VariantN(size_t maxDataSize,AllowedTypesParam...)132*627f7eb2Smrg struct VariantN(size_t maxDataSize, AllowedTypesParam...)
133*627f7eb2Smrg {
134*627f7eb2Smrg     /**
135*627f7eb2Smrg     The list of allowed types. If empty, any type is allowed.
136*627f7eb2Smrg     */
137*627f7eb2Smrg     alias AllowedTypes = This2Variant!(VariantN, AllowedTypesParam);
138*627f7eb2Smrg 
139*627f7eb2Smrg private:
140*627f7eb2Smrg     // Compute the largest practical size from maxDataSize
141*627f7eb2Smrg     struct SizeChecker
142*627f7eb2Smrg     {
143*627f7eb2Smrg         int function() fptr;
144*627f7eb2Smrg         ubyte[maxDataSize] data;
145*627f7eb2Smrg     }
146*627f7eb2Smrg     enum size = SizeChecker.sizeof - (int function()).sizeof;
147*627f7eb2Smrg 
148*627f7eb2Smrg     /** Tells whether a type $(D T) is statically _allowed for
149*627f7eb2Smrg      * storage inside a $(D VariantN) object by looking
150*627f7eb2Smrg      * $(D T) up in $(D AllowedTypes).
151*627f7eb2Smrg      */
152*627f7eb2Smrg     public template allowed(T)
153*627f7eb2Smrg     {
154*627f7eb2Smrg         enum bool allowed
155*627f7eb2Smrg             = is(T == VariantN)
156*627f7eb2Smrg             ||
157*627f7eb2Smrg             //T.sizeof <= size &&
158*627f7eb2Smrg             (AllowedTypes.length == 0 || staticIndexOf!(T, AllowedTypes) >= 0);
159*627f7eb2Smrg     }
160*627f7eb2Smrg 
161*627f7eb2Smrg     // Each internal operation is encoded with an identifier. See
162*627f7eb2Smrg     // the "handler" function below.
163*627f7eb2Smrg     enum OpID { getTypeInfo, get, compare, equals, testConversion, toString,
164*627f7eb2Smrg             index, indexAssign, catAssign, copyOut, length,
165*627f7eb2Smrg             apply, postblit, destruct }
166*627f7eb2Smrg 
167*627f7eb2Smrg     // state
168*627f7eb2Smrg     ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
169*627f7eb2Smrg         = &handler!(void);
170*627f7eb2Smrg     union
171*627f7eb2Smrg     {
172*627f7eb2Smrg         ubyte[size] store;
173*627f7eb2Smrg         // conservatively mark the region as pointers
174*627f7eb2Smrg         static if (size >= (void*).sizeof)
175*627f7eb2Smrg             void*[size / (void*).sizeof] p;
176*627f7eb2Smrg     }
177*627f7eb2Smrg 
178*627f7eb2Smrg     // internals
179*627f7eb2Smrg     // Handler for an uninitialized value
180*627f7eb2Smrg     static ptrdiff_t handler(A : void)(OpID selector, ubyte[size]*, void* parm)
181*627f7eb2Smrg     {
182*627f7eb2Smrg         switch (selector)
183*627f7eb2Smrg         {
184*627f7eb2Smrg         case OpID.getTypeInfo:
185*627f7eb2Smrg             *cast(TypeInfo *) parm = typeid(A);
186*627f7eb2Smrg             break;
187*627f7eb2Smrg         case OpID.copyOut:
188*627f7eb2Smrg             auto target = cast(VariantN *) parm;
189*627f7eb2Smrg             target.fptr = &handler!(A);
190*627f7eb2Smrg             // no need to copy the data (it's garbage)
191*627f7eb2Smrg             break;
192*627f7eb2Smrg         case OpID.compare:
193*627f7eb2Smrg         case OpID.equals:
194*627f7eb2Smrg             auto rhs = cast(const VariantN *) parm;
195*627f7eb2Smrg             return rhs.peek!(A)
196*627f7eb2Smrg                 ? 0 // all uninitialized are equal
197*627f7eb2Smrg                 : ptrdiff_t.min; // uninitialized variant is not comparable otherwise
198*627f7eb2Smrg         case OpID.toString:
199*627f7eb2Smrg             string * target = cast(string*) parm;
200*627f7eb2Smrg             *target = "<Uninitialized VariantN>";
201*627f7eb2Smrg             break;
202*627f7eb2Smrg         case OpID.postblit:
203*627f7eb2Smrg         case OpID.destruct:
204*627f7eb2Smrg             break;
205*627f7eb2Smrg         case OpID.get:
206*627f7eb2Smrg         case OpID.testConversion:
207*627f7eb2Smrg         case OpID.index:
208*627f7eb2Smrg         case OpID.indexAssign:
209*627f7eb2Smrg         case OpID.catAssign:
210*627f7eb2Smrg         case OpID.length:
211*627f7eb2Smrg             throw new VariantException(
212*627f7eb2Smrg                 "Attempt to use an uninitialized VariantN");
213*627f7eb2Smrg         default: assert(false, "Invalid OpID");
214*627f7eb2Smrg         }
215*627f7eb2Smrg         return 0;
216*627f7eb2Smrg     }
217*627f7eb2Smrg 
218*627f7eb2Smrg     // Handler for all of a type's operations
219*627f7eb2Smrg     static ptrdiff_t handler(A)(OpID selector, ubyte[size]* pStore, void* parm)
220*627f7eb2Smrg     {
221*627f7eb2Smrg         import std.conv : to;
222*627f7eb2Smrg         static A* getPtr(void* untyped)
223*627f7eb2Smrg         {
224*627f7eb2Smrg             if (untyped)
225*627f7eb2Smrg             {
226*627f7eb2Smrg                 static if (A.sizeof <= size)
227*627f7eb2Smrg                     return cast(A*) untyped;
228*627f7eb2Smrg                 else
229*627f7eb2Smrg                     return *cast(A**) untyped;
230*627f7eb2Smrg             }
231*627f7eb2Smrg             return null;
232*627f7eb2Smrg         }
233*627f7eb2Smrg 
234*627f7eb2Smrg         static ptrdiff_t compare(A* rhsPA, A* zis, OpID selector)
235*627f7eb2Smrg         {
236*627f7eb2Smrg             static if (is(typeof(*rhsPA == *zis)))
237*627f7eb2Smrg             {
238*627f7eb2Smrg                 if (*rhsPA == *zis)
239*627f7eb2Smrg                 {
240*627f7eb2Smrg                     return 0;
241*627f7eb2Smrg                 }
242*627f7eb2Smrg                 static if (is(typeof(*zis < *rhsPA)))
243*627f7eb2Smrg                 {
244*627f7eb2Smrg                     // Many types (such as any using the default Object opCmp)
245*627f7eb2Smrg                     // will throw on an invalid opCmp, so do it only
246*627f7eb2Smrg                     // if the caller requests it.
247*627f7eb2Smrg                     if (selector == OpID.compare)
248*627f7eb2Smrg                         return *zis < *rhsPA ? -1 : 1;
249*627f7eb2Smrg                     else
250*627f7eb2Smrg                         return ptrdiff_t.min;
251*627f7eb2Smrg                 }
252*627f7eb2Smrg                 else
253*627f7eb2Smrg                 {
254*627f7eb2Smrg                     // Not equal, and type does not support ordering
255*627f7eb2Smrg                     // comparisons.
256*627f7eb2Smrg                     return ptrdiff_t.min;
257*627f7eb2Smrg                 }
258*627f7eb2Smrg             }
259*627f7eb2Smrg             else
260*627f7eb2Smrg             {
261*627f7eb2Smrg                 // Type does not support comparisons at all.
262*627f7eb2Smrg                 return ptrdiff_t.min;
263*627f7eb2Smrg             }
264*627f7eb2Smrg         }
265*627f7eb2Smrg 
266*627f7eb2Smrg         auto zis = getPtr(pStore);
267*627f7eb2Smrg         // Input: TypeInfo object
268*627f7eb2Smrg         // Output: target points to a copy of *me, if me was not null
269*627f7eb2Smrg         // Returns: true iff the A can be converted to the type represented
270*627f7eb2Smrg         // by the incoming TypeInfo
271*627f7eb2Smrg         static bool tryPutting(A* src, TypeInfo targetType, void* target)
272*627f7eb2Smrg         {
273*627f7eb2Smrg             alias UA = Unqual!A;
274*627f7eb2Smrg             alias MutaTypes = AliasSeq!(UA, ImplicitConversionTargets!UA);
275*627f7eb2Smrg             alias ConstTypes = staticMap!(ConstOf, MutaTypes);
276*627f7eb2Smrg             alias SharedTypes = staticMap!(SharedOf, MutaTypes);
277*627f7eb2Smrg             alias SharedConstTypes = staticMap!(SharedConstOf, MutaTypes);
278*627f7eb2Smrg             alias ImmuTypes  = staticMap!(ImmutableOf, MutaTypes);
279*627f7eb2Smrg 
280*627f7eb2Smrg             static if (is(A == immutable))
281*627f7eb2Smrg                 alias AllTypes = AliasSeq!(ImmuTypes, ConstTypes, SharedConstTypes);
282*627f7eb2Smrg             else static if (is(A == shared))
283*627f7eb2Smrg             {
284*627f7eb2Smrg                 static if (is(A == const))
285*627f7eb2Smrg                     alias AllTypes = SharedConstTypes;
286*627f7eb2Smrg                 else
287*627f7eb2Smrg                     alias AllTypes = AliasSeq!(SharedTypes, SharedConstTypes);
288*627f7eb2Smrg             }
289*627f7eb2Smrg             else
290*627f7eb2Smrg             {
291*627f7eb2Smrg                 static if (is(A == const))
292*627f7eb2Smrg                     alias AllTypes = ConstTypes;
293*627f7eb2Smrg                 else
294*627f7eb2Smrg                     alias AllTypes = AliasSeq!(MutaTypes, ConstTypes);
295*627f7eb2Smrg             }
296*627f7eb2Smrg 
297*627f7eb2Smrg             foreach (T ; AllTypes)
298*627f7eb2Smrg             {
299*627f7eb2Smrg                 if (targetType != typeid(T))
300*627f7eb2Smrg                     continue;
301*627f7eb2Smrg 
302*627f7eb2Smrg                 static if (is(typeof(*cast(T*) target = *src)) ||
303*627f7eb2Smrg                            is(T ==        const(U), U) ||
304*627f7eb2Smrg                            is(T ==       shared(U), U) ||
305*627f7eb2Smrg                            is(T == shared const(U), U) ||
306*627f7eb2Smrg                            is(T ==    immutable(U), U))
307*627f7eb2Smrg                 {
308*627f7eb2Smrg                     import std.conv : emplaceRef;
309*627f7eb2Smrg 
310*627f7eb2Smrg                     auto zat = cast(T*) target;
311*627f7eb2Smrg                     if (src)
312*627f7eb2Smrg                     {
313*627f7eb2Smrg                         static if (T.sizeof > 0)
314*627f7eb2Smrg                             assert(target, "target must be non-null");
315*627f7eb2Smrg 
316*627f7eb2Smrg                         emplaceRef(*cast(Unqual!T*) zat, *cast(UA*) src);
317*627f7eb2Smrg                     }
318*627f7eb2Smrg                 }
319*627f7eb2Smrg                 else
320*627f7eb2Smrg                 {
321*627f7eb2Smrg                     // type T is not constructible from A
322*627f7eb2Smrg                     if (src)
323*627f7eb2Smrg                         assert(false, A.stringof);
324*627f7eb2Smrg                 }
325*627f7eb2Smrg                 return true;
326*627f7eb2Smrg             }
327*627f7eb2Smrg             return false;
328*627f7eb2Smrg         }
329*627f7eb2Smrg 
330*627f7eb2Smrg         switch (selector)
331*627f7eb2Smrg         {
332*627f7eb2Smrg         case OpID.getTypeInfo:
333*627f7eb2Smrg             *cast(TypeInfo *) parm = typeid(A);
334*627f7eb2Smrg             break;
335*627f7eb2Smrg         case OpID.copyOut:
336*627f7eb2Smrg             auto target = cast(VariantN *) parm;
337*627f7eb2Smrg             assert(target);
338*627f7eb2Smrg 
339*627f7eb2Smrg             static if (target.size < A.sizeof)
340*627f7eb2Smrg             {
341*627f7eb2Smrg                 if (target.type.tsize < A.sizeof)
342*627f7eb2Smrg                     *cast(A**)&target.store = new A;
343*627f7eb2Smrg             }
344*627f7eb2Smrg             tryPutting(zis, typeid(A), cast(void*) getPtr(&target.store))
345*627f7eb2Smrg                 || assert(false);
346*627f7eb2Smrg             target.fptr = &handler!(A);
347*627f7eb2Smrg             break;
348*627f7eb2Smrg         case OpID.get:
349*627f7eb2Smrg             auto t = * cast(Tuple!(TypeInfo, void*)*) parm;
350*627f7eb2Smrg             return !tryPutting(zis, t[0], t[1]);
351*627f7eb2Smrg         case OpID.testConversion:
352*627f7eb2Smrg             return !tryPutting(null, *cast(TypeInfo*) parm, null);
353*627f7eb2Smrg         case OpID.compare:
354*627f7eb2Smrg         case OpID.equals:
355*627f7eb2Smrg             auto rhsP = cast(VariantN *) parm;
356*627f7eb2Smrg             auto rhsType = rhsP.type;
357*627f7eb2Smrg             // Are we the same?
358*627f7eb2Smrg             if (rhsType == typeid(A))
359*627f7eb2Smrg             {
360*627f7eb2Smrg                 // cool! Same type!
361*627f7eb2Smrg                 auto rhsPA = getPtr(&rhsP.store);
362*627f7eb2Smrg                 return compare(rhsPA, zis, selector);
363*627f7eb2Smrg             }
364*627f7eb2Smrg             else if (rhsType == typeid(void))
365*627f7eb2Smrg             {
366*627f7eb2Smrg                 // No support for ordering comparisons with
367*627f7eb2Smrg                 // uninitialized vars
368*627f7eb2Smrg                 return ptrdiff_t.min;
369*627f7eb2Smrg             }
370*627f7eb2Smrg             VariantN temp;
371*627f7eb2Smrg             // Do I convert to rhs?
372*627f7eb2Smrg             if (tryPutting(zis, rhsType, &temp.store))
373*627f7eb2Smrg             {
374*627f7eb2Smrg                 // cool, I do; temp's store contains my data in rhs's type!
375*627f7eb2Smrg                 // also fix up its fptr
376*627f7eb2Smrg                 temp.fptr = rhsP.fptr;
377*627f7eb2Smrg                 // now lhsWithRhsType is a full-blown VariantN of rhs's type
378*627f7eb2Smrg                 if (selector == OpID.compare)
379*627f7eb2Smrg                     return temp.opCmp(*rhsP);
380*627f7eb2Smrg                 else
381*627f7eb2Smrg                     return temp.opEquals(*rhsP) ? 0 : 1;
382*627f7eb2Smrg             }
383*627f7eb2Smrg             // Does rhs convert to zis?
384*627f7eb2Smrg             auto t = tuple(typeid(A), &temp.store);
385*627f7eb2Smrg             if (rhsP.fptr(OpID.get, &rhsP.store, &t) == 0)
386*627f7eb2Smrg             {
387*627f7eb2Smrg                 // cool! Now temp has rhs in my type!
388*627f7eb2Smrg                 auto rhsPA = getPtr(&temp.store);
389*627f7eb2Smrg                 return compare(rhsPA, zis, selector);
390*627f7eb2Smrg             }
391*627f7eb2Smrg             return ptrdiff_t.min; // dunno
392*627f7eb2Smrg         case OpID.toString:
393*627f7eb2Smrg             auto target = cast(string*) parm;
394*627f7eb2Smrg             static if (is(typeof(to!(string)(*zis))))
395*627f7eb2Smrg             {
396*627f7eb2Smrg                 *target = to!(string)(*zis);
397*627f7eb2Smrg                 break;
398*627f7eb2Smrg             }
399*627f7eb2Smrg             // TODO: The following test evaluates to true for shared objects.
400*627f7eb2Smrg             //       Use __traits for now until this is sorted out.
401*627f7eb2Smrg             // else static if (is(typeof((*zis).toString)))
402*627f7eb2Smrg             else static if (__traits(compiles, {(*zis).toString();}))
403*627f7eb2Smrg             {
404*627f7eb2Smrg                 *target = (*zis).toString();
405*627f7eb2Smrg                 break;
406*627f7eb2Smrg             }
407*627f7eb2Smrg             else
408*627f7eb2Smrg             {
409*627f7eb2Smrg                 throw new VariantException(typeid(A), typeid(string));
410*627f7eb2Smrg             }
411*627f7eb2Smrg 
412*627f7eb2Smrg         case OpID.index:
413*627f7eb2Smrg             auto result = cast(Variant*) parm;
414*627f7eb2Smrg             static if (isArray!(A) && !is(Unqual!(typeof(A.init[0])) == void))
415*627f7eb2Smrg             {
416*627f7eb2Smrg                 // array type; input and output are the same VariantN
417*627f7eb2Smrg                 size_t index = result.convertsTo!(int)
418*627f7eb2Smrg                     ? result.get!(int) : result.get!(size_t);
419*627f7eb2Smrg                 *result = (*zis)[index];
420*627f7eb2Smrg                 break;
421*627f7eb2Smrg             }
422*627f7eb2Smrg             else static if (isAssociativeArray!(A))
423*627f7eb2Smrg             {
424*627f7eb2Smrg                 *result = (*zis)[result.get!(typeof(A.init.keys[0]))];
425*627f7eb2Smrg                 break;
426*627f7eb2Smrg             }
427*627f7eb2Smrg             else
428*627f7eb2Smrg             {
429*627f7eb2Smrg                 throw new VariantException(typeid(A), result[0].type);
430*627f7eb2Smrg             }
431*627f7eb2Smrg 
432*627f7eb2Smrg         case OpID.indexAssign:
433*627f7eb2Smrg             // array type; result comes first, index comes second
434*627f7eb2Smrg             auto args = cast(Variant*) parm;
435*627f7eb2Smrg             static if (isArray!(A) && is(typeof((*zis)[0] = (*zis)[0])))
436*627f7eb2Smrg             {
437*627f7eb2Smrg                 size_t index = args[1].convertsTo!(int)
438*627f7eb2Smrg                     ? args[1].get!(int) : args[1].get!(size_t);
439*627f7eb2Smrg                 (*zis)[index] = args[0].get!(typeof((*zis)[0]));
440*627f7eb2Smrg                 break;
441*627f7eb2Smrg             }
442*627f7eb2Smrg             else static if (isAssociativeArray!(A))
443*627f7eb2Smrg             {
444*627f7eb2Smrg                 (*zis)[args[1].get!(typeof(A.init.keys[0]))]
445*627f7eb2Smrg                     = args[0].get!(typeof(A.init.values[0]));
446*627f7eb2Smrg                 break;
447*627f7eb2Smrg             }
448*627f7eb2Smrg             else
449*627f7eb2Smrg             {
450*627f7eb2Smrg                 throw new VariantException(typeid(A), args[0].type);
451*627f7eb2Smrg             }
452*627f7eb2Smrg 
453*627f7eb2Smrg         case OpID.catAssign:
454*627f7eb2Smrg             static if (!is(Unqual!(typeof((*zis)[0])) == void) && is(typeof((*zis)[0])) && is(typeof((*zis) ~= *zis)))
455*627f7eb2Smrg             {
456*627f7eb2Smrg                 // array type; parm is the element to append
457*627f7eb2Smrg                 auto arg = cast(Variant*) parm;
458*627f7eb2Smrg                 alias E = typeof((*zis)[0]);
459*627f7eb2Smrg                 if (arg[0].convertsTo!(E))
460*627f7eb2Smrg                 {
461*627f7eb2Smrg                     // append one element to the array
462*627f7eb2Smrg                     (*zis) ~= [ arg[0].get!(E) ];
463*627f7eb2Smrg                 }
464*627f7eb2Smrg                 else
465*627f7eb2Smrg                 {
466*627f7eb2Smrg                     // append a whole array to the array
467*627f7eb2Smrg                     (*zis) ~= arg[0].get!(A);
468*627f7eb2Smrg                 }
469*627f7eb2Smrg                 break;
470*627f7eb2Smrg             }
471*627f7eb2Smrg             else
472*627f7eb2Smrg             {
473*627f7eb2Smrg                 throw new VariantException(typeid(A), typeid(void[]));
474*627f7eb2Smrg             }
475*627f7eb2Smrg 
476*627f7eb2Smrg         case OpID.length:
477*627f7eb2Smrg             static if (isArray!(A) || isAssociativeArray!(A))
478*627f7eb2Smrg             {
479*627f7eb2Smrg                 return zis.length;
480*627f7eb2Smrg             }
481*627f7eb2Smrg             else
482*627f7eb2Smrg             {
483*627f7eb2Smrg                 throw new VariantException(typeid(A), typeid(void[]));
484*627f7eb2Smrg             }
485*627f7eb2Smrg 
486*627f7eb2Smrg         case OpID.apply:
487*627f7eb2Smrg             static if (!isFunctionPointer!A && !isDelegate!A)
488*627f7eb2Smrg             {
489*627f7eb2Smrg                 import std.conv : text;
490*627f7eb2Smrg                 import std.exception : enforce;
491*627f7eb2Smrg                 enforce(0, text("Cannot apply `()' to a value of type `",
492*627f7eb2Smrg                                 A.stringof, "'."));
493*627f7eb2Smrg             }
494*627f7eb2Smrg             else
495*627f7eb2Smrg             {
496*627f7eb2Smrg                 import std.conv : text;
497*627f7eb2Smrg                 import std.exception : enforce;
498*627f7eb2Smrg                 alias ParamTypes = Parameters!A;
499*627f7eb2Smrg                 auto p = cast(Variant*) parm;
500*627f7eb2Smrg                 auto argCount = p.get!size_t;
501*627f7eb2Smrg                 // To assign the tuple we need to use the unqualified version,
502*627f7eb2Smrg                 // otherwise we run into issues such as with const values.
503*627f7eb2Smrg                 // We still get the actual type from the Variant though
504*627f7eb2Smrg                 // to ensure that we retain const correctness.
505*627f7eb2Smrg                 Tuple!(staticMap!(Unqual, ParamTypes)) t;
506*627f7eb2Smrg                 enforce(t.length == argCount,
507*627f7eb2Smrg                         text("Argument count mismatch: ",
508*627f7eb2Smrg                              A.stringof, " expects ", t.length,
509*627f7eb2Smrg                              " argument(s), not ", argCount, "."));
510*627f7eb2Smrg                 auto variantArgs = p[1 .. argCount + 1];
511*627f7eb2Smrg                 foreach (i, T; ParamTypes)
512*627f7eb2Smrg                 {
513*627f7eb2Smrg                     t[i] = cast() variantArgs[i].get!T;
514*627f7eb2Smrg                 }
515*627f7eb2Smrg 
516*627f7eb2Smrg                 auto args = cast(Tuple!(ParamTypes))t;
517*627f7eb2Smrg                 static if (is(ReturnType!A == void))
518*627f7eb2Smrg                 {
519*627f7eb2Smrg                     (*zis)(args.expand);
520*627f7eb2Smrg                     *p = Variant.init; // void returns uninitialized Variant.
521*627f7eb2Smrg                 }
522*627f7eb2Smrg                 else
523*627f7eb2Smrg                 {
524*627f7eb2Smrg                     *p = (*zis)(args.expand);
525*627f7eb2Smrg                 }
526*627f7eb2Smrg             }
527*627f7eb2Smrg             break;
528*627f7eb2Smrg 
529*627f7eb2Smrg         case OpID.postblit:
530*627f7eb2Smrg             static if (hasElaborateCopyConstructor!A)
531*627f7eb2Smrg             {
532*627f7eb2Smrg                 typeid(A).postblit(zis);
533*627f7eb2Smrg             }
534*627f7eb2Smrg             break;
535*627f7eb2Smrg 
536*627f7eb2Smrg         case OpID.destruct:
537*627f7eb2Smrg             static if (hasElaborateDestructor!A)
538*627f7eb2Smrg             {
539*627f7eb2Smrg                 typeid(A).destroy(zis);
540*627f7eb2Smrg             }
541*627f7eb2Smrg             break;
542*627f7eb2Smrg 
543*627f7eb2Smrg         default: assert(false);
544*627f7eb2Smrg         }
545*627f7eb2Smrg         return 0;
546*627f7eb2Smrg     }
547*627f7eb2Smrg 
548*627f7eb2Smrg     enum doUnittest = is(VariantN == Variant);
549*627f7eb2Smrg 
550*627f7eb2Smrg public:
551*627f7eb2Smrg     /** Constructs a $(D VariantN) value given an argument of a
552*627f7eb2Smrg      * generic type. Statically rejects disallowed types.
553*627f7eb2Smrg      */
554*627f7eb2Smrg 
555*627f7eb2Smrg     this(T)(T value)
556*627f7eb2Smrg     {
557*627f7eb2Smrg         static assert(allowed!(T), "Cannot store a " ~ T.stringof
558*627f7eb2Smrg             ~ " in a " ~ VariantN.stringof);
559*627f7eb2Smrg         opAssign(value);
560*627f7eb2Smrg     }
561*627f7eb2Smrg 
562*627f7eb2Smrg     /// Allows assignment from a subset algebraic type
563*627f7eb2Smrg     this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value)
564*627f7eb2Smrg         if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
565*627f7eb2Smrg     {
566*627f7eb2Smrg         opAssign(value);
567*627f7eb2Smrg     }
568*627f7eb2Smrg 
569*627f7eb2Smrg     static if (!AllowedTypes.length || anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
570*627f7eb2Smrg     {
571*627f7eb2Smrg         this(this)
572*627f7eb2Smrg         {
573*627f7eb2Smrg             fptr(OpID.postblit, &store, null);
574*627f7eb2Smrg         }
575*627f7eb2Smrg     }
576*627f7eb2Smrg 
577*627f7eb2Smrg     static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
578*627f7eb2Smrg     {
579*627f7eb2Smrg         ~this()
580*627f7eb2Smrg         {
581*627f7eb2Smrg             fptr(OpID.destruct, &store, null);
582*627f7eb2Smrg         }
583*627f7eb2Smrg     }
584*627f7eb2Smrg 
585*627f7eb2Smrg     /** Assigns a $(D VariantN) from a generic
586*627f7eb2Smrg      * argument. Statically rejects disallowed types. */
587*627f7eb2Smrg 
588*627f7eb2Smrg     VariantN opAssign(T)(T rhs)
589*627f7eb2Smrg     {
590*627f7eb2Smrg         //writeln(typeid(rhs));
591*627f7eb2Smrg         static assert(allowed!(T), "Cannot store a " ~ T.stringof
592*627f7eb2Smrg             ~ " in a " ~ VariantN.stringof ~ ". Valid types are "
593*627f7eb2Smrg                 ~ AllowedTypes.stringof);
594*627f7eb2Smrg 
595*627f7eb2Smrg         static if (is(T : VariantN))
596*627f7eb2Smrg         {
597*627f7eb2Smrg             rhs.fptr(OpID.copyOut, &rhs.store, &this);
598*627f7eb2Smrg         }
599*627f7eb2Smrg         else static if (is(T : const(VariantN)))
600*627f7eb2Smrg         {
601*627f7eb2Smrg             static assert(false,
602*627f7eb2Smrg                     "Assigning Variant objects from const Variant"~
603*627f7eb2Smrg                     " objects is currently not supported.");
604*627f7eb2Smrg         }
605*627f7eb2Smrg         else
606*627f7eb2Smrg         {
607*627f7eb2Smrg             static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
608*627f7eb2Smrg             {
609*627f7eb2Smrg                 // Assignment should destruct previous value
610*627f7eb2Smrg                 fptr(OpID.destruct, &store, null);
611*627f7eb2Smrg             }
612*627f7eb2Smrg 
613*627f7eb2Smrg             static if (T.sizeof <= size)
614*627f7eb2Smrg             {
615*627f7eb2Smrg                 import core.stdc.string : memcpy;
616*627f7eb2Smrg                 // If T is a class we're only copying the reference, so it
617*627f7eb2Smrg                 // should be safe to cast away shared so the memcpy will work.
618*627f7eb2Smrg                 //
619*627f7eb2Smrg                 // TODO: If a shared class has an atomic reference then using
620*627f7eb2Smrg                 //       an atomic load may be more correct.  Just make sure
621*627f7eb2Smrg                 //       to use the fastest approach for the load op.
622*627f7eb2Smrg                 static if (is(T == class) && is(T == shared))
623*627f7eb2Smrg                     memcpy(&store, cast(const(void*)) &rhs, rhs.sizeof);
624*627f7eb2Smrg                 else
625*627f7eb2Smrg                     memcpy(&store, &rhs, rhs.sizeof);
626*627f7eb2Smrg                 static if (hasElaborateCopyConstructor!T)
627*627f7eb2Smrg                 {
628*627f7eb2Smrg                     typeid(T).postblit(&store);
629*627f7eb2Smrg                 }
630*627f7eb2Smrg             }
631*627f7eb2Smrg             else
632*627f7eb2Smrg             {
633*627f7eb2Smrg                 import core.stdc.string : memcpy;
634*627f7eb2Smrg                 static if (__traits(compiles, {new T(T.init);}))
635*627f7eb2Smrg                 {
636*627f7eb2Smrg                     auto p = new T(rhs);
637*627f7eb2Smrg                 }
638*627f7eb2Smrg                 else
639*627f7eb2Smrg                 {
640*627f7eb2Smrg                     auto p = new T;
641*627f7eb2Smrg                     *p = rhs;
642*627f7eb2Smrg                 }
643*627f7eb2Smrg                 memcpy(&store, &p, p.sizeof);
644*627f7eb2Smrg             }
645*627f7eb2Smrg             fptr = &handler!(T);
646*627f7eb2Smrg         }
647*627f7eb2Smrg         return this;
648*627f7eb2Smrg     }
649*627f7eb2Smrg 
650*627f7eb2Smrg     // Allow assignment from another variant which is a subset of this one
651*627f7eb2Smrg     VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs)
652*627f7eb2Smrg         if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
653*627f7eb2Smrg     {
654*627f7eb2Smrg         // discover which type rhs is actually storing
655*627f7eb2Smrg         foreach (V; T.AllowedTypes)
656*627f7eb2Smrg             if (rhs.type == typeid(V))
657*627f7eb2Smrg                 return this = rhs.get!V;
658*627f7eb2Smrg         assert(0, T.AllowedTypes.stringof);
659*627f7eb2Smrg     }
660*627f7eb2Smrg 
661*627f7eb2Smrg 
662*627f7eb2Smrg     Variant opCall(P...)(auto ref P params)
663*627f7eb2Smrg     {
664*627f7eb2Smrg         Variant[P.length + 1] pack;
665*627f7eb2Smrg         pack[0] = P.length;
666*627f7eb2Smrg         foreach (i, _; params)
667*627f7eb2Smrg         {
668*627f7eb2Smrg             pack[i + 1] = params[i];
669*627f7eb2Smrg         }
670*627f7eb2Smrg         fptr(OpID.apply, &store, &pack);
671*627f7eb2Smrg         return pack[0];
672*627f7eb2Smrg     }
673*627f7eb2Smrg 
674*627f7eb2Smrg     /** Returns true if and only if the $(D VariantN) object
675*627f7eb2Smrg      * holds a valid value (has been initialized with, or assigned
676*627f7eb2Smrg      * from, a valid value).
677*627f7eb2Smrg      */
678*627f7eb2Smrg     @property bool hasValue() const pure nothrow
679*627f7eb2Smrg     {
680*627f7eb2Smrg         // @@@BUG@@@ in compiler, the cast shouldn't be needed
681*627f7eb2Smrg         return cast(typeof(&handler!(void))) fptr != &handler!(void);
682*627f7eb2Smrg     }
683*627f7eb2Smrg 
684*627f7eb2Smrg     ///
685*627f7eb2Smrg     static if (doUnittest)
686*627f7eb2Smrg     @system unittest
687*627f7eb2Smrg     {
688*627f7eb2Smrg         Variant a;
689*627f7eb2Smrg         assert(!a.hasValue);
690*627f7eb2Smrg         Variant b;
691*627f7eb2Smrg         a = b;
692*627f7eb2Smrg         assert(!a.hasValue); // still no value
693*627f7eb2Smrg         a = 5;
694*627f7eb2Smrg         assert(a.hasValue);
695*627f7eb2Smrg     }
696*627f7eb2Smrg 
697*627f7eb2Smrg     /**
698*627f7eb2Smrg      * If the $(D VariantN) object holds a value of the
699*627f7eb2Smrg      * $(I exact) type $(D T), returns a pointer to that
700*627f7eb2Smrg      * value. Otherwise, returns $(D null). In cases
701*627f7eb2Smrg      * where $(D T) is statically disallowed, $(D
702*627f7eb2Smrg      * peek) will not compile.
703*627f7eb2Smrg      */
704*627f7eb2Smrg     @property inout(T)* peek(T)() inout
705*627f7eb2Smrg     {
706*627f7eb2Smrg         static if (!is(T == void))
707*627f7eb2Smrg             static assert(allowed!(T), "Cannot store a " ~ T.stringof
708*627f7eb2Smrg                     ~ " in a " ~ VariantN.stringof);
709*627f7eb2Smrg         if (type != typeid(T))
710*627f7eb2Smrg             return null;
711*627f7eb2Smrg         static if (T.sizeof <= size)
712*627f7eb2Smrg             return cast(inout T*)&store;
713*627f7eb2Smrg         else
714*627f7eb2Smrg             return *cast(inout T**)&store;
715*627f7eb2Smrg     }
716*627f7eb2Smrg 
717*627f7eb2Smrg     ///
718*627f7eb2Smrg     static if (doUnittest)
719*627f7eb2Smrg     @system unittest
720*627f7eb2Smrg     {
721*627f7eb2Smrg         Variant a = 5;
722*627f7eb2Smrg         auto b = a.peek!(int);
723*627f7eb2Smrg         assert(b !is null);
724*627f7eb2Smrg         *b = 6;
725*627f7eb2Smrg         assert(a == 6);
726*627f7eb2Smrg     }
727*627f7eb2Smrg 
728*627f7eb2Smrg     /**
729*627f7eb2Smrg      * Returns the $(D typeid) of the currently held value.
730*627f7eb2Smrg      */
731*627f7eb2Smrg 
732*627f7eb2Smrg     @property TypeInfo type() const nothrow @trusted
733*627f7eb2Smrg     {
734*627f7eb2Smrg         scope(failure) assert(0);
735*627f7eb2Smrg 
736*627f7eb2Smrg         TypeInfo result;
737*627f7eb2Smrg         fptr(OpID.getTypeInfo, null, &result);
738*627f7eb2Smrg         return result;
739*627f7eb2Smrg     }
740*627f7eb2Smrg 
741*627f7eb2Smrg     /**
742*627f7eb2Smrg      * Returns $(D true) if and only if the $(D VariantN)
743*627f7eb2Smrg      * object holds an object implicitly convertible to type `T`.
744*627f7eb2Smrg      * Implicit convertibility is defined as per
745*627f7eb2Smrg      * $(REF_ALTTEXT ImplicitConversionTargets, ImplicitConversionTargets, std,traits).
746*627f7eb2Smrg      */
747*627f7eb2Smrg 
748*627f7eb2Smrg     @property bool convertsTo(T)() const
749*627f7eb2Smrg     {
750*627f7eb2Smrg         TypeInfo info = typeid(T);
751*627f7eb2Smrg         return fptr(OpID.testConversion, null, &info) == 0;
752*627f7eb2Smrg     }
753*627f7eb2Smrg 
754*627f7eb2Smrg     /**
755*627f7eb2Smrg     Returns the value stored in the `VariantN` object, either by specifying the
756*627f7eb2Smrg     needed type or the index in the list of allowed types. The latter overload
757*627f7eb2Smrg     only applies to bounded variants (e.g. $(LREF Algebraic)).
758*627f7eb2Smrg 
759*627f7eb2Smrg     Params:
760*627f7eb2Smrg     T = The requested type. The currently stored value must implicitly convert
761*627f7eb2Smrg     to the requested type, in fact `DecayStaticToDynamicArray!T`. If an
762*627f7eb2Smrg     implicit conversion is not possible, throws a `VariantException`.
763*627f7eb2Smrg     index = The index of the type among `AllowedTypesParam`, zero-based.
764*627f7eb2Smrg      */
765*627f7eb2Smrg     @property inout(T) get(T)() inout
766*627f7eb2Smrg     {
767*627f7eb2Smrg         inout(T) result = void;
768*627f7eb2Smrg         static if (is(T == shared))
769*627f7eb2Smrg             alias R = shared Unqual!T;
770*627f7eb2Smrg         else
771*627f7eb2Smrg             alias R = Unqual!T;
772*627f7eb2Smrg         auto buf = tuple(typeid(T), cast(R*)&result);
773*627f7eb2Smrg 
774*627f7eb2Smrg         if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf))
775*627f7eb2Smrg         {
776*627f7eb2Smrg             throw new VariantException(type, typeid(T));
777*627f7eb2Smrg         }
778*627f7eb2Smrg         return result;
779*627f7eb2Smrg     }
780*627f7eb2Smrg 
781*627f7eb2Smrg     /// Ditto
782*627f7eb2Smrg     @property auto get(uint index)() inout
783*627f7eb2Smrg     if (index < AllowedTypes.length)
784*627f7eb2Smrg     {
785*627f7eb2Smrg         foreach (i, T; AllowedTypes)
786*627f7eb2Smrg         {
787*627f7eb2Smrg             static if (index == i) return get!T;
788*627f7eb2Smrg         }
789*627f7eb2Smrg         assert(0);
790*627f7eb2Smrg     }
791*627f7eb2Smrg 
792*627f7eb2Smrg     /**
793*627f7eb2Smrg      * Returns the value stored in the $(D VariantN) object,
794*627f7eb2Smrg      * explicitly converted (coerced) to the requested type $(D
795*627f7eb2Smrg      * T). If $(D T) is a string type, the value is formatted as
796*627f7eb2Smrg      * a string. If the $(D VariantN) object is a string, a
797*627f7eb2Smrg      * parse of the string to type $(D T) is attempted. If a
798*627f7eb2Smrg      * conversion is not possible, throws a $(D
799*627f7eb2Smrg      * VariantException).
800*627f7eb2Smrg      */
801*627f7eb2Smrg 
802*627f7eb2Smrg     @property T coerce(T)()
803*627f7eb2Smrg     {
804*627f7eb2Smrg         import std.conv : to, text;
805*627f7eb2Smrg         static if (isNumeric!T || isBoolean!T)
806*627f7eb2Smrg         {
807*627f7eb2Smrg             if (convertsTo!real)
808*627f7eb2Smrg             {
809*627f7eb2Smrg                 // maybe optimize this fella; handle ints separately
810*627f7eb2Smrg                 return to!T(get!real);
811*627f7eb2Smrg             }
812*627f7eb2Smrg             else if (convertsTo!(const(char)[]))
813*627f7eb2Smrg             {
814*627f7eb2Smrg                 return to!T(get!(const(char)[]));
815*627f7eb2Smrg             }
816*627f7eb2Smrg             // I'm not sure why this doesn't convert to const(char),
817*627f7eb2Smrg             // but apparently it doesn't (probably a deeper bug).
818*627f7eb2Smrg             //
819*627f7eb2Smrg             // Until that is fixed, this quick addition keeps a common
820*627f7eb2Smrg             // function working. "10".coerce!int ought to work.
821*627f7eb2Smrg             else if (convertsTo!(immutable(char)[]))
822*627f7eb2Smrg             {
823*627f7eb2Smrg                 return to!T(get!(immutable(char)[]));
824*627f7eb2Smrg             }
825*627f7eb2Smrg             else
826*627f7eb2Smrg             {
827*627f7eb2Smrg                 import std.exception : enforce;
828*627f7eb2Smrg                 enforce(false, text("Type ", type, " does not convert to ",
829*627f7eb2Smrg                                 typeid(T)));
830*627f7eb2Smrg                 assert(0);
831*627f7eb2Smrg             }
832*627f7eb2Smrg         }
833*627f7eb2Smrg         else static if (is(T : Object))
834*627f7eb2Smrg         {
835*627f7eb2Smrg             return to!(T)(get!(Object));
836*627f7eb2Smrg         }
837*627f7eb2Smrg         else static if (isSomeString!(T))
838*627f7eb2Smrg         {
839*627f7eb2Smrg             return to!(T)(toString());
840*627f7eb2Smrg         }
841*627f7eb2Smrg         else
842*627f7eb2Smrg         {
843*627f7eb2Smrg             // Fix for bug 1649
844*627f7eb2Smrg             static assert(false, "unsupported type for coercion");
845*627f7eb2Smrg         }
846*627f7eb2Smrg     }
847*627f7eb2Smrg 
848*627f7eb2Smrg     /**
849*627f7eb2Smrg      * Formats the stored value as a string.
850*627f7eb2Smrg      */
851*627f7eb2Smrg 
852*627f7eb2Smrg     string toString()
853*627f7eb2Smrg     {
854*627f7eb2Smrg         string result;
855*627f7eb2Smrg         fptr(OpID.toString, &store, &result) == 0 || assert(false);
856*627f7eb2Smrg         return result;
857*627f7eb2Smrg     }
858*627f7eb2Smrg 
859*627f7eb2Smrg     /**
860*627f7eb2Smrg      * Comparison for equality used by the "==" and "!="  operators.
861*627f7eb2Smrg      */
862*627f7eb2Smrg 
863*627f7eb2Smrg     // returns 1 if the two are equal
864*627f7eb2Smrg     bool opEquals(T)(auto ref T rhs) const
865*627f7eb2Smrg     if (allowed!T || is(Unqual!T == VariantN))
866*627f7eb2Smrg     {
867*627f7eb2Smrg         static if (is(Unqual!T == VariantN))
868*627f7eb2Smrg             alias temp = rhs;
869*627f7eb2Smrg         else
870*627f7eb2Smrg             auto temp = VariantN(rhs);
871*627f7eb2Smrg         return !fptr(OpID.equals, cast(ubyte[size]*) &store,
872*627f7eb2Smrg                      cast(void*) &temp);
873*627f7eb2Smrg     }
874*627f7eb2Smrg 
875*627f7eb2Smrg     // workaround for bug 10567 fix
876*627f7eb2Smrg     int opCmp(ref const VariantN rhs) const
877*627f7eb2Smrg     {
878*627f7eb2Smrg         return (cast() this).opCmp!(VariantN)(cast() rhs);
879*627f7eb2Smrg     }
880*627f7eb2Smrg 
881*627f7eb2Smrg     /**
882*627f7eb2Smrg      * Ordering comparison used by the "<", "<=", ">", and ">="
883*627f7eb2Smrg      * operators. In case comparison is not sensible between the held
884*627f7eb2Smrg      * value and $(D rhs), an exception is thrown.
885*627f7eb2Smrg      */
886*627f7eb2Smrg 
887*627f7eb2Smrg     int opCmp(T)(T rhs)
888*627f7eb2Smrg     if (allowed!T)  // includes T == VariantN
889*627f7eb2Smrg     {
890*627f7eb2Smrg         static if (is(T == VariantN))
891*627f7eb2Smrg             alias temp = rhs;
892*627f7eb2Smrg         else
893*627f7eb2Smrg             auto temp = VariantN(rhs);
894*627f7eb2Smrg         auto result = fptr(OpID.compare, &store, &temp);
895*627f7eb2Smrg         if (result == ptrdiff_t.min)
896*627f7eb2Smrg         {
897*627f7eb2Smrg             throw new VariantException(type, temp.type);
898*627f7eb2Smrg         }
899*627f7eb2Smrg 
900*627f7eb2Smrg         assert(result >= -1 && result <= 1);  // Should be true for opCmp.
901*627f7eb2Smrg         return cast(int) result;
902*627f7eb2Smrg     }
903*627f7eb2Smrg 
904*627f7eb2Smrg     /**
905*627f7eb2Smrg      * Computes the hash of the held value.
906*627f7eb2Smrg      */
907*627f7eb2Smrg 
908*627f7eb2Smrg     size_t toHash() const nothrow @safe
909*627f7eb2Smrg     {
910*627f7eb2Smrg         return type.getHash(&store);
911*627f7eb2Smrg     }
912*627f7eb2Smrg 
913*627f7eb2Smrg     private VariantN opArithmetic(T, string op)(T other)
914*627f7eb2Smrg     {
915*627f7eb2Smrg         static if (isInstanceOf!(.VariantN, T))
916*627f7eb2Smrg         {
917*627f7eb2Smrg             string tryUseType(string tp)
918*627f7eb2Smrg             {
919*627f7eb2Smrg                 import std.format : format;
920*627f7eb2Smrg                 return q{
921*627f7eb2Smrg                     static if (allowed!%1$s && T.allowed!%1$s)
922*627f7eb2Smrg                         if (convertsTo!%1$s && other.convertsTo!%1$s)
923*627f7eb2Smrg                             return VariantN(get!%1$s %2$s other.get!%1$s);
924*627f7eb2Smrg                 }.format(tp, op);
925*627f7eb2Smrg             }
926*627f7eb2Smrg 
927*627f7eb2Smrg             mixin(tryUseType("uint"));
928*627f7eb2Smrg             mixin(tryUseType("int"));
929*627f7eb2Smrg             mixin(tryUseType("ulong"));
930*627f7eb2Smrg             mixin(tryUseType("long"));
931*627f7eb2Smrg             mixin(tryUseType("float"));
932*627f7eb2Smrg             mixin(tryUseType("double"));
933*627f7eb2Smrg             mixin(tryUseType("real"));
934*627f7eb2Smrg         }
935*627f7eb2Smrg         else
936*627f7eb2Smrg         {
937*627f7eb2Smrg             static if (allowed!T)
938*627f7eb2Smrg                 if (auto pv = peek!T) return VariantN(mixin("*pv " ~ op ~ " other"));
939*627f7eb2Smrg             static if (allowed!uint && is(typeof(T.max) : uint) && isUnsigned!T)
940*627f7eb2Smrg                 if (convertsTo!uint) return VariantN(mixin("get!(uint) " ~ op ~ " other"));
941*627f7eb2Smrg             static if (allowed!int && is(typeof(T.max) : int) && !isUnsigned!T)
942*627f7eb2Smrg                 if (convertsTo!int) return VariantN(mixin("get!(int) " ~ op ~ " other"));
943*627f7eb2Smrg             static if (allowed!ulong && is(typeof(T.max) : ulong) && isUnsigned!T)
944*627f7eb2Smrg                 if (convertsTo!ulong) return VariantN(mixin("get!(ulong) " ~ op ~ " other"));
945*627f7eb2Smrg             static if (allowed!long && is(typeof(T.max) : long) && !isUnsigned!T)
946*627f7eb2Smrg                 if (convertsTo!long) return VariantN(mixin("get!(long) " ~ op ~ " other"));
947*627f7eb2Smrg             static if (allowed!float && is(T : float))
948*627f7eb2Smrg                 if (convertsTo!float) return VariantN(mixin("get!(float) " ~ op ~ " other"));
949*627f7eb2Smrg             static if (allowed!double && is(T : double))
950*627f7eb2Smrg                 if (convertsTo!double) return VariantN(mixin("get!(double) " ~ op ~ " other"));
951*627f7eb2Smrg             static if (allowed!real && is (T : real))
952*627f7eb2Smrg                 if (convertsTo!real) return VariantN(mixin("get!(real) " ~ op ~ " other"));
953*627f7eb2Smrg         }
954*627f7eb2Smrg 
955*627f7eb2Smrg         throw new VariantException("No possible match found for VariantN "~op~" "~T.stringof);
956*627f7eb2Smrg     }
957*627f7eb2Smrg 
958*627f7eb2Smrg     private VariantN opLogic(T, string op)(T other)
959*627f7eb2Smrg     {
960*627f7eb2Smrg         VariantN result;
961*627f7eb2Smrg         static if (is(T == VariantN))
962*627f7eb2Smrg         {
963*627f7eb2Smrg             if (convertsTo!(uint) && other.convertsTo!(uint))
964*627f7eb2Smrg                 result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
965*627f7eb2Smrg             else if (convertsTo!(int) && other.convertsTo!(int))
966*627f7eb2Smrg                 result = mixin("get!(int) " ~ op ~ " other.get!(int)");
967*627f7eb2Smrg             else if (convertsTo!(ulong) && other.convertsTo!(ulong))
968*627f7eb2Smrg                 result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
969*627f7eb2Smrg             else
970*627f7eb2Smrg                 result = mixin("get!(long) " ~ op ~ " other.get!(long)");
971*627f7eb2Smrg         }
972*627f7eb2Smrg         else
973*627f7eb2Smrg         {
974*627f7eb2Smrg             if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
975*627f7eb2Smrg                 result = mixin("get!(uint) " ~ op ~ " other");
976*627f7eb2Smrg             else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
977*627f7eb2Smrg                 result = mixin("get!(int) " ~ op ~ " other");
978*627f7eb2Smrg             else if (is(typeof(T.max) : ulong) && T.min == 0
979*627f7eb2Smrg                      && convertsTo!(ulong))
980*627f7eb2Smrg                 result = mixin("get!(ulong) " ~ op ~ " other");
981*627f7eb2Smrg             else
982*627f7eb2Smrg                 result = mixin("get!(long) " ~ op ~ " other");
983*627f7eb2Smrg         }
984*627f7eb2Smrg         return result;
985*627f7eb2Smrg     }
986*627f7eb2Smrg 
987*627f7eb2Smrg     /**
988*627f7eb2Smrg      * Arithmetic between $(D VariantN) objects and numeric
989*627f7eb2Smrg      * values. All arithmetic operations return a $(D VariantN)
990*627f7eb2Smrg      * object typed depending on the types of both values
991*627f7eb2Smrg      * involved. The conversion rules mimic D's built-in rules for
992*627f7eb2Smrg      * arithmetic conversions.
993*627f7eb2Smrg      */
994*627f7eb2Smrg 
995*627f7eb2Smrg     // Adapted from http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/Variant
996*627f7eb2Smrg     // arithmetic
997*627f7eb2Smrg     VariantN opAdd(T)(T rhs) { return opArithmetic!(T, "+")(rhs); }
998*627f7eb2Smrg     ///ditto
999*627f7eb2Smrg     VariantN opSub(T)(T rhs) { return opArithmetic!(T, "-")(rhs); }
1000*627f7eb2Smrg 
1001*627f7eb2Smrg     // Commenteed all _r versions for now because of ambiguities
1002*627f7eb2Smrg     // arising when two Variants are used
1003*627f7eb2Smrg 
1004*627f7eb2Smrg     // ///ditto
1005*627f7eb2Smrg     // VariantN opSub_r(T)(T lhs)
1006*627f7eb2Smrg     // {
1007*627f7eb2Smrg     //     return VariantN(lhs).opArithmetic!(VariantN, "-")(this);
1008*627f7eb2Smrg     // }
1009*627f7eb2Smrg     ///ditto
1010*627f7eb2Smrg     VariantN opMul(T)(T rhs) { return opArithmetic!(T, "*")(rhs); }
1011*627f7eb2Smrg     ///ditto
1012*627f7eb2Smrg     VariantN opDiv(T)(T rhs) { return opArithmetic!(T, "/")(rhs); }
1013*627f7eb2Smrg     // ///ditto
1014*627f7eb2Smrg     // VariantN opDiv_r(T)(T lhs)
1015*627f7eb2Smrg     // {
1016*627f7eb2Smrg     //     return VariantN(lhs).opArithmetic!(VariantN, "/")(this);
1017*627f7eb2Smrg     // }
1018*627f7eb2Smrg     ///ditto
1019*627f7eb2Smrg     VariantN opMod(T)(T rhs) { return opArithmetic!(T, "%")(rhs); }
1020*627f7eb2Smrg     // ///ditto
1021*627f7eb2Smrg     // VariantN opMod_r(T)(T lhs)
1022*627f7eb2Smrg     // {
1023*627f7eb2Smrg     //     return VariantN(lhs).opArithmetic!(VariantN, "%")(this);
1024*627f7eb2Smrg     // }
1025*627f7eb2Smrg     ///ditto
1026*627f7eb2Smrg     VariantN opAnd(T)(T rhs) { return opLogic!(T, "&")(rhs); }
1027*627f7eb2Smrg     ///ditto
1028*627f7eb2Smrg     VariantN opOr(T)(T rhs) { return opLogic!(T, "|")(rhs); }
1029*627f7eb2Smrg     ///ditto
1030*627f7eb2Smrg     VariantN opXor(T)(T rhs) { return opLogic!(T, "^")(rhs); }
1031*627f7eb2Smrg     ///ditto
1032*627f7eb2Smrg     VariantN opShl(T)(T rhs) { return opLogic!(T, "<<")(rhs); }
1033*627f7eb2Smrg     // ///ditto
1034*627f7eb2Smrg     // VariantN opShl_r(T)(T lhs)
1035*627f7eb2Smrg     // {
1036*627f7eb2Smrg     //     return VariantN(lhs).opLogic!(VariantN, "<<")(this);
1037*627f7eb2Smrg     // }
1038*627f7eb2Smrg     ///ditto
1039*627f7eb2Smrg     VariantN opShr(T)(T rhs) { return opLogic!(T, ">>")(rhs); }
1040*627f7eb2Smrg     // ///ditto
1041*627f7eb2Smrg     // VariantN opShr_r(T)(T lhs)
1042*627f7eb2Smrg     // {
1043*627f7eb2Smrg     //     return VariantN(lhs).opLogic!(VariantN, ">>")(this);
1044*627f7eb2Smrg     // }
1045*627f7eb2Smrg     ///ditto
1046*627f7eb2Smrg     VariantN opUShr(T)(T rhs) { return opLogic!(T, ">>>")(rhs); }
1047*627f7eb2Smrg     // ///ditto
1048*627f7eb2Smrg     // VariantN opUShr_r(T)(T lhs)
1049*627f7eb2Smrg     // {
1050*627f7eb2Smrg     //     return VariantN(lhs).opLogic!(VariantN, ">>>")(this);
1051*627f7eb2Smrg     // }
1052*627f7eb2Smrg     ///ditto
1053*627f7eb2Smrg     VariantN opCat(T)(T rhs)
1054*627f7eb2Smrg     {
1055*627f7eb2Smrg         auto temp = this;
1056*627f7eb2Smrg         temp ~= rhs;
1057*627f7eb2Smrg         return temp;
1058*627f7eb2Smrg     }
1059*627f7eb2Smrg     // ///ditto
1060*627f7eb2Smrg     // VariantN opCat_r(T)(T rhs)
1061*627f7eb2Smrg     // {
1062*627f7eb2Smrg     //     VariantN temp = rhs;
1063*627f7eb2Smrg     //     temp ~= this;
1064*627f7eb2Smrg     //     return temp;
1065*627f7eb2Smrg     // }
1066*627f7eb2Smrg 
1067*627f7eb2Smrg     ///ditto
1068*627f7eb2Smrg     VariantN opAddAssign(T)(T rhs)  { return this = this + rhs; }
1069*627f7eb2Smrg     ///ditto
1070*627f7eb2Smrg     VariantN opSubAssign(T)(T rhs)  { return this = this - rhs; }
1071*627f7eb2Smrg     ///ditto
1072*627f7eb2Smrg     VariantN opMulAssign(T)(T rhs)  { return this = this * rhs; }
1073*627f7eb2Smrg     ///ditto
1074*627f7eb2Smrg     VariantN opDivAssign(T)(T rhs)  { return this = this / rhs; }
1075*627f7eb2Smrg     ///ditto
1076*627f7eb2Smrg     VariantN opModAssign(T)(T rhs)  { return this = this % rhs; }
1077*627f7eb2Smrg     ///ditto
1078*627f7eb2Smrg     VariantN opAndAssign(T)(T rhs)  { return this = this & rhs; }
1079*627f7eb2Smrg     ///ditto
1080*627f7eb2Smrg     VariantN opOrAssign(T)(T rhs)   { return this = this | rhs; }
1081*627f7eb2Smrg     ///ditto
1082*627f7eb2Smrg     VariantN opXorAssign(T)(T rhs)  { return this = this ^ rhs; }
1083*627f7eb2Smrg     ///ditto
1084*627f7eb2Smrg     VariantN opShlAssign(T)(T rhs)  { return this = this << rhs; }
1085*627f7eb2Smrg     ///ditto
1086*627f7eb2Smrg     VariantN opShrAssign(T)(T rhs)  { return this = this >> rhs; }
1087*627f7eb2Smrg     ///ditto
1088*627f7eb2Smrg     VariantN opUShrAssign(T)(T rhs) { return this = this >>> rhs; }
1089*627f7eb2Smrg     ///ditto
1090*627f7eb2Smrg     VariantN opCatAssign(T)(T rhs)
1091*627f7eb2Smrg     {
1092*627f7eb2Smrg         auto toAppend = Variant(rhs);
1093*627f7eb2Smrg         fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
1094*627f7eb2Smrg         return this;
1095*627f7eb2Smrg     }
1096*627f7eb2Smrg 
1097*627f7eb2Smrg     /**
1098*627f7eb2Smrg      * Array and associative array operations. If a $(D
1099*627f7eb2Smrg      * VariantN) contains an (associative) array, it can be indexed
1100*627f7eb2Smrg      * into. Otherwise, an exception is thrown.
1101*627f7eb2Smrg      */
1102*627f7eb2Smrg     inout(Variant) opIndex(K)(K i) inout
1103*627f7eb2Smrg     {
1104*627f7eb2Smrg         auto result = Variant(i);
1105*627f7eb2Smrg         fptr(OpID.index, cast(ubyte[size]*) &store, &result) == 0 || assert(false);
1106*627f7eb2Smrg         return result;
1107*627f7eb2Smrg     }
1108*627f7eb2Smrg 
1109*627f7eb2Smrg     ///
1110*627f7eb2Smrg     static if (doUnittest)
1111*627f7eb2Smrg     @system unittest
1112*627f7eb2Smrg     {
1113*627f7eb2Smrg         Variant a = new int[10];
1114*627f7eb2Smrg         a[5] = 42;
1115*627f7eb2Smrg         assert(a[5] == 42);
1116*627f7eb2Smrg         a[5] += 8;
1117*627f7eb2Smrg         assert(a[5] == 50);
1118*627f7eb2Smrg 
1119*627f7eb2Smrg         int[int] hash = [ 42:24 ];
1120*627f7eb2Smrg         a = hash;
1121*627f7eb2Smrg         assert(a[42] == 24);
1122*627f7eb2Smrg         a[42] /= 2;
1123*627f7eb2Smrg         assert(a[42] == 12);
1124*627f7eb2Smrg     }
1125*627f7eb2Smrg 
1126*627f7eb2Smrg     /// ditto
1127*627f7eb2Smrg     Variant opIndexAssign(T, N)(T value, N i)
1128*627f7eb2Smrg     {
1129*627f7eb2Smrg         static if (AllowedTypes.length && !isInstanceOf!(.VariantN, T))
1130*627f7eb2Smrg         {
1131*627f7eb2Smrg             enum canAssign(U) = __traits(compiles, (U u){ u[i] = value; });
1132*627f7eb2Smrg             static assert(anySatisfy!(canAssign, AllowedTypes),
1133*627f7eb2Smrg                 "Cannot assign " ~ T.stringof ~ " to " ~ VariantN.stringof ~
1134*627f7eb2Smrg                 " indexed with " ~ N.stringof);
1135*627f7eb2Smrg         }
1136*627f7eb2Smrg         Variant[2] args = [ Variant(value), Variant(i) ];
1137*627f7eb2Smrg         fptr(OpID.indexAssign, &store, &args) == 0 || assert(false);
1138*627f7eb2Smrg         return args[0];
1139*627f7eb2Smrg     }
1140*627f7eb2Smrg 
1141*627f7eb2Smrg     /// ditto
1142*627f7eb2Smrg     Variant opIndexOpAssign(string op, T, N)(T value, N i)
1143*627f7eb2Smrg     {
1144*627f7eb2Smrg         return opIndexAssign(mixin(`opIndex(i)` ~ op ~ `value`), i);
1145*627f7eb2Smrg     }
1146*627f7eb2Smrg 
1147*627f7eb2Smrg     /** If the $(D VariantN) contains an (associative) array,
1148*627f7eb2Smrg      * returns the _length of that array. Otherwise, throws an
1149*627f7eb2Smrg      * exception.
1150*627f7eb2Smrg      */
1151*627f7eb2Smrg     @property size_t length()
1152*627f7eb2Smrg     {
1153*627f7eb2Smrg         return cast(size_t) fptr(OpID.length, &store, null);
1154*627f7eb2Smrg     }
1155*627f7eb2Smrg 
1156*627f7eb2Smrg     /**
1157*627f7eb2Smrg        If the $(D VariantN) contains an array, applies $(D dg) to each
1158*627f7eb2Smrg        element of the array in turn. Otherwise, throws an exception.
1159*627f7eb2Smrg      */
1160*627f7eb2Smrg     int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate))
1161*627f7eb2Smrg     {
1162*627f7eb2Smrg         alias A = Parameters!(Delegate)[0];
1163*627f7eb2Smrg         if (type == typeid(A[]))
1164*627f7eb2Smrg         {
1165*627f7eb2Smrg             auto arr = get!(A[]);
1166*627f7eb2Smrg             foreach (ref e; arr)
1167*627f7eb2Smrg             {
1168*627f7eb2Smrg                 if (dg(e)) return 1;
1169*627f7eb2Smrg             }
1170*627f7eb2Smrg         }
1171*627f7eb2Smrg         else static if (is(A == VariantN))
1172*627f7eb2Smrg         {
1173*627f7eb2Smrg             foreach (i; 0 .. length)
1174*627f7eb2Smrg             {
1175*627f7eb2Smrg                 // @@@TODO@@@: find a better way to not confuse
1176*627f7eb2Smrg                 // clients who think they change values stored in the
1177*627f7eb2Smrg                 // Variant when in fact they are only changing tmp.
1178*627f7eb2Smrg                 auto tmp = this[i];
1179*627f7eb2Smrg                 debug scope(exit) assert(tmp == this[i]);
1180*627f7eb2Smrg                 if (dg(tmp)) return 1;
1181*627f7eb2Smrg             }
1182*627f7eb2Smrg         }
1183*627f7eb2Smrg         else
1184*627f7eb2Smrg         {
1185*627f7eb2Smrg             import std.conv : text;
1186*627f7eb2Smrg             import std.exception : enforce;
1187*627f7eb2Smrg             enforce(false, text("Variant type ", type,
1188*627f7eb2Smrg                             " not iterable with values of type ",
1189*627f7eb2Smrg                             A.stringof));
1190*627f7eb2Smrg         }
1191*627f7eb2Smrg         return 0;
1192*627f7eb2Smrg     }
1193*627f7eb2Smrg }
1194*627f7eb2Smrg 
1195*627f7eb2Smrg @system unittest
1196*627f7eb2Smrg {
1197*627f7eb2Smrg     import std.conv : to;
1198*627f7eb2Smrg     Variant v;
foo()1199*627f7eb2Smrg     int foo() { return 42; }
1200*627f7eb2Smrg     v = &foo;
1201*627f7eb2Smrg     assert(v() == 42);
1202*627f7eb2Smrg 
bar(string s)1203*627f7eb2Smrg     static int bar(string s) { return to!int(s); }
1204*627f7eb2Smrg     v = &bar;
1205*627f7eb2Smrg     assert(v("43") == 43);
1206*627f7eb2Smrg }
1207*627f7eb2Smrg 
1208*627f7eb2Smrg @system unittest
1209*627f7eb2Smrg {
1210*627f7eb2Smrg     int[int] hash = [ 42:24 ];
1211*627f7eb2Smrg     Variant v = hash;
1212*627f7eb2Smrg     assert(v[42] == 24);
1213*627f7eb2Smrg     v[42] = 5;
1214*627f7eb2Smrg     assert(v[42] == 5);
1215*627f7eb2Smrg }
1216*627f7eb2Smrg 
1217*627f7eb2Smrg // opIndex with static arrays, issue 12771
1218*627f7eb2Smrg @system unittest
1219*627f7eb2Smrg {
1220*627f7eb2Smrg     int[4] elements = [0, 1, 2, 3];
1221*627f7eb2Smrg     Variant v = elements;
1222*627f7eb2Smrg     assert(v == elements);
1223*627f7eb2Smrg     assert(v[2] == 2);
1224*627f7eb2Smrg     assert(v[3] == 3);
1225*627f7eb2Smrg     v[2] = 6;
1226*627f7eb2Smrg     assert(v[2] == 6);
1227*627f7eb2Smrg     assert(v != elements);
1228*627f7eb2Smrg }
1229*627f7eb2Smrg 
1230*627f7eb2Smrg @system unittest
1231*627f7eb2Smrg {
1232*627f7eb2Smrg     import std.exception : assertThrown;
1233*627f7eb2Smrg     Algebraic!(int[]) v = [2, 2];
1234*627f7eb2Smrg 
1235*627f7eb2Smrg     assert(v == [2, 2]);
1236*627f7eb2Smrg     v[0] = 1;
1237*627f7eb2Smrg     assert(v[0] == 1);
1238*627f7eb2Smrg     assert(v != [2, 2]);
1239*627f7eb2Smrg 
1240*627f7eb2Smrg     // opIndexAssign from Variant
1241*627f7eb2Smrg     v[1] = v[0];
1242*627f7eb2Smrg     assert(v[1] == 1);
1243*627f7eb2Smrg 
1244*627f7eb2Smrg     static assert(!__traits(compiles, (v[1] = null)));
1245*627f7eb2Smrg     assertThrown!VariantException(v[1] = Variant(null));
1246*627f7eb2Smrg }
1247*627f7eb2Smrg 
1248*627f7eb2Smrg //Issue# 8195
1249*627f7eb2Smrg @system unittest
1250*627f7eb2Smrg {
1251*627f7eb2Smrg     struct S
1252*627f7eb2Smrg     {
1253*627f7eb2Smrg         int a;
1254*627f7eb2Smrg         long b;
1255*627f7eb2Smrg         string c;
1256*627f7eb2Smrg         real d = 0.0;
1257*627f7eb2Smrg         bool e;
1258*627f7eb2Smrg     }
1259*627f7eb2Smrg 
1260*627f7eb2Smrg     static assert(S.sizeof >= Variant.sizeof);
1261*627f7eb2Smrg     alias Types = AliasSeq!(string, int, S);
1262*627f7eb2Smrg     alias MyVariant = VariantN!(maxSize!Types, Types);
1263*627f7eb2Smrg 
1264*627f7eb2Smrg     auto v = MyVariant(S.init);
1265*627f7eb2Smrg     assert(v == S.init);
1266*627f7eb2Smrg }
1267*627f7eb2Smrg 
1268*627f7eb2Smrg // Issue #10961
1269*627f7eb2Smrg @system unittest
1270*627f7eb2Smrg {
1271*627f7eb2Smrg     // Primarily test that we can assign a void[] to a Variant.
1272*627f7eb2Smrg     void[] elements = cast(void[])[1, 2, 3];
1273*627f7eb2Smrg     Variant v = elements;
1274*627f7eb2Smrg     void[] returned = v.get!(void[]);
1275*627f7eb2Smrg     assert(returned == elements);
1276*627f7eb2Smrg }
1277*627f7eb2Smrg 
1278*627f7eb2Smrg // Issue #13352
1279*627f7eb2Smrg @system unittest
1280*627f7eb2Smrg {
1281*627f7eb2Smrg     alias TP = Algebraic!(long);
1282*627f7eb2Smrg     auto a = TP(1L);
1283*627f7eb2Smrg     auto b = TP(2L);
1284*627f7eb2Smrg     assert(!TP.allowed!ulong);
1285*627f7eb2Smrg     assert(a + b == 3L);
1286*627f7eb2Smrg     assert(a + 2 == 3L);
1287*627f7eb2Smrg     assert(1 + b == 3L);
1288*627f7eb2Smrg 
1289*627f7eb2Smrg     alias TP2 = Algebraic!(long, string);
1290*627f7eb2Smrg     auto c = TP2(3L);
1291*627f7eb2Smrg     assert(a + c == 4L);
1292*627f7eb2Smrg }
1293*627f7eb2Smrg 
1294*627f7eb2Smrg // Issue #13354
1295*627f7eb2Smrg @system unittest
1296*627f7eb2Smrg {
1297*627f7eb2Smrg     alias A = Algebraic!(string[]);
1298*627f7eb2Smrg     A a = ["a", "b"];
1299*627f7eb2Smrg     assert(a[0] == "a");
1300*627f7eb2Smrg     assert(a[1] == "b");
1301*627f7eb2Smrg     a[1] = "c";
1302*627f7eb2Smrg     assert(a[1] == "c");
1303*627f7eb2Smrg 
1304*627f7eb2Smrg     alias AA = Algebraic!(int[string]);
1305*627f7eb2Smrg     AA aa = ["a": 1, "b": 2];
1306*627f7eb2Smrg     assert(aa["a"] == 1);
1307*627f7eb2Smrg     assert(aa["b"] == 2);
1308*627f7eb2Smrg     aa["b"] = 3;
1309*627f7eb2Smrg     assert(aa["b"] == 3);
1310*627f7eb2Smrg }
1311*627f7eb2Smrg 
1312*627f7eb2Smrg // Issue #14198
1313*627f7eb2Smrg @system unittest
1314*627f7eb2Smrg {
1315*627f7eb2Smrg     Variant a = true;
1316*627f7eb2Smrg     assert(a.type == typeid(bool));
1317*627f7eb2Smrg }
1318*627f7eb2Smrg 
1319*627f7eb2Smrg // Issue #14233
1320*627f7eb2Smrg @system unittest
1321*627f7eb2Smrg {
1322*627f7eb2Smrg     alias Atom = Algebraic!(string, This[]);
1323*627f7eb2Smrg 
1324*627f7eb2Smrg     Atom[] values = [];
1325*627f7eb2Smrg     auto a = Atom(values);
1326*627f7eb2Smrg }
1327*627f7eb2Smrg 
1328*627f7eb2Smrg pure nothrow @nogc
1329*627f7eb2Smrg @system unittest
1330*627f7eb2Smrg {
1331*627f7eb2Smrg     Algebraic!(int, double) a;
1332*627f7eb2Smrg     a = 100;
1333*627f7eb2Smrg     a = 1.0;
1334*627f7eb2Smrg }
1335*627f7eb2Smrg 
1336*627f7eb2Smrg // Issue 14457
1337*627f7eb2Smrg @system unittest
1338*627f7eb2Smrg {
1339*627f7eb2Smrg     alias A = Algebraic!(int, float, double);
1340*627f7eb2Smrg     alias B = Algebraic!(int, float);
1341*627f7eb2Smrg 
1342*627f7eb2Smrg     A a = 1;
1343*627f7eb2Smrg     B b = 6f;
1344*627f7eb2Smrg     a = b;
1345*627f7eb2Smrg 
1346*627f7eb2Smrg     assert(a.type == typeid(float));
1347*627f7eb2Smrg     assert(a.get!float == 6f);
1348*627f7eb2Smrg }
1349*627f7eb2Smrg 
1350*627f7eb2Smrg // Issue 14585
1351*627f7eb2Smrg @system unittest
1352*627f7eb2Smrg {
1353*627f7eb2Smrg     static struct S
1354*627f7eb2Smrg     {
1355*627f7eb2Smrg         int x = 42;
~thisS1356*627f7eb2Smrg         ~this() {assert(x == 42);}
1357*627f7eb2Smrg     }
1358*627f7eb2Smrg     Variant(S()).get!S;
1359*627f7eb2Smrg }
1360*627f7eb2Smrg 
1361*627f7eb2Smrg // Issue 14586
1362*627f7eb2Smrg @system unittest
1363*627f7eb2Smrg {
1364*627f7eb2Smrg     const Variant v = new immutable Object;
1365*627f7eb2Smrg     v.get!(immutable Object);
1366*627f7eb2Smrg }
1367*627f7eb2Smrg 
1368*627f7eb2Smrg @system unittest
1369*627f7eb2Smrg {
1370*627f7eb2Smrg     static struct S
1371*627f7eb2Smrg     {
opCastS1372*627f7eb2Smrg         T opCast(T)() {assert(false);}
1373*627f7eb2Smrg     }
1374*627f7eb2Smrg     Variant v = S();
1375*627f7eb2Smrg     v.get!S;
1376*627f7eb2Smrg }
1377*627f7eb2Smrg 
1378*627f7eb2Smrg 
1379*627f7eb2Smrg /**
1380*627f7eb2Smrg _Algebraic data type restricted to a closed set of possible
1381*627f7eb2Smrg types. It's an alias for $(LREF VariantN) with an
1382*627f7eb2Smrg appropriately-constructed maximum size. `Algebraic` is
1383*627f7eb2Smrg useful when it is desirable to restrict what a discriminated type
1384*627f7eb2Smrg could hold to the end of defining simpler and more efficient
1385*627f7eb2Smrg manipulation.
1386*627f7eb2Smrg 
1387*627f7eb2Smrg */
Algebraic(T...)1388*627f7eb2Smrg template Algebraic(T...)
1389*627f7eb2Smrg {
1390*627f7eb2Smrg     alias Algebraic = VariantN!(maxSize!T, T);
1391*627f7eb2Smrg }
1392*627f7eb2Smrg 
1393*627f7eb2Smrg ///
1394*627f7eb2Smrg @system unittest
1395*627f7eb2Smrg {
1396*627f7eb2Smrg     auto v = Algebraic!(int, double, string)(5);
1397*627f7eb2Smrg     assert(v.peek!(int));
1398*627f7eb2Smrg     v = 3.14;
1399*627f7eb2Smrg     assert(v.peek!(double));
1400*627f7eb2Smrg     // auto x = v.peek!(long); // won't compile, type long not allowed
1401*627f7eb2Smrg     // v = '1'; // won't compile, type char not allowed
1402*627f7eb2Smrg }
1403*627f7eb2Smrg 
1404*627f7eb2Smrg /**
1405*627f7eb2Smrg $(H4 Self-Referential Types)
1406*627f7eb2Smrg 
1407*627f7eb2Smrg A useful and popular use of algebraic data structures is for defining $(LUCKY
1408*627f7eb2Smrg self-referential data structures), i.e. structures that embed references to
1409*627f7eb2Smrg values of their own type within.
1410*627f7eb2Smrg 
1411*627f7eb2Smrg This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1412*627f7eb2Smrg reference to the type being defined is needed. The `Algebraic` instantiation
1413*627f7eb2Smrg will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1414*627f7eb2Smrg alpha renaming) on its constituent types, replacing `This`
1415*627f7eb2Smrg with the self-referenced type. The structure of the type involving `This` may
1416*627f7eb2Smrg be arbitrarily complex.
1417*627f7eb2Smrg */
1418*627f7eb2Smrg @system unittest
1419*627f7eb2Smrg {
1420*627f7eb2Smrg     import std.typecons : Tuple, tuple;
1421*627f7eb2Smrg 
1422*627f7eb2Smrg     // A tree is either a leaf or a branch of two other trees
1423*627f7eb2Smrg     alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
1424*627f7eb2Smrg     Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
1425*627f7eb2Smrg     Tree!int* right = tree.get!1[1];
1426*627f7eb2Smrg     assert(*right == 43);
1427*627f7eb2Smrg 
1428*627f7eb2Smrg     // An object is a double, a string, or a hash of objects
1429*627f7eb2Smrg     alias Obj = Algebraic!(double, string, This[string]);
1430*627f7eb2Smrg     Obj obj = "hello";
1431*627f7eb2Smrg     assert(obj.get!1 == "hello");
1432*627f7eb2Smrg     obj = 42.0;
1433*627f7eb2Smrg     assert(obj.get!0 == 42);
1434*627f7eb2Smrg     obj = ["customer": Obj("John"), "paid": Obj(23.95)];
1435*627f7eb2Smrg     assert(obj.get!2["customer"] == "John");
1436*627f7eb2Smrg }
1437*627f7eb2Smrg 
1438*627f7eb2Smrg /**
1439*627f7eb2Smrg Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1440*627f7eb2Smrg `char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1441*627f7eb2Smrg to hold all of D's predefined types unboxed, including all numeric types,
1442*627f7eb2Smrg pointers, delegates, and class references.  You may want to use
1443*627f7eb2Smrg $(D VariantN) directly with a different maximum size either for
1444*627f7eb2Smrg storing larger types unboxed, or for saving memory.
1445*627f7eb2Smrg  */
1446*627f7eb2Smrg alias Variant = VariantN!(maxSize!(creal, char[], void delegate()));
1447*627f7eb2Smrg 
1448*627f7eb2Smrg /**
1449*627f7eb2Smrg  * Returns an array of variants constructed from $(D args).
1450*627f7eb2Smrg  *
1451*627f7eb2Smrg  * This is by design. During construction the $(D Variant) needs
1452*627f7eb2Smrg  * static type information about the type being held, so as to store a
1453*627f7eb2Smrg  * pointer to function for fast retrieval.
1454*627f7eb2Smrg  */
variantArray(T...)1455*627f7eb2Smrg Variant[] variantArray(T...)(T args)
1456*627f7eb2Smrg {
1457*627f7eb2Smrg     Variant[] result;
1458*627f7eb2Smrg     foreach (arg; args)
1459*627f7eb2Smrg     {
1460*627f7eb2Smrg         result ~= Variant(arg);
1461*627f7eb2Smrg     }
1462*627f7eb2Smrg     return result;
1463*627f7eb2Smrg }
1464*627f7eb2Smrg 
1465*627f7eb2Smrg ///
1466*627f7eb2Smrg @system unittest
1467*627f7eb2Smrg {
1468*627f7eb2Smrg     auto a = variantArray(1, 3.14, "Hi!");
1469*627f7eb2Smrg     assert(a[1] == 3.14);
1470*627f7eb2Smrg     auto b = Variant(a); // variant array as variant
1471*627f7eb2Smrg     assert(b[1] == 3.14);
1472*627f7eb2Smrg }
1473*627f7eb2Smrg 
1474*627f7eb2Smrg /**
1475*627f7eb2Smrg  * Thrown in three cases:
1476*627f7eb2Smrg  *
1477*627f7eb2Smrg  * $(OL $(LI An uninitialized `Variant` is used in any way except
1478*627f7eb2Smrg  * assignment and $(D hasValue);) $(LI A $(D get) or
1479*627f7eb2Smrg  * $(D coerce) is attempted with an incompatible target type;)
1480*627f7eb2Smrg  * $(LI A comparison between $(D Variant) objects of
1481*627f7eb2Smrg  * incompatible types is attempted.))
1482*627f7eb2Smrg  *
1483*627f7eb2Smrg  */
1484*627f7eb2Smrg 
1485*627f7eb2Smrg // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE
1486*627f7eb2Smrg static class VariantException : Exception
1487*627f7eb2Smrg {
1488*627f7eb2Smrg     /// The source type in the conversion or comparison
1489*627f7eb2Smrg     TypeInfo source;
1490*627f7eb2Smrg     /// The target type in the conversion or comparison
1491*627f7eb2Smrg     TypeInfo target;
this(string s)1492*627f7eb2Smrg     this(string s)
1493*627f7eb2Smrg     {
1494*627f7eb2Smrg         super(s);
1495*627f7eb2Smrg     }
this(TypeInfo source,TypeInfo target)1496*627f7eb2Smrg     this(TypeInfo source, TypeInfo target)
1497*627f7eb2Smrg     {
1498*627f7eb2Smrg         super("Variant: attempting to use incompatible types "
1499*627f7eb2Smrg                             ~ source.toString()
1500*627f7eb2Smrg                             ~ " and " ~ target.toString());
1501*627f7eb2Smrg         this.source = source;
1502*627f7eb2Smrg         this.target = target;
1503*627f7eb2Smrg     }
1504*627f7eb2Smrg }
1505*627f7eb2Smrg 
1506*627f7eb2Smrg @system unittest
1507*627f7eb2Smrg {
1508*627f7eb2Smrg     alias W1 = This2Variant!(char, int, This[int]);
1509*627f7eb2Smrg     alias W2 = AliasSeq!(int, char[int]);
1510*627f7eb2Smrg     static assert(is(W1 == W2));
1511*627f7eb2Smrg 
1512*627f7eb2Smrg     alias var_t = Algebraic!(void, string);
1513*627f7eb2Smrg     var_t foo = "quux";
1514*627f7eb2Smrg }
1515*627f7eb2Smrg 
1516*627f7eb2Smrg @system unittest
1517*627f7eb2Smrg {
1518*627f7eb2Smrg      alias A = Algebraic!(real, This[], This[int], This[This]);
1519*627f7eb2Smrg      A v1, v2, v3;
1520*627f7eb2Smrg      v2 = 5.0L;
1521*627f7eb2Smrg      v3 = 42.0L;
1522*627f7eb2Smrg      //v1 = [ v2 ][];
1523*627f7eb2Smrg       auto v = v1.peek!(A[]);
1524*627f7eb2Smrg      //writeln(v[0]);
1525*627f7eb2Smrg      v1 = [ 9 : v3 ];
1526*627f7eb2Smrg      //writeln(v1);
1527*627f7eb2Smrg      v1 = [ v3 : v3 ];
1528*627f7eb2Smrg      //writeln(v1);
1529*627f7eb2Smrg }
1530*627f7eb2Smrg 
1531*627f7eb2Smrg @system unittest
1532*627f7eb2Smrg {
1533*627f7eb2Smrg     import std.conv : ConvException;
1534*627f7eb2Smrg     import std.exception : assertThrown, collectException;
1535*627f7eb2Smrg     // try it with an oddly small size
1536*627f7eb2Smrg     VariantN!(1) test;
1537*627f7eb2Smrg     assert(test.size > 1);
1538*627f7eb2Smrg 
1539*627f7eb2Smrg     // variantArray tests
1540*627f7eb2Smrg     auto heterogeneous = variantArray(1, 4.5, "hi");
1541*627f7eb2Smrg     assert(heterogeneous.length == 3);
1542*627f7eb2Smrg     auto variantArrayAsVariant = Variant(heterogeneous);
1543*627f7eb2Smrg     assert(variantArrayAsVariant[0] == 1);
1544*627f7eb2Smrg     assert(variantArrayAsVariant.length == 3);
1545*627f7eb2Smrg 
1546*627f7eb2Smrg     // array tests
1547*627f7eb2Smrg     auto arr = Variant([1.2].dup);
1548*627f7eb2Smrg     auto e = arr[0];
1549*627f7eb2Smrg     assert(e == 1.2);
1550*627f7eb2Smrg     arr[0] = 2.0;
1551*627f7eb2Smrg     assert(arr[0] == 2);
1552*627f7eb2Smrg     arr ~= 4.5;
1553*627f7eb2Smrg     assert(arr[1] == 4.5);
1554*627f7eb2Smrg 
1555*627f7eb2Smrg     // general tests
1556*627f7eb2Smrg     Variant a;
1557*627f7eb2Smrg     auto b = Variant(5);
1558*627f7eb2Smrg     assert(!b.peek!(real) && b.peek!(int));
1559*627f7eb2Smrg     // assign
1560*627f7eb2Smrg     a = *b.peek!(int);
1561*627f7eb2Smrg     // comparison
1562*627f7eb2Smrg     assert(a == b, a.type.toString() ~ " " ~ b.type.toString());
1563*627f7eb2Smrg     auto c = Variant("this is a string");
1564*627f7eb2Smrg     assert(a != c);
1565*627f7eb2Smrg     // comparison via implicit conversions
1566*627f7eb2Smrg     a = 42; b = 42.0; assert(a == b);
1567*627f7eb2Smrg 
1568*627f7eb2Smrg     // try failing conversions
1569*627f7eb2Smrg     bool failed = false;
1570*627f7eb2Smrg     try
1571*627f7eb2Smrg     {
1572*627f7eb2Smrg         auto d = c.get!(int);
1573*627f7eb2Smrg     }
catch(Exception e)1574*627f7eb2Smrg     catch (Exception e)
1575*627f7eb2Smrg     {
1576*627f7eb2Smrg         //writeln(stderr, e.toString);
1577*627f7eb2Smrg         failed = true;
1578*627f7eb2Smrg     }
1579*627f7eb2Smrg     assert(failed); // :o)
1580*627f7eb2Smrg 
1581*627f7eb2Smrg     // toString tests
1582*627f7eb2Smrg     a = Variant(42); assert(a.toString() == "42");
1583*627f7eb2Smrg     a = Variant(42.22); assert(a.toString() == "42.22");
1584*627f7eb2Smrg 
1585*627f7eb2Smrg     // coerce tests
1586*627f7eb2Smrg     a = Variant(42.22); assert(a.coerce!(int) == 42);
1587*627f7eb2Smrg     a = cast(short) 5; assert(a.coerce!(double) == 5);
1588*627f7eb2Smrg     a = Variant("10"); assert(a.coerce!int == 10);
1589*627f7eb2Smrg 
1590*627f7eb2Smrg     a = Variant(1);
1591*627f7eb2Smrg     assert(a.coerce!bool);
1592*627f7eb2Smrg     a = Variant(0);
1593*627f7eb2Smrg     assert(!a.coerce!bool);
1594*627f7eb2Smrg 
1595*627f7eb2Smrg     a = Variant(1.0);
1596*627f7eb2Smrg     assert(a.coerce!bool);
1597*627f7eb2Smrg     a = Variant(0.0);
1598*627f7eb2Smrg     assert(!a.coerce!bool);
1599*627f7eb2Smrg     a = Variant(float.init);
1600*627f7eb2Smrg     assertThrown!ConvException(a.coerce!bool);
1601*627f7eb2Smrg 
1602*627f7eb2Smrg     a = Variant("true");
1603*627f7eb2Smrg     assert(a.coerce!bool);
1604*627f7eb2Smrg     a = Variant("false");
1605*627f7eb2Smrg     assert(!a.coerce!bool);
1606*627f7eb2Smrg     a = Variant("");
1607*627f7eb2Smrg     assertThrown!ConvException(a.coerce!bool);
1608*627f7eb2Smrg 
1609*627f7eb2Smrg     // Object tests
1610*627f7eb2Smrg     class B1 {}
1611*627f7eb2Smrg     class B2 : B1 {}
1612*627f7eb2Smrg     a = new B2;
1613*627f7eb2Smrg     assert(a.coerce!(B1) !is null);
1614*627f7eb2Smrg     a = new B1;
1615*627f7eb2Smrg     assert(collectException(a.coerce!(B2) is null));
1616*627f7eb2Smrg     a = cast(Object) new B2; // lose static type info; should still work
1617*627f7eb2Smrg     assert(a.coerce!(B2) !is null);
1618*627f7eb2Smrg 
1619*627f7eb2Smrg //     struct Big { int a[45]; }
1620*627f7eb2Smrg //     a = Big.init;
1621*627f7eb2Smrg 
1622*627f7eb2Smrg     // hash
1623*627f7eb2Smrg     assert(a.toHash() != 0);
1624*627f7eb2Smrg }
1625*627f7eb2Smrg 
1626*627f7eb2Smrg // tests adapted from
1627*627f7eb2Smrg // http://www.dsource.org/projects/tango/browser/trunk/tango/core/Variant.d?rev=2601
1628*627f7eb2Smrg @system unittest
1629*627f7eb2Smrg {
1630*627f7eb2Smrg     Variant v;
1631*627f7eb2Smrg 
1632*627f7eb2Smrg     assert(!v.hasValue);
1633*627f7eb2Smrg     v = 42;
1634*627f7eb2Smrg     assert( v.peek!(int) );
1635*627f7eb2Smrg     assert( v.convertsTo!(long) );
1636*627f7eb2Smrg     assert( v.get!(int) == 42 );
1637*627f7eb2Smrg     assert( v.get!(long) == 42L );
1638*627f7eb2Smrg     assert( v.get!(ulong) == 42uL );
1639*627f7eb2Smrg 
1640*627f7eb2Smrg     v = "Hello, World!";
1641*627f7eb2Smrg     assert( v.peek!(string) );
1642*627f7eb2Smrg 
1643*627f7eb2Smrg     assert( v.get!(string) == "Hello, World!" );
1644*627f7eb2Smrg     assert(!is(char[] : wchar[]));
1645*627f7eb2Smrg     assert( !v.convertsTo!(wchar[]) );
1646*627f7eb2Smrg     assert( v.get!(string) == "Hello, World!" );
1647*627f7eb2Smrg 
1648*627f7eb2Smrg     // Literal arrays are dynamically-typed
1649*627f7eb2Smrg     v = cast(int[4]) [1,2,3,4];
1650*627f7eb2Smrg     assert( v.peek!(int[4]) );
1651*627f7eb2Smrg     assert( v.get!(int[4]) == [1,2,3,4] );
1652*627f7eb2Smrg 
1653*627f7eb2Smrg     {
1654*627f7eb2Smrg          v = [1,2,3,4,5];
1655*627f7eb2Smrg          assert( v.peek!(int[]) );
1656*627f7eb2Smrg          assert( v.get!(int[]) == [1,2,3,4,5] );
1657*627f7eb2Smrg     }
1658*627f7eb2Smrg 
1659*627f7eb2Smrg     v = 3.1413;
1660*627f7eb2Smrg     assert( v.peek!(double) );
1661*627f7eb2Smrg     assert( v.convertsTo!(real) );
1662*627f7eb2Smrg     //@@@ BUG IN COMPILER: DOUBLE SHOULD NOT IMPLICITLY CONVERT TO FLOAT
1663*627f7eb2Smrg     assert( !v.convertsTo!(float) );
1664*627f7eb2Smrg     assert( *v.peek!(double) == 3.1413 );
1665*627f7eb2Smrg 
1666*627f7eb2Smrg     auto u = Variant(v);
1667*627f7eb2Smrg     assert( u.peek!(double) );
1668*627f7eb2Smrg     assert( *u.peek!(double) == 3.1413 );
1669*627f7eb2Smrg 
1670*627f7eb2Smrg     // operators
1671*627f7eb2Smrg     v = 38;
1672*627f7eb2Smrg     assert( v + 4 == 42 );
1673*627f7eb2Smrg     assert( 4 + v == 42 );
1674*627f7eb2Smrg     assert( v - 4 == 34 );
1675*627f7eb2Smrg     assert( Variant(4) - v == -34 );
1676*627f7eb2Smrg     assert( v * 2 == 76 );
1677*627f7eb2Smrg     assert( 2 * v == 76 );
1678*627f7eb2Smrg     assert( v / 2 == 19 );
1679*627f7eb2Smrg     assert( Variant(2) / v == 0 );
1680*627f7eb2Smrg     assert( v % 2 == 0 );
1681*627f7eb2Smrg     assert( Variant(2) % v == 2 );
1682*627f7eb2Smrg     assert( (v & 6) == 6 );
1683*627f7eb2Smrg     assert( (6 & v) == 6 );
1684*627f7eb2Smrg     assert( (v | 9) == 47 );
1685*627f7eb2Smrg     assert( (9 | v) == 47 );
1686*627f7eb2Smrg     assert( (v ^ 5) == 35 );
1687*627f7eb2Smrg     assert( (5 ^ v) == 35 );
1688*627f7eb2Smrg     assert( v << 1 == 76 );
1689*627f7eb2Smrg     assert( Variant(1) << Variant(2) == 4 );
1690*627f7eb2Smrg     assert( v >> 1 == 19 );
1691*627f7eb2Smrg     assert( Variant(4) >> Variant(2) == 1 );
1692*627f7eb2Smrg     assert( Variant("abc") ~ "def" == "abcdef" );
1693*627f7eb2Smrg     assert( Variant("abc") ~ Variant("def") == "abcdef" );
1694*627f7eb2Smrg 
1695*627f7eb2Smrg     v = 38;
1696*627f7eb2Smrg     v += 4;
1697*627f7eb2Smrg     assert( v == 42 );
1698*627f7eb2Smrg     v = 38; v -= 4; assert( v == 34 );
1699*627f7eb2Smrg     v = 38; v *= 2; assert( v == 76 );
1700*627f7eb2Smrg     v = 38; v /= 2; assert( v == 19 );
1701*627f7eb2Smrg     v = 38; v %= 2; assert( v == 0 );
1702*627f7eb2Smrg     v = 38; v &= 6; assert( v == 6 );
1703*627f7eb2Smrg     v = 38; v |= 9; assert( v == 47 );
1704*627f7eb2Smrg     v = 38; v ^= 5; assert( v == 35 );
1705*627f7eb2Smrg     v = 38; v <<= 1; assert( v == 76 );
1706*627f7eb2Smrg     v = 38; v >>= 1; assert( v == 19 );
1707*627f7eb2Smrg     v = 38; v += 1;  assert( v < 40 );
1708*627f7eb2Smrg 
1709*627f7eb2Smrg     v = "abc";
1710*627f7eb2Smrg     v ~= "def";
1711*627f7eb2Smrg     assert( v == "abcdef", *v.peek!(char[]) );
1712*627f7eb2Smrg     assert( Variant(0) < Variant(42) );
1713*627f7eb2Smrg     assert( Variant(42) > Variant(0) );
1714*627f7eb2Smrg     assert( Variant(42) > Variant(0.1) );
1715*627f7eb2Smrg     assert( Variant(42.1) > Variant(1) );
1716*627f7eb2Smrg     assert( Variant(21) == Variant(21) );
1717*627f7eb2Smrg     assert( Variant(0) != Variant(42) );
1718*627f7eb2Smrg     assert( Variant("bar") == Variant("bar") );
1719*627f7eb2Smrg     assert( Variant("foo") != Variant("bar") );
1720*627f7eb2Smrg 
1721*627f7eb2Smrg     {
1722*627f7eb2Smrg         auto v1 = Variant(42);
1723*627f7eb2Smrg         auto v2 = Variant("foo");
1724*627f7eb2Smrg         auto v3 = Variant(1+2.0i);
1725*627f7eb2Smrg 
1726*627f7eb2Smrg         int[Variant] hash;
1727*627f7eb2Smrg         hash[v1] = 0;
1728*627f7eb2Smrg         hash[v2] = 1;
1729*627f7eb2Smrg         hash[v3] = 2;
1730*627f7eb2Smrg 
1731*627f7eb2Smrg         assert( hash[v1] == 0 );
1732*627f7eb2Smrg         assert( hash[v2] == 1 );
1733*627f7eb2Smrg         assert( hash[v3] == 2 );
1734*627f7eb2Smrg     }
1735*627f7eb2Smrg 
1736*627f7eb2Smrg     {
1737*627f7eb2Smrg         int[char[]] hash;
1738*627f7eb2Smrg         hash["a"] = 1;
1739*627f7eb2Smrg         hash["b"] = 2;
1740*627f7eb2Smrg         hash["c"] = 3;
1741*627f7eb2Smrg         Variant vhash = hash;
1742*627f7eb2Smrg 
1743*627f7eb2Smrg         assert( vhash.get!(int[char[]])["a"] == 1 );
1744*627f7eb2Smrg         assert( vhash.get!(int[char[]])["b"] == 2 );
1745*627f7eb2Smrg         assert( vhash.get!(int[char[]])["c"] == 3 );
1746*627f7eb2Smrg     }
1747*627f7eb2Smrg }
1748*627f7eb2Smrg 
1749*627f7eb2Smrg @system unittest
1750*627f7eb2Smrg {
1751*627f7eb2Smrg     // check comparisons incompatible with AllowedTypes
1752*627f7eb2Smrg     Algebraic!int v = 2;
1753*627f7eb2Smrg 
1754*627f7eb2Smrg     assert(v == 2);
1755*627f7eb2Smrg     assert(v < 3);
1756*627f7eb2Smrg     static assert(!__traits(compiles, {v == long.max;}));
1757*627f7eb2Smrg     static assert(!__traits(compiles, {v == null;}));
1758*627f7eb2Smrg     static assert(!__traits(compiles, {v < long.max;}));
1759*627f7eb2Smrg     static assert(!__traits(compiles, {v > null;}));
1760*627f7eb2Smrg }
1761*627f7eb2Smrg 
1762*627f7eb2Smrg @system unittest
1763*627f7eb2Smrg {
1764*627f7eb2Smrg     // bug 1558
1765*627f7eb2Smrg     Variant va=1;
1766*627f7eb2Smrg     Variant vb=-2;
1767*627f7eb2Smrg     assert((va+vb).get!(int) == -1);
1768*627f7eb2Smrg     assert((va-vb).get!(int) == 3);
1769*627f7eb2Smrg }
1770*627f7eb2Smrg 
1771*627f7eb2Smrg @system unittest
1772*627f7eb2Smrg {
1773*627f7eb2Smrg     Variant a;
1774*627f7eb2Smrg     a=5;
1775*627f7eb2Smrg     Variant b;
1776*627f7eb2Smrg     b=a;
1777*627f7eb2Smrg     Variant[] c;
1778*627f7eb2Smrg     c = variantArray(1, 2, 3.0, "hello", 4);
1779*627f7eb2Smrg     assert(c[3] == "hello");
1780*627f7eb2Smrg }
1781*627f7eb2Smrg 
1782*627f7eb2Smrg @system unittest
1783*627f7eb2Smrg {
1784*627f7eb2Smrg     Variant v = 5;
1785*627f7eb2Smrg     assert(!__traits(compiles, v.coerce!(bool delegate())));
1786*627f7eb2Smrg }
1787*627f7eb2Smrg 
1788*627f7eb2Smrg 
1789*627f7eb2Smrg @system unittest
1790*627f7eb2Smrg {
1791*627f7eb2Smrg     struct Huge {
1792*627f7eb2Smrg         real a, b, c, d, e, f, g;
1793*627f7eb2Smrg     }
1794*627f7eb2Smrg 
1795*627f7eb2Smrg     Huge huge;
1796*627f7eb2Smrg     huge.e = 42;
1797*627f7eb2Smrg     Variant v;
1798*627f7eb2Smrg     v = huge;  // Compile time error.
1799*627f7eb2Smrg     assert(v.get!(Huge).e == 42);
1800*627f7eb2Smrg }
1801*627f7eb2Smrg 
1802*627f7eb2Smrg @system unittest
1803*627f7eb2Smrg {
1804*627f7eb2Smrg     const x = Variant(42);
1805*627f7eb2Smrg     auto y1 = x.get!(const int);
1806*627f7eb2Smrg     // @@@BUG@@@
1807*627f7eb2Smrg     //auto y2 = x.get!(immutable int)();
1808*627f7eb2Smrg }
1809*627f7eb2Smrg 
1810*627f7eb2Smrg // test iteration
1811*627f7eb2Smrg @system unittest
1812*627f7eb2Smrg {
1813*627f7eb2Smrg     auto v = Variant([ 1, 2, 3, 4 ][]);
1814*627f7eb2Smrg     auto j = 0;
foreach(int i;v)1815*627f7eb2Smrg     foreach (int i; v)
1816*627f7eb2Smrg     {
1817*627f7eb2Smrg         assert(i == ++j);
1818*627f7eb2Smrg     }
1819*627f7eb2Smrg     assert(j == 4);
1820*627f7eb2Smrg }
1821*627f7eb2Smrg 
1822*627f7eb2Smrg // test convertibility
1823*627f7eb2Smrg @system unittest
1824*627f7eb2Smrg {
1825*627f7eb2Smrg     auto v = Variant("abc".dup);
1826*627f7eb2Smrg     assert(v.convertsTo!(char[]));
1827*627f7eb2Smrg }
1828*627f7eb2Smrg 
1829*627f7eb2Smrg // http://d.puremagic.com/issues/show_bug.cgi?id=5424
1830*627f7eb2Smrg @system unittest
1831*627f7eb2Smrg {
1832*627f7eb2Smrg     interface A {
1833*627f7eb2Smrg         void func1();
1834*627f7eb2Smrg     }
1835*627f7eb2Smrg     static class AC: A {
func1()1836*627f7eb2Smrg         void func1() {
1837*627f7eb2Smrg         }
1838*627f7eb2Smrg     }
1839*627f7eb2Smrg 
1840*627f7eb2Smrg     A a = new AC();
1841*627f7eb2Smrg     a.func1();
1842*627f7eb2Smrg     Variant b = Variant(a);
1843*627f7eb2Smrg }
1844*627f7eb2Smrg 
1845*627f7eb2Smrg @system unittest
1846*627f7eb2Smrg {
1847*627f7eb2Smrg     // bug 7070
1848*627f7eb2Smrg     Variant v;
1849*627f7eb2Smrg     v = null;
1850*627f7eb2Smrg }
1851*627f7eb2Smrg 
1852*627f7eb2Smrg // Class and interface opEquals, issue 12157
1853*627f7eb2Smrg @system unittest
1854*627f7eb2Smrg {
1855*627f7eb2Smrg     class Foo { }
1856*627f7eb2Smrg 
1857*627f7eb2Smrg     class DerivedFoo : Foo { }
1858*627f7eb2Smrg 
1859*627f7eb2Smrg     Foo f1 = new Foo();
1860*627f7eb2Smrg     Foo f2 = new DerivedFoo();
1861*627f7eb2Smrg 
1862*627f7eb2Smrg     Variant v1 = f1, v2 = f2;
1863*627f7eb2Smrg     assert(v1 == f1);
1864*627f7eb2Smrg     assert(v1 != new Foo());
1865*627f7eb2Smrg     assert(v1 != f2);
1866*627f7eb2Smrg     assert(v2 != v1);
1867*627f7eb2Smrg     assert(v2 == f2);
1868*627f7eb2Smrg }
1869*627f7eb2Smrg 
1870*627f7eb2Smrg // Const parameters with opCall, issue 11361.
1871*627f7eb2Smrg @system unittest
1872*627f7eb2Smrg {
t1(string c)1873*627f7eb2Smrg     static string t1(string c) {
1874*627f7eb2Smrg         return c ~ "a";
1875*627f7eb2Smrg     }
1876*627f7eb2Smrg 
t2(const (char)[]p)1877*627f7eb2Smrg     static const(char)[] t2(const(char)[] p) {
1878*627f7eb2Smrg         return p ~ "b";
1879*627f7eb2Smrg     }
1880*627f7eb2Smrg 
t3(int p)1881*627f7eb2Smrg     static char[] t3(int p) {
1882*627f7eb2Smrg         import std.conv : text;
1883*627f7eb2Smrg         return p.text.dup;
1884*627f7eb2Smrg     }
1885*627f7eb2Smrg 
1886*627f7eb2Smrg     Variant v1 = &t1;
1887*627f7eb2Smrg     Variant v2 = &t2;
1888*627f7eb2Smrg     Variant v3 = &t3;
1889*627f7eb2Smrg 
1890*627f7eb2Smrg     assert(v1("abc") == "abca");
1891*627f7eb2Smrg     assert(v1("abc").type == typeid(string));
1892*627f7eb2Smrg     assert(v2("abc") == "abcb");
1893*627f7eb2Smrg 
1894*627f7eb2Smrg     assert(v2(cast(char[])("abc".dup)) == "abcb");
1895*627f7eb2Smrg     assert(v2("abc").type == typeid(const(char)[]));
1896*627f7eb2Smrg 
1897*627f7eb2Smrg     assert(v3(4) == ['4']);
1898*627f7eb2Smrg     assert(v3(4).type == typeid(char[]));
1899*627f7eb2Smrg }
1900*627f7eb2Smrg 
1901*627f7eb2Smrg // issue 12071
1902*627f7eb2Smrg @system unittest
1903*627f7eb2Smrg {
1904*627f7eb2Smrg     static struct Structure { int data; }
1905*627f7eb2Smrg     alias VariantTest = Algebraic!(Structure delegate() pure nothrow @nogc @safe);
1906*627f7eb2Smrg 
1907*627f7eb2Smrg     bool called = false;
example()1908*627f7eb2Smrg     Structure example() pure nothrow @nogc @safe
1909*627f7eb2Smrg     {
1910*627f7eb2Smrg         called = true;
1911*627f7eb2Smrg         return Structure.init;
1912*627f7eb2Smrg     }
1913*627f7eb2Smrg     auto m = VariantTest(&example);
1914*627f7eb2Smrg     m();
1915*627f7eb2Smrg     assert(called);
1916*627f7eb2Smrg }
1917*627f7eb2Smrg 
1918*627f7eb2Smrg // Ordering comparisons of incompatible types, e.g. issue 7990.
1919*627f7eb2Smrg @system unittest
1920*627f7eb2Smrg {
1921*627f7eb2Smrg     import std.exception : assertThrown;
1922*627f7eb2Smrg     assertThrown!VariantException(Variant(3) < "a");
1923*627f7eb2Smrg     assertThrown!VariantException("a" < Variant(3));
1924*627f7eb2Smrg     assertThrown!VariantException(Variant(3) < Variant("a"));
1925*627f7eb2Smrg 
1926*627f7eb2Smrg     assertThrown!VariantException(Variant.init < Variant(3));
1927*627f7eb2Smrg     assertThrown!VariantException(Variant(3) < Variant.init);
1928*627f7eb2Smrg }
1929*627f7eb2Smrg 
1930*627f7eb2Smrg // Handling of unordered types, e.g. issue 9043.
1931*627f7eb2Smrg @system unittest
1932*627f7eb2Smrg {
1933*627f7eb2Smrg     import std.exception : assertThrown;
1934*627f7eb2Smrg     static struct A { int a; }
1935*627f7eb2Smrg 
1936*627f7eb2Smrg     assert(Variant(A(3)) != A(4));
1937*627f7eb2Smrg 
1938*627f7eb2Smrg     assertThrown!VariantException(Variant(A(3)) < A(4));
1939*627f7eb2Smrg     assertThrown!VariantException(A(3) < Variant(A(4)));
1940*627f7eb2Smrg     assertThrown!VariantException(Variant(A(3)) < Variant(A(4)));
1941*627f7eb2Smrg }
1942*627f7eb2Smrg 
1943*627f7eb2Smrg // Handling of empty types and arrays, e.g. issue 10958
1944*627f7eb2Smrg @system unittest
1945*627f7eb2Smrg {
1946*627f7eb2Smrg     class EmptyClass { }
1947*627f7eb2Smrg     struct EmptyStruct { }
1948*627f7eb2Smrg     alias EmptyArray = void[0];
1949*627f7eb2Smrg     alias Alg = Algebraic!(EmptyClass, EmptyStruct, EmptyArray);
1950*627f7eb2Smrg 
testEmpty(T)1951*627f7eb2Smrg     Variant testEmpty(T)()
1952*627f7eb2Smrg     {
1953*627f7eb2Smrg         T inst;
1954*627f7eb2Smrg         Variant v = inst;
1955*627f7eb2Smrg         assert(v.get!T == inst);
1956*627f7eb2Smrg         assert(v.peek!T !is null);
1957*627f7eb2Smrg         assert(*v.peek!T == inst);
1958*627f7eb2Smrg         Alg alg = inst;
1959*627f7eb2Smrg         assert(alg.get!T == inst);
1960*627f7eb2Smrg         return v;
1961*627f7eb2Smrg     }
1962*627f7eb2Smrg 
1963*627f7eb2Smrg     testEmpty!EmptyClass();
1964*627f7eb2Smrg     testEmpty!EmptyStruct();
1965*627f7eb2Smrg     testEmpty!EmptyArray();
1966*627f7eb2Smrg 
1967*627f7eb2Smrg     // EmptyClass/EmptyStruct sizeof is 1, so we have this to test just size 0.
1968*627f7eb2Smrg     EmptyArray arr = EmptyArray.init;
1969*627f7eb2Smrg     Algebraic!(EmptyArray) a = arr;
1970*627f7eb2Smrg     assert(a.length == 0);
1971*627f7eb2Smrg     assert(a.get!EmptyArray == arr);
1972*627f7eb2Smrg }
1973*627f7eb2Smrg 
1974*627f7eb2Smrg // Handling of void function pointers / delegates, e.g. issue 11360
1975*627f7eb2Smrg @system unittest
1976*627f7eb2Smrg {
t1()1977*627f7eb2Smrg     static void t1() { }
1978*627f7eb2Smrg     Variant v = &t1;
1979*627f7eb2Smrg     assert(v() == Variant.init);
1980*627f7eb2Smrg 
t2()1981*627f7eb2Smrg     static int t2() { return 3; }
1982*627f7eb2Smrg     Variant v2 = &t2;
1983*627f7eb2Smrg     assert(v2() == 3);
1984*627f7eb2Smrg }
1985*627f7eb2Smrg 
1986*627f7eb2Smrg // Using peek for large structs, issue 8580
1987*627f7eb2Smrg @system unittest
1988*627f7eb2Smrg {
TestStruct(bool pad)1989*627f7eb2Smrg     struct TestStruct(bool pad)
1990*627f7eb2Smrg     {
1991*627f7eb2Smrg         int val1;
1992*627f7eb2Smrg         static if (pad)
1993*627f7eb2Smrg             ubyte[Variant.size] padding;
1994*627f7eb2Smrg         int val2;
1995*627f7eb2Smrg     }
1996*627f7eb2Smrg 
testPeekWith(T)1997*627f7eb2Smrg     void testPeekWith(T)()
1998*627f7eb2Smrg     {
1999*627f7eb2Smrg         T inst;
2000*627f7eb2Smrg         inst.val1 = 3;
2001*627f7eb2Smrg         inst.val2 = 4;
2002*627f7eb2Smrg         Variant v = inst;
2003*627f7eb2Smrg         T* original = v.peek!T;
2004*627f7eb2Smrg         assert(original.val1 == 3);
2005*627f7eb2Smrg         assert(original.val2 == 4);
2006*627f7eb2Smrg         original.val1 = 6;
2007*627f7eb2Smrg         original.val2 = 8;
2008*627f7eb2Smrg         T modified = v.get!T;
2009*627f7eb2Smrg         assert(modified.val1 == 6);
2010*627f7eb2Smrg         assert(modified.val2 == 8);
2011*627f7eb2Smrg     }
2012*627f7eb2Smrg 
2013*627f7eb2Smrg     testPeekWith!(TestStruct!false)();
2014*627f7eb2Smrg     testPeekWith!(TestStruct!true)();
2015*627f7eb2Smrg }
2016*627f7eb2Smrg 
2017*627f7eb2Smrg /**
2018*627f7eb2Smrg  * Applies a delegate or function to the given $(LREF Algebraic) depending on the held type,
2019*627f7eb2Smrg  * ensuring that all types are handled by the visiting functions.
2020*627f7eb2Smrg  *
2021*627f7eb2Smrg  * The delegate or function having the currently held value as parameter is called
2022*627f7eb2Smrg  * with $(D variant)'s current value. Visiting handlers are passed
2023*627f7eb2Smrg  * in the template parameter list.
2024*627f7eb2Smrg  * It is statically ensured that all held types of
2025*627f7eb2Smrg  * $(D variant) are handled across all handlers.
2026*627f7eb2Smrg  * $(D visit) allows delegates and static functions to be passed
2027*627f7eb2Smrg  * as parameters.
2028*627f7eb2Smrg  *
2029*627f7eb2Smrg  * If a function with an untyped parameter is specified, this function is called
2030*627f7eb2Smrg  * when the variant contains a type that does not match any other function.
2031*627f7eb2Smrg  * This can be used to apply the same function across multiple possible types.
2032*627f7eb2Smrg  * Exactly one generic function is allowed.
2033*627f7eb2Smrg  *
2034*627f7eb2Smrg  * If a function without parameters is specified, this function is called
2035*627f7eb2Smrg  * when `variant` doesn't hold a value. Exactly one parameter-less function
2036*627f7eb2Smrg  * is allowed.
2037*627f7eb2Smrg  *
2038*627f7eb2Smrg  * Duplicate overloads matching the same type in one of the visitors are disallowed.
2039*627f7eb2Smrg  *
2040*627f7eb2Smrg  * Returns: The return type of visit is deduced from the visiting functions and must be
2041*627f7eb2Smrg  * the same across all overloads.
2042*627f7eb2Smrg  * Throws: $(LREF VariantException) if `variant` doesn't hold a value and no
2043*627f7eb2Smrg  * parameter-less fallback function is specified.
2044*627f7eb2Smrg  */
2045*627f7eb2Smrg template visit(Handlers...)
2046*627f7eb2Smrg if (Handlers.length > 0)
2047*627f7eb2Smrg {
2048*627f7eb2Smrg     ///
2049*627f7eb2Smrg     auto visit(VariantType)(VariantType variant)
2050*627f7eb2Smrg         if (isAlgebraic!VariantType)
2051*627f7eb2Smrg     {
2052*627f7eb2Smrg         return visitImpl!(true, VariantType, Handlers)(variant);
2053*627f7eb2Smrg     }
2054*627f7eb2Smrg }
2055*627f7eb2Smrg 
2056*627f7eb2Smrg ///
2057*627f7eb2Smrg @system unittest
2058*627f7eb2Smrg {
2059*627f7eb2Smrg     Algebraic!(int, string) variant;
2060*627f7eb2Smrg 
2061*627f7eb2Smrg     variant = 10;
2062*627f7eb2Smrg     assert(variant.visit!((string s) => cast(int) s.length,
2063*627f7eb2Smrg                           (int i)    => i)()
2064*627f7eb2Smrg                           == 10);
2065*627f7eb2Smrg     variant = "string";
2066*627f7eb2Smrg     assert(variant.visit!((int i) => i,
2067*627f7eb2Smrg                           (string s) => cast(int) s.length)()
2068*627f7eb2Smrg                           == 6);
2069*627f7eb2Smrg 
2070*627f7eb2Smrg     // Error function usage
2071*627f7eb2Smrg     Algebraic!(int, string) emptyVar;
2072*627f7eb2Smrg     auto rslt = emptyVar.visit!((string s) => cast(int) s.length,
2073*627f7eb2Smrg                           (int i)    => i,
2074*627f7eb2Smrg                           () => -1)();
2075*627f7eb2Smrg     assert(rslt == -1);
2076*627f7eb2Smrg 
2077*627f7eb2Smrg     // Generic function usage
2078*627f7eb2Smrg     Algebraic!(int, float, real) number = 2;
2079*627f7eb2Smrg     assert(number.visit!(x => x += 1) == 3);
2080*627f7eb2Smrg 
2081*627f7eb2Smrg     // Generic function for int/float with separate behavior for string
2082*627f7eb2Smrg     Algebraic!(int, float, string) something = 2;
2083*627f7eb2Smrg     assert(something.visit!((string s) => s.length, x => x) == 2); // generic
2084*627f7eb2Smrg     something = "asdf";
2085*627f7eb2Smrg     assert(something.visit!((string s) => s.length, x => x) == 4); // string
2086*627f7eb2Smrg 
2087*627f7eb2Smrg     // Generic handler and empty handler
2088*627f7eb2Smrg     Algebraic!(int, float, real) empty2;
2089*627f7eb2Smrg     assert(empty2.visit!(x => x + 1, () => -1) == -1);
2090*627f7eb2Smrg }
2091*627f7eb2Smrg 
2092*627f7eb2Smrg @system unittest
2093*627f7eb2Smrg {
2094*627f7eb2Smrg     Algebraic!(size_t, string) variant;
2095*627f7eb2Smrg 
2096*627f7eb2Smrg     // not all handled check
2097*627f7eb2Smrg     static assert(!__traits(compiles, variant.visit!((size_t i){ })() ));
2098*627f7eb2Smrg 
2099*627f7eb2Smrg     variant = cast(size_t) 10;
2100*627f7eb2Smrg     auto which = 0;
2101*627f7eb2Smrg     variant.visit!( (string s) => which = 1,
2102*627f7eb2Smrg                     (size_t i) => which = 0
2103*627f7eb2Smrg                     )();
2104*627f7eb2Smrg 
2105*627f7eb2Smrg     // integer overload was called
2106*627f7eb2Smrg     assert(which == 0);
2107*627f7eb2Smrg 
2108*627f7eb2Smrg     // mustn't compile as generic Variant not supported
2109*627f7eb2Smrg     Variant v;
2110*627f7eb2Smrg     static assert(!__traits(compiles, v.visit!((string s) => which = 1,
2111*627f7eb2Smrg                                                (size_t i) => which = 0
2112*627f7eb2Smrg                                                 )()
2113*627f7eb2Smrg                                                 ));
2114*627f7eb2Smrg 
func(string s)2115*627f7eb2Smrg     static size_t func(string s) {
2116*627f7eb2Smrg         return s.length;
2117*627f7eb2Smrg     }
2118*627f7eb2Smrg 
2119*627f7eb2Smrg     variant = "test";
2120*627f7eb2Smrg     assert( 4 == variant.visit!(func,
2121*627f7eb2Smrg                                 (size_t i) => i
2122*627f7eb2Smrg                                 )());
2123*627f7eb2Smrg 
2124*627f7eb2Smrg     Algebraic!(int, float, string) variant2 = 5.0f;
2125*627f7eb2Smrg     // Shouldn' t compile as float not handled by visitor.
2126*627f7eb2Smrg     static assert(!__traits(compiles, variant2.visit!(
2127*627f7eb2Smrg                         (int _) {},
2128*627f7eb2Smrg                         (string _) {})()));
2129*627f7eb2Smrg 
2130*627f7eb2Smrg     Algebraic!(size_t, string, float) variant3;
2131*627f7eb2Smrg     variant3 = 10.0f;
2132*627f7eb2Smrg     auto floatVisited = false;
2133*627f7eb2Smrg 
2134*627f7eb2Smrg     assert(variant3.visit!(
2135*627f7eb2Smrg                  (float f) { floatVisited = true; return cast(size_t) f; },
2136*627f7eb2Smrg                  func,
2137*627f7eb2Smrg                  (size_t i) { return i; }
2138*627f7eb2Smrg                  )() == 10);
2139*627f7eb2Smrg     assert(floatVisited == true);
2140*627f7eb2Smrg 
2141*627f7eb2Smrg     Algebraic!(float, string) variant4;
2142*627f7eb2Smrg 
2143*627f7eb2Smrg     assert(variant4.visit!(func, (float f) => cast(size_t) f, () => size_t.max)() == size_t.max);
2144*627f7eb2Smrg 
2145*627f7eb2Smrg     // double error func check
2146*627f7eb2Smrg     static assert(!__traits(compiles,
2147*627f7eb2Smrg                             visit!(() => size_t.max, func, (float f) => cast(size_t) f, () => size_t.max)(variant4))
2148*627f7eb2Smrg                  );
2149*627f7eb2Smrg }
2150*627f7eb2Smrg 
2151*627f7eb2Smrg // disallow providing multiple generic handlers to visit
2152*627f7eb2Smrg // disallow a generic handler that does not apply to all types
2153*627f7eb2Smrg @system unittest
2154*627f7eb2Smrg {
2155*627f7eb2Smrg     Algebraic!(int, float) number = 2;
2156*627f7eb2Smrg     // ok, x + 1 valid for int and float
2157*627f7eb2Smrg     static assert( __traits(compiles, number.visit!(x => x + 1)));
2158*627f7eb2Smrg     // bad, two generic handlers
2159*627f7eb2Smrg     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x + 2)));
2160*627f7eb2Smrg     // bad, x ~ "a" does not apply to int or float
2161*627f7eb2Smrg     static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2162*627f7eb2Smrg     // bad, x ~ "a" does not apply to int or float
2163*627f7eb2Smrg     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2164*627f7eb2Smrg 
2165*627f7eb2Smrg     Algebraic!(int, string) maybenumber = 2;
2166*627f7eb2Smrg     // ok, x ~ "a" valid for string, x + 1 valid for int, only 1 generic
2167*627f7eb2Smrg     static assert( __traits(compiles, number.visit!((string x) => x ~ "a", x => x + 1)));
2168*627f7eb2Smrg     // bad, x ~ "a" valid for string but not int
2169*627f7eb2Smrg     static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2170*627f7eb2Smrg     // bad, two generics, each only applies in one case
2171*627f7eb2Smrg     static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2172*627f7eb2Smrg }
2173*627f7eb2Smrg 
2174*627f7eb2Smrg /**
2175*627f7eb2Smrg  * Behaves as $(LREF visit) but doesn't enforce that all types are handled
2176*627f7eb2Smrg  * by the visiting functions.
2177*627f7eb2Smrg  *
2178*627f7eb2Smrg  * If a parameter-less function is specified it is called when
2179*627f7eb2Smrg  * either $(D variant) doesn't hold a value or holds a type
2180*627f7eb2Smrg  * which isn't handled by the visiting functions.
2181*627f7eb2Smrg  *
2182*627f7eb2Smrg  * Returns: The return type of tryVisit is deduced from the visiting functions and must be
2183*627f7eb2Smrg  * the same across all overloads.
2184*627f7eb2Smrg  * Throws: $(LREF VariantException) if `variant` doesn't hold a value or
2185*627f7eb2Smrg  * `variant` holds a value which isn't handled by the visiting functions,
2186*627f7eb2Smrg  * when no parameter-less fallback function is specified.
2187*627f7eb2Smrg  */
2188*627f7eb2Smrg template tryVisit(Handlers...)
2189*627f7eb2Smrg if (Handlers.length > 0)
2190*627f7eb2Smrg {
2191*627f7eb2Smrg     ///
2192*627f7eb2Smrg     auto tryVisit(VariantType)(VariantType variant)
2193*627f7eb2Smrg         if (isAlgebraic!VariantType)
2194*627f7eb2Smrg     {
2195*627f7eb2Smrg         return visitImpl!(false, VariantType, Handlers)(variant);
2196*627f7eb2Smrg     }
2197*627f7eb2Smrg }
2198*627f7eb2Smrg 
2199*627f7eb2Smrg ///
2200*627f7eb2Smrg @system unittest
2201*627f7eb2Smrg {
2202*627f7eb2Smrg     Algebraic!(int, string) variant;
2203*627f7eb2Smrg 
2204*627f7eb2Smrg     variant = 10;
2205*627f7eb2Smrg     auto which = -1;
2206*627f7eb2Smrg     variant.tryVisit!((int i) { which = 0; })();
2207*627f7eb2Smrg     assert(which == 0);
2208*627f7eb2Smrg 
2209*627f7eb2Smrg     // Error function usage
2210*627f7eb2Smrg     variant = "test";
2211*627f7eb2Smrg     variant.tryVisit!((int i) { which = 0; },
2212*627f7eb2Smrg                       ()      { which = -100; })();
2213*627f7eb2Smrg     assert(which == -100);
2214*627f7eb2Smrg }
2215*627f7eb2Smrg 
2216*627f7eb2Smrg @system unittest
2217*627f7eb2Smrg {
2218*627f7eb2Smrg     import std.exception : assertThrown;
2219*627f7eb2Smrg     Algebraic!(int, string) variant;
2220*627f7eb2Smrg 
2221*627f7eb2Smrg     variant = 10;
2222*627f7eb2Smrg     auto which = -1;
2223*627f7eb2Smrg     variant.tryVisit!((int i){ which = 0; })();
2224*627f7eb2Smrg 
2225*627f7eb2Smrg     assert(which == 0);
2226*627f7eb2Smrg 
2227*627f7eb2Smrg     variant = "test";
2228*627f7eb2Smrg 
2229*627f7eb2Smrg     assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })());
2230*627f7eb2Smrg 
errorfunc()2231*627f7eb2Smrg     void errorfunc()
2232*627f7eb2Smrg     {
2233*627f7eb2Smrg         which = -1;
2234*627f7eb2Smrg     }
2235*627f7eb2Smrg 
2236*627f7eb2Smrg     variant.tryVisit!((int i) { which = 0; }, errorfunc)();
2237*627f7eb2Smrg 
2238*627f7eb2Smrg     assert(which == -1);
2239*627f7eb2Smrg }
2240*627f7eb2Smrg 
isAlgebraic(Type)2241*627f7eb2Smrg private template isAlgebraic(Type)
2242*627f7eb2Smrg {
2243*627f7eb2Smrg     static if (is(Type _ == VariantN!T, T...))
2244*627f7eb2Smrg         enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam
2245*627f7eb2Smrg     else
2246*627f7eb2Smrg         enum isAlgebraic = false;
2247*627f7eb2Smrg }
2248*627f7eb2Smrg 
2249*627f7eb2Smrg @system unittest
2250*627f7eb2Smrg {
2251*627f7eb2Smrg     static assert(!isAlgebraic!(Variant));
2252*627f7eb2Smrg     static assert( isAlgebraic!(Algebraic!(string)));
2253*627f7eb2Smrg     static assert( isAlgebraic!(Algebraic!(int, int[])));
2254*627f7eb2Smrg }
2255*627f7eb2Smrg 
2256*627f7eb2Smrg private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2257*627f7eb2Smrg if (isAlgebraic!VariantType && Handler.length > 0)
2258*627f7eb2Smrg {
2259*627f7eb2Smrg     alias AllowedTypes = VariantType.AllowedTypes;
2260*627f7eb2Smrg 
2261*627f7eb2Smrg 
2262*627f7eb2Smrg     /**
2263*627f7eb2Smrg      * Returns: Struct where $(D indices)  is an array which
2264*627f7eb2Smrg      * contains at the n-th position the index in Handler which takes the
2265*627f7eb2Smrg      * n-th type of AllowedTypes. If an Handler doesn't match an
2266*627f7eb2Smrg      * AllowedType, -1 is set. If a function in the delegates doesn't
2267*627f7eb2Smrg      * have parameters, the field $(D exceptionFuncIdx) is set;
2268*627f7eb2Smrg      * otherwise it's -1.
2269*627f7eb2Smrg      */
visitGetOverloadMap()2270*627f7eb2Smrg     auto visitGetOverloadMap()
2271*627f7eb2Smrg     {
2272*627f7eb2Smrg         struct Result {
2273*627f7eb2Smrg             int[AllowedTypes.length] indices;
2274*627f7eb2Smrg             int exceptionFuncIdx = -1;
2275*627f7eb2Smrg             int generalFuncIdx = -1;
2276*627f7eb2Smrg         }
2277*627f7eb2Smrg 
2278*627f7eb2Smrg         Result result;
2279*627f7eb2Smrg 
2280*627f7eb2Smrg         foreach (tidx, T; AllowedTypes)
2281*627f7eb2Smrg         {
2282*627f7eb2Smrg             bool added = false;
2283*627f7eb2Smrg             foreach (dgidx, dg; Handler)
2284*627f7eb2Smrg             {
2285*627f7eb2Smrg                 // Handle normal function objects
2286*627f7eb2Smrg                 static if (isSomeFunction!dg)
2287*627f7eb2Smrg                 {
2288*627f7eb2Smrg                     alias Params = Parameters!dg;
2289*627f7eb2Smrg                     static if (Params.length == 0)
2290*627f7eb2Smrg                     {
2291*627f7eb2Smrg                         // Just check exception functions in the first
2292*627f7eb2Smrg                         // inner iteration (over delegates)
2293*627f7eb2Smrg                         if (tidx > 0)
2294*627f7eb2Smrg                             continue;
2295*627f7eb2Smrg                         else
2296*627f7eb2Smrg                         {
2297*627f7eb2Smrg                             if (result.exceptionFuncIdx != -1)
2298*627f7eb2Smrg                                 assert(false, "duplicate parameter-less (error-)function specified");
2299*627f7eb2Smrg                             result.exceptionFuncIdx = dgidx;
2300*627f7eb2Smrg                         }
2301*627f7eb2Smrg                     }
2302*627f7eb2Smrg                     else static if (is(Params[0] == T) || is(Unqual!(Params[0]) == T))
2303*627f7eb2Smrg                     {
2304*627f7eb2Smrg                         if (added)
2305*627f7eb2Smrg                             assert(false, "duplicate overload specified for type '" ~ T.stringof ~ "'");
2306*627f7eb2Smrg 
2307*627f7eb2Smrg                         added = true;
2308*627f7eb2Smrg                         result.indices[tidx] = dgidx;
2309*627f7eb2Smrg                     }
2310*627f7eb2Smrg                 }
2311*627f7eb2Smrg                 else static if (isSomeFunction!(dg!T))
2312*627f7eb2Smrg                 {
2313*627f7eb2Smrg                     assert(result.generalFuncIdx == -1 ||
2314*627f7eb2Smrg                            result.generalFuncIdx == dgidx,
2315*627f7eb2Smrg                            "Only one generic visitor function is allowed");
2316*627f7eb2Smrg                     result.generalFuncIdx = dgidx;
2317*627f7eb2Smrg                 }
2318*627f7eb2Smrg                 // Handle composite visitors with opCall overloads
2319*627f7eb2Smrg                 else
2320*627f7eb2Smrg                 {
2321*627f7eb2Smrg                     static assert(false, dg.stringof ~ " is not a function or delegate");
2322*627f7eb2Smrg                 }
2323*627f7eb2Smrg             }
2324*627f7eb2Smrg 
2325*627f7eb2Smrg             if (!added)
2326*627f7eb2Smrg                 result.indices[tidx] = -1;
2327*627f7eb2Smrg         }
2328*627f7eb2Smrg 
2329*627f7eb2Smrg         return result;
2330*627f7eb2Smrg     }
2331*627f7eb2Smrg 
2332*627f7eb2Smrg     enum HandlerOverloadMap = visitGetOverloadMap();
2333*627f7eb2Smrg 
2334*627f7eb2Smrg     if (!variant.hasValue)
2335*627f7eb2Smrg     {
2336*627f7eb2Smrg         // Call the exception function. The HandlerOverloadMap
2337*627f7eb2Smrg         // will have its exceptionFuncIdx field set to value != -1 if an
2338*627f7eb2Smrg         // exception function has been specified; otherwise we just through an exception.
2339*627f7eb2Smrg         static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2340*627f7eb2Smrg             return Handler[ HandlerOverloadMap.exceptionFuncIdx ]();
2341*627f7eb2Smrg         else
2342*627f7eb2Smrg             throw new VariantException("variant must hold a value before being visited.");
2343*627f7eb2Smrg     }
2344*627f7eb2Smrg 
foreach(idx,T;AllowedTypes)2345*627f7eb2Smrg     foreach (idx, T; AllowedTypes)
2346*627f7eb2Smrg     {
2347*627f7eb2Smrg         if (auto ptr = variant.peek!T)
2348*627f7eb2Smrg         {
2349*627f7eb2Smrg             enum dgIdx = HandlerOverloadMap.indices[idx];
2350*627f7eb2Smrg 
2351*627f7eb2Smrg             static if (dgIdx == -1)
2352*627f7eb2Smrg             {
2353*627f7eb2Smrg                 static if (HandlerOverloadMap.generalFuncIdx >= 0)
2354*627f7eb2Smrg                     return Handler[HandlerOverloadMap.generalFuncIdx](*ptr);
2355*627f7eb2Smrg                 else static if (Strict)
2356*627f7eb2Smrg                     static assert(false, "overload for type '" ~ T.stringof ~ "' hasn't been specified");
2357*627f7eb2Smrg                 else static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2358*627f7eb2Smrg                     return Handler[HandlerOverloadMap.exceptionFuncIdx]();
2359*627f7eb2Smrg                 else
2360*627f7eb2Smrg                     throw new VariantException(
2361*627f7eb2Smrg                         "variant holds value of type '"
2362*627f7eb2Smrg                         ~ T.stringof ~
2363*627f7eb2Smrg                         "' but no visitor has been provided"
2364*627f7eb2Smrg                     );
2365*627f7eb2Smrg             }
2366*627f7eb2Smrg             else
2367*627f7eb2Smrg             {
2368*627f7eb2Smrg                 return Handler[ dgIdx ](*ptr);
2369*627f7eb2Smrg             }
2370*627f7eb2Smrg         }
2371*627f7eb2Smrg     }
2372*627f7eb2Smrg 
2373*627f7eb2Smrg     assert(false);
2374*627f7eb2Smrg }
2375*627f7eb2Smrg 
2376*627f7eb2Smrg @system unittest
2377*627f7eb2Smrg {
2378*627f7eb2Smrg     // validate that visit can be called with a const type
2379*627f7eb2Smrg     struct Foo { int depth; }
2380*627f7eb2Smrg     struct Bar { int depth; }
2381*627f7eb2Smrg     alias FooBar = Algebraic!(Foo, Bar);
2382*627f7eb2Smrg 
depth(in FooBar fb)2383*627f7eb2Smrg     int depth(in FooBar fb) {
2384*627f7eb2Smrg         return fb.visit!((Foo foo) => foo.depth,
2385*627f7eb2Smrg                          (Bar bar) => bar.depth);
2386*627f7eb2Smrg     }
2387*627f7eb2Smrg 
2388*627f7eb2Smrg     FooBar fb = Foo(3);
2389*627f7eb2Smrg     assert(depth(fb) == 3);
2390*627f7eb2Smrg }
2391*627f7eb2Smrg 
2392*627f7eb2Smrg @system unittest
2393*627f7eb2Smrg {
2394*627f7eb2Smrg     // https://issues.dlang.org/show_bug.cgi?id=16383
this()2395*627f7eb2Smrg     class Foo {this() immutable {}}
2396*627f7eb2Smrg     alias V = Algebraic!(immutable Foo);
2397*627f7eb2Smrg 
2398*627f7eb2Smrg     auto x = V(new immutable Foo).visit!(
2399*627f7eb2Smrg         (immutable(Foo) _) => 3
2400*627f7eb2Smrg     );
2401*627f7eb2Smrg     assert(x == 3);
2402*627f7eb2Smrg }
2403*627f7eb2Smrg 
2404*627f7eb2Smrg @system unittest
2405*627f7eb2Smrg {
2406*627f7eb2Smrg     // http://d.puremagic.com/issues/show_bug.cgi?id=5310
2407*627f7eb2Smrg     const Variant a;
2408*627f7eb2Smrg     assert(a == a);
2409*627f7eb2Smrg     Variant b;
2410*627f7eb2Smrg     assert(a == b);
2411*627f7eb2Smrg     assert(b == a);
2412*627f7eb2Smrg }
2413*627f7eb2Smrg 
2414*627f7eb2Smrg @system unittest
2415*627f7eb2Smrg {
2416*627f7eb2Smrg     const Variant a = [2];
2417*627f7eb2Smrg     assert(a[0] == 2);
2418*627f7eb2Smrg }
2419*627f7eb2Smrg 
2420*627f7eb2Smrg @system unittest
2421*627f7eb2Smrg {
2422*627f7eb2Smrg     // http://d.puremagic.com/issues/show_bug.cgi?id=10017
2423*627f7eb2Smrg     static struct S
2424*627f7eb2Smrg     {
2425*627f7eb2Smrg         ubyte[Variant.size + 1] s;
2426*627f7eb2Smrg     }
2427*627f7eb2Smrg 
2428*627f7eb2Smrg     Variant v1, v2;
2429*627f7eb2Smrg     v1 = S(); // the payload is allocated on the heap
2430*627f7eb2Smrg     v2 = v1;  // AssertError: target must be non-null
2431*627f7eb2Smrg     assert(v1 == v2);
2432*627f7eb2Smrg }
2433*627f7eb2Smrg @system unittest
2434*627f7eb2Smrg {
2435*627f7eb2Smrg     import std.exception : assertThrown;
2436*627f7eb2Smrg     // http://d.puremagic.com/issues/show_bug.cgi?id=7069
2437*627f7eb2Smrg     Variant v;
2438*627f7eb2Smrg 
2439*627f7eb2Smrg     int i = 10;
2440*627f7eb2Smrg     v = i;
2441*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ConstOf))
2442*627f7eb2Smrg     {
2443*627f7eb2Smrg         assert(v.get!(qual!int) == 10);
2444*627f7eb2Smrg         assert(v.get!(qual!float) == 10.0f);
2445*627f7eb2Smrg     }
2446*627f7eb2Smrg     foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2447*627f7eb2Smrg     {
2448*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!int));
2449*627f7eb2Smrg     }
2450*627f7eb2Smrg 
2451*627f7eb2Smrg     const(int) ci = 20;
2452*627f7eb2Smrg     v = ci;
2453*627f7eb2Smrg     foreach (qual; AliasSeq!(ConstOf))
2454*627f7eb2Smrg     {
2455*627f7eb2Smrg         assert(v.get!(qual!int) == 20);
2456*627f7eb2Smrg         assert(v.get!(qual!float) == 20.0f);
2457*627f7eb2Smrg     }
2458*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ImmutableOf, SharedOf, SharedConstOf))
2459*627f7eb2Smrg     {
2460*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!int));
2461*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!float));
2462*627f7eb2Smrg     }
2463*627f7eb2Smrg 
2464*627f7eb2Smrg     immutable(int) ii = ci;
2465*627f7eb2Smrg     v = ii;
2466*627f7eb2Smrg     foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2467*627f7eb2Smrg     {
2468*627f7eb2Smrg         assert(v.get!(qual!int) == 20);
2469*627f7eb2Smrg         assert(v.get!(qual!float) == 20.0f);
2470*627f7eb2Smrg     }
2471*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, SharedOf))
2472*627f7eb2Smrg     {
2473*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!int));
2474*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!float));
2475*627f7eb2Smrg     }
2476*627f7eb2Smrg 
2477*627f7eb2Smrg     int[] ai = [1,2,3];
2478*627f7eb2Smrg     v = ai;
2479*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ConstOf))
2480*627f7eb2Smrg     {
2481*627f7eb2Smrg         assert(v.get!(qual!(int[])) == [1,2,3]);
2482*627f7eb2Smrg         assert(v.get!(qual!(int)[]) == [1,2,3]);
2483*627f7eb2Smrg     }
2484*627f7eb2Smrg     foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2485*627f7eb2Smrg     {
2486*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!(int[])));
2487*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!(int)[]));
2488*627f7eb2Smrg     }
2489*627f7eb2Smrg 
2490*627f7eb2Smrg     const(int[]) cai = [4,5,6];
2491*627f7eb2Smrg     v = cai;
2492*627f7eb2Smrg     foreach (qual; AliasSeq!(ConstOf))
2493*627f7eb2Smrg     {
2494*627f7eb2Smrg         assert(v.get!(qual!(int[])) == [4,5,6]);
2495*627f7eb2Smrg         assert(v.get!(qual!(int)[]) == [4,5,6]);
2496*627f7eb2Smrg     }
2497*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ImmutableOf, SharedOf, SharedConstOf))
2498*627f7eb2Smrg     {
2499*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!(int[])));
2500*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!(int)[]));
2501*627f7eb2Smrg     }
2502*627f7eb2Smrg 
2503*627f7eb2Smrg     immutable(int[]) iai = [7,8,9];
2504*627f7eb2Smrg     v = iai;
2505*627f7eb2Smrg     //assert(v.get!(immutable(int[])) == [7,8,9]);   // Bug ??? runtime error
2506*627f7eb2Smrg     assert(v.get!(immutable(int)[]) == [7,8,9]);
2507*627f7eb2Smrg     assert(v.get!(const(int[])) == [7,8,9]);
2508*627f7eb2Smrg     assert(v.get!(const(int)[]) == [7,8,9]);
2509*627f7eb2Smrg     //assert(v.get!(shared(const(int[]))) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
2510*627f7eb2Smrg     //assert(v.get!(shared(const(int))[]) == cast(shared const)[7,8,9]);    // Bug ??? runtime error
2511*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf))
2512*627f7eb2Smrg     {
2513*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!(int[])));
2514*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!(int)[]));
2515*627f7eb2Smrg     }
2516*627f7eb2Smrg 
2517*627f7eb2Smrg     class A {}
2518*627f7eb2Smrg     class B : A {}
2519*627f7eb2Smrg     B b = new B();
2520*627f7eb2Smrg     v = b;
2521*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ConstOf))
2522*627f7eb2Smrg     {
2523*627f7eb2Smrg         assert(v.get!(qual!B) is b);
2524*627f7eb2Smrg         assert(v.get!(qual!A) is b);
2525*627f7eb2Smrg         assert(v.get!(qual!Object) is b);
2526*627f7eb2Smrg     }
2527*627f7eb2Smrg     foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2528*627f7eb2Smrg     {
2529*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!B));
2530*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!A));
2531*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!Object));
2532*627f7eb2Smrg     }
2533*627f7eb2Smrg 
2534*627f7eb2Smrg     const(B) cb = new B();
2535*627f7eb2Smrg     v = cb;
2536*627f7eb2Smrg     foreach (qual; AliasSeq!(ConstOf))
2537*627f7eb2Smrg     {
2538*627f7eb2Smrg         assert(v.get!(qual!B) is cb);
2539*627f7eb2Smrg         assert(v.get!(qual!A) is cb);
2540*627f7eb2Smrg         assert(v.get!(qual!Object) is cb);
2541*627f7eb2Smrg     }
2542*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ImmutableOf, SharedOf, SharedConstOf))
2543*627f7eb2Smrg     {
2544*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!B));
2545*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!A));
2546*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!Object));
2547*627f7eb2Smrg     }
2548*627f7eb2Smrg 
2549*627f7eb2Smrg     immutable(B) ib = new immutable(B)();
2550*627f7eb2Smrg     v = ib;
2551*627f7eb2Smrg     foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2552*627f7eb2Smrg     {
2553*627f7eb2Smrg         assert(v.get!(qual!B) is ib);
2554*627f7eb2Smrg         assert(v.get!(qual!A) is ib);
2555*627f7eb2Smrg         assert(v.get!(qual!Object) is ib);
2556*627f7eb2Smrg     }
2557*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, SharedOf))
2558*627f7eb2Smrg     {
2559*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!B));
2560*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!A));
2561*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!Object));
2562*627f7eb2Smrg     }
2563*627f7eb2Smrg 
2564*627f7eb2Smrg     shared(B) sb = new shared B();
2565*627f7eb2Smrg     v = sb;
2566*627f7eb2Smrg     foreach (qual; AliasSeq!(SharedOf, SharedConstOf))
2567*627f7eb2Smrg     {
2568*627f7eb2Smrg         assert(v.get!(qual!B) is sb);
2569*627f7eb2Smrg         assert(v.get!(qual!A) is sb);
2570*627f7eb2Smrg         assert(v.get!(qual!Object) is sb);
2571*627f7eb2Smrg     }
2572*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ImmutableOf, ConstOf))
2573*627f7eb2Smrg     {
2574*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!B));
2575*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!A));
2576*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!Object));
2577*627f7eb2Smrg     }
2578*627f7eb2Smrg 
2579*627f7eb2Smrg     shared(const(B)) scb = new shared const B();
2580*627f7eb2Smrg     v = scb;
2581*627f7eb2Smrg     foreach (qual; AliasSeq!(SharedConstOf))
2582*627f7eb2Smrg     {
2583*627f7eb2Smrg         assert(v.get!(qual!B) is scb);
2584*627f7eb2Smrg         assert(v.get!(qual!A) is scb);
2585*627f7eb2Smrg         assert(v.get!(qual!Object) is scb);
2586*627f7eb2Smrg     }
2587*627f7eb2Smrg     foreach (qual; AliasSeq!(MutableOf, ConstOf, ImmutableOf, SharedOf))
2588*627f7eb2Smrg     {
2589*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!B));
2590*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!A));
2591*627f7eb2Smrg         assertThrown!VariantException(v.get!(qual!Object));
2592*627f7eb2Smrg     }
2593*627f7eb2Smrg }
2594*627f7eb2Smrg 
2595*627f7eb2Smrg @system unittest
2596*627f7eb2Smrg {
2597*627f7eb2Smrg     static struct DummyScope
2598*627f7eb2Smrg     {
2599*627f7eb2Smrg         // https://d.puremagic.com/issues/show_bug.cgi?id=12540
2600*627f7eb2Smrg         alias Alias12540 = Algebraic!Class12540;
2601*627f7eb2Smrg 
2602*627f7eb2Smrg         static class Class12540
2603*627f7eb2Smrg         {
2604*627f7eb2Smrg             Alias12540 entity;
2605*627f7eb2Smrg         }
2606*627f7eb2Smrg     }
2607*627f7eb2Smrg }
2608*627f7eb2Smrg 
2609*627f7eb2Smrg @system unittest
2610*627f7eb2Smrg {
2611*627f7eb2Smrg     // https://issues.dlang.org/show_bug.cgi?id=10194
2612*627f7eb2Smrg     // Also test for elaborate copying
2613*627f7eb2Smrg     static struct S
2614*627f7eb2Smrg     {
2615*627f7eb2Smrg         @disable this();
2616*627f7eb2Smrg         this(int dummy)
2617*627f7eb2Smrg         {
2618*627f7eb2Smrg             ++cnt;
2619*627f7eb2Smrg         }
2620*627f7eb2Smrg 
2621*627f7eb2Smrg         this(this)
2622*627f7eb2Smrg         {
2623*627f7eb2Smrg             ++cnt;
2624*627f7eb2Smrg         }
2625*627f7eb2Smrg 
2626*627f7eb2Smrg         @disable S opAssign();
2627*627f7eb2Smrg 
2628*627f7eb2Smrg         ~this()
2629*627f7eb2Smrg         {
2630*627f7eb2Smrg             --cnt;
2631*627f7eb2Smrg             assert(cnt >= 0);
2632*627f7eb2Smrg         }
2633*627f7eb2Smrg         static int cnt = 0;
2634*627f7eb2Smrg     }
2635*627f7eb2Smrg 
2636*627f7eb2Smrg     {
2637*627f7eb2Smrg         Variant v;
2638*627f7eb2Smrg         {
2639*627f7eb2Smrg             v = S(0);
2640*627f7eb2Smrg             assert(S.cnt == 1);
2641*627f7eb2Smrg         }
2642*627f7eb2Smrg         assert(S.cnt == 1);
2643*627f7eb2Smrg 
2644*627f7eb2Smrg         // assigning a new value should destroy the existing one
2645*627f7eb2Smrg         v = 0;
2646*627f7eb2Smrg         assert(S.cnt == 0);
2647*627f7eb2Smrg 
2648*627f7eb2Smrg         // destroying the variant should destroy it's current value
2649*627f7eb2Smrg         v = S(0);
2650*627f7eb2Smrg         assert(S.cnt == 1);
2651*627f7eb2Smrg     }
2652*627f7eb2Smrg     assert(S.cnt == 0);
2653*627f7eb2Smrg }
2654*627f7eb2Smrg 
2655*627f7eb2Smrg @system unittest
2656*627f7eb2Smrg {
2657*627f7eb2Smrg     // Bugzilla 13300
2658*627f7eb2Smrg     static struct S
2659*627f7eb2Smrg     {
2660*627f7eb2Smrg         this(this) {}
2661*627f7eb2Smrg         ~this() {}
2662*627f7eb2Smrg     }
2663*627f7eb2Smrg 
2664*627f7eb2Smrg     static assert( hasElaborateCopyConstructor!(Variant));
2665*627f7eb2Smrg     static assert(!hasElaborateCopyConstructor!(Algebraic!bool));
2666*627f7eb2Smrg     static assert( hasElaborateCopyConstructor!(Algebraic!S));
2667*627f7eb2Smrg     static assert( hasElaborateCopyConstructor!(Algebraic!(bool, S)));
2668*627f7eb2Smrg 
2669*627f7eb2Smrg     static assert( hasElaborateDestructor!(Variant));
2670*627f7eb2Smrg     static assert(!hasElaborateDestructor!(Algebraic!bool));
2671*627f7eb2Smrg     static assert( hasElaborateDestructor!(Algebraic!S));
2672*627f7eb2Smrg     static assert( hasElaborateDestructor!(Algebraic!(bool, S)));
2673*627f7eb2Smrg 
2674*627f7eb2Smrg     import std.array;
2675*627f7eb2Smrg     alias Value = Algebraic!bool;
2676*627f7eb2Smrg 
2677*627f7eb2Smrg     static struct T
2678*627f7eb2Smrg     {
2679*627f7eb2Smrg         Value value;
2680*627f7eb2Smrg         @disable this();
2681*627f7eb2Smrg     }
2682*627f7eb2Smrg     auto a = appender!(T[]);
2683*627f7eb2Smrg }
2684*627f7eb2Smrg 
2685*627f7eb2Smrg @system unittest
2686*627f7eb2Smrg {
2687*627f7eb2Smrg     // Bugzilla 13871
2688*627f7eb2Smrg     alias A = Algebraic!(int, typeof(null));
2689*627f7eb2Smrg     static struct B { A value; }
2690*627f7eb2Smrg     alias C = std.variant.Algebraic!B;
2691*627f7eb2Smrg 
2692*627f7eb2Smrg     C var;
2693*627f7eb2Smrg     var = C(B());
2694*627f7eb2Smrg }
2695*627f7eb2Smrg 
2696*627f7eb2Smrg @system unittest
2697*627f7eb2Smrg {
2698*627f7eb2Smrg     import std.exception : assertThrown, assertNotThrown;
2699*627f7eb2Smrg     // Make sure Variant can handle types with opDispatch but no length field.
2700*627f7eb2Smrg     struct SWithNoLength
2701*627f7eb2Smrg     {
2702*627f7eb2Smrg         void opDispatch(string s)() { }
2703*627f7eb2Smrg     }
2704*627f7eb2Smrg 
2705*627f7eb2Smrg     struct SWithLength
2706*627f7eb2Smrg     {
2707*627f7eb2Smrg         @property int opDispatch(string s)()
2708*627f7eb2Smrg         {
2709*627f7eb2Smrg             // Assume that s == "length"
2710*627f7eb2Smrg             return 5; // Any value is OK for test.
2711*627f7eb2Smrg         }
2712*627f7eb2Smrg     }
2713*627f7eb2Smrg 
2714*627f7eb2Smrg     SWithNoLength sWithNoLength;
2715*627f7eb2Smrg     Variant v = sWithNoLength;
2716*627f7eb2Smrg     assertThrown!VariantException(v.length);
2717*627f7eb2Smrg 
2718*627f7eb2Smrg     SWithLength sWithLength;
2719*627f7eb2Smrg     v = sWithLength;
2720*627f7eb2Smrg     assertNotThrown!VariantException(v.get!SWithLength.length);
2721*627f7eb2Smrg     assertThrown!VariantException(v.length);
2722*627f7eb2Smrg }
2723*627f7eb2Smrg 
2724*627f7eb2Smrg @system unittest
2725*627f7eb2Smrg {
2726*627f7eb2Smrg     // Bugzilla 13534
2727*627f7eb2Smrg     static assert(!__traits(compiles, () @safe {
2728*627f7eb2Smrg         auto foo() @system { return 3; }
2729*627f7eb2Smrg         auto v = Variant(&foo);
2730*627f7eb2Smrg         v(); // foo is called in safe code!?
2731*627f7eb2Smrg     }));
2732*627f7eb2Smrg }
2733*627f7eb2Smrg 
2734*627f7eb2Smrg @system unittest
2735*627f7eb2Smrg {
2736*627f7eb2Smrg     // Bugzilla 15039
2737*627f7eb2Smrg     import std.typecons;
2738*627f7eb2Smrg     import std.variant;
2739*627f7eb2Smrg 
2740*627f7eb2Smrg     alias IntTypedef = Typedef!int;
2741*627f7eb2Smrg     alias Obj = Algebraic!(int, IntTypedef, This[]);
2742*627f7eb2Smrg 
2743*627f7eb2Smrg     Obj obj = 1;
2744*627f7eb2Smrg 
2745*627f7eb2Smrg     obj.visit!(
2746*627f7eb2Smrg         (int x) {},
2747*627f7eb2Smrg         (IntTypedef x) {},
2748*627f7eb2Smrg         (Obj[] x) {},
2749*627f7eb2Smrg     );
2750*627f7eb2Smrg }
2751*627f7eb2Smrg 
2752*627f7eb2Smrg @system unittest
2753*627f7eb2Smrg {
2754*627f7eb2Smrg     // Bugzilla 15791
2755*627f7eb2Smrg     int n = 3;
2756*627f7eb2Smrg     struct NS1 { int foo() { return n + 10; } }
2757*627f7eb2Smrg     struct NS2 { int foo() { return n * 10; } }
2758*627f7eb2Smrg 
2759*627f7eb2Smrg     Variant v;
2760*627f7eb2Smrg     v = NS1();
2761*627f7eb2Smrg     assert(v.get!NS1.foo() == 13);
2762*627f7eb2Smrg     v = NS2();
2763*627f7eb2Smrg     assert(v.get!NS2.foo() == 30);
2764*627f7eb2Smrg }
2765*627f7eb2Smrg 
2766*627f7eb2Smrg @system unittest
2767*627f7eb2Smrg {
2768*627f7eb2Smrg     // Bugzilla 15827
2769*627f7eb2Smrg     static struct Foo15827 { Variant v; this(Foo15827 v) {} }
2770*627f7eb2Smrg     Variant v = Foo15827.init;
2771*627f7eb2Smrg }
2772