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