1// Written in the D programming language.
2
3/**
4This module implements a
5$(HTTP erdani.org/publications/cuj-04-2002.html,discriminated union)
6type (a.k.a.
7$(HTTP en.wikipedia.org/wiki/Tagged_union,tagged union),
8$(HTTP en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)).
9Such types are useful
10for type-uniform binary interfaces, interfacing with scripting
11languages, and comfortable exploratory programming.
12
13A $(LREF Variant) object can hold a value of any type, with very few
14restrictions (such as `shared` types and noncopyable types). Setting the value
15is as immediate as assigning to the `Variant` object. To read back the value of
16the 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
18exact type currently held, call $(LREF type), which returns the `TypeInfo` of
19the current value.
20
21In addition to $(LREF Variant), this module also defines the $(LREF Algebraic)
22type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of
23types, which are specified in the instantiation (e.g. $(D Algebraic!(int,
24string)) may only hold an `int` or a `string`).
25
26Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
27prompting the following improvements: (1) better support for arrays; (2) support
28for associative arrays; (3) friendlier behavior towards the garbage collector.
29Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
30License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
31Authors:   $(HTTP erdani.org, Andrei Alexandrescu)
32Source:    $(PHOBOSSRC std/_variant.d)
33*/
34module std.variant;
35
36import 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  +/
78template 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
101struct This;
102
103private 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 */
132struct 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
139private:
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
550public:
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;
1199    int foo() { return 42; }
1200    v = &foo;
1201    assert(v() == 42);
1202
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
1328pure 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;
1356        ~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    {
1372        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
1381types. It's an alias for $(LREF VariantN) with an
1382appropriately-constructed maximum size. `Algebraic` is
1383useful when it is desirable to restrict what a discriminated type
1384could hold to the end of defining simpler and more efficient
1385manipulation.
1386
1387*/
1388template 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
1407A useful and popular use of algebraic data structures is for defining $(LUCKY
1408self-referential data structures), i.e. structures that embed references to
1409values of their own type within.
1410
1411This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1412reference to the type being defined is needed. The `Algebraic` instantiation
1413will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1414alpha renaming) on its constituent types, replacing `This`
1415with the self-referenced type. The structure of the type involving `This` may
1416be 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/**
1439Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1440`char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1441to hold all of D's predefined types unboxed, including all numeric types,
1442pointers, delegates, and class references.  You may want to use
1443$(D VariantN) directly with a different maximum size either for
1444storing larger types unboxed, or for saving memory.
1445 */
1446alias 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 */
1455Variant[] 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
1486static 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;
1492    this(string s)
1493    {
1494        super(s);
1495    }
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    }
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;
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 {
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{
1873    static string t1(string c) {
1874        return c ~ "a";
1875    }
1876
1877    static const(char)[] t2(const(char)[] p) {
1878        return p ~ "b";
1879    }
1880
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;
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
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{
1977    static void t1() { }
1978    Variant v = &t1;
1979    assert(v() == Variant.init);
1980
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{
1989    struct TestStruct(bool pad)
1990    {
1991        int val1;
1992        static if (pad)
1993            ubyte[Variant.size] padding;
1994        int val2;
1995    }
1996
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 */
2045template visit(Handlers...)
2046if (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
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 */
2188template tryVisit(Handlers...)
2189if (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
2231    void errorfunc()
2232    {
2233        which = -1;
2234    }
2235
2236    variant.tryVisit!((int i) { which = 0; }, errorfunc)();
2237
2238    assert(which == -1);
2239}
2240
2241private 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
2256private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2257if (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     */
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
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
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
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