Daily bump.
[gcc.git] / libphobos / src / std / variant.d
bloba0b564440120ed0ca96b8fdfee0f4161f8519565
1 // Written in the D programming language.
3 /**
4 This module implements a
5 $(HTTP erdani.org/publications/cuj-04-2002.php.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.
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) method. To query whether a
17 `Variant` currently holds a value of type `T`, use $(LREF peek). To fetch the
18 exact type currently held, call $(LREF type), which returns the `TypeInfo` of
19 the current value.
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`).
26 $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
27 code. Instead, use $(REF SumType, std,sumtype).)
29 Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
30 prompting the following improvements: (1) better support for arrays; (2) support
31 for associative arrays; (3) friendlier behavior towards the garbage collector.
32 Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
33 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
34 Authors: $(HTTP erdani.org, Andrei Alexandrescu)
35 Source: $(PHOBOSSRC std/variant.d)
37 module std.variant;
39 import std.meta, std.traits, std.typecons;
41 ///
42 @system unittest
44 Variant a; // Must assign before use, otherwise exception ensues
45 // Initialize with an integer; make the type int
46 Variant b = 42;
47 assert(b.type == typeid(int));
48 // Peek at the value
49 assert(b.peek!(int) !is null && *b.peek!(int) == 42);
50 // Automatically convert per language rules
51 auto x = b.get!(real);
53 // Assign any other type, including other variants
54 a = b;
55 a = 3.14;
56 assert(a.type == typeid(double));
57 // Implicit conversions work just as with built-in types
58 assert(a < b);
59 // Check for convertibility
60 assert(!a.convertsTo!(int)); // double not convertible to int
61 // Strings and all other arrays are supported
62 a = "now I'm a string";
63 assert(a == "now I'm a string");
65 // can also assign arrays
66 a = new int[42];
67 assert(a.length == 42);
68 a[5] = 7;
69 assert(a[5] == 7);
71 // Can also assign class values
72 class Foo {}
73 auto foo = new Foo;
74 a = foo;
75 assert(*a.peek!(Foo) == foo); // and full type information is preserved
78 /++
79 Gives the `sizeof` the largest type given.
81 See_Also: $(LINK https://forum.dlang.org/thread/wbpnncxepehgcswhuazl@forum.dlang.org?page=1)
83 template maxSize(Ts...)
85 align(1) union Impl
87 static foreach (i, T; Ts)
89 static if (!is(T == void))
90 mixin("T _field_", i, ";");
93 enum maxSize = Impl.sizeof;
96 ///
97 @safe unittest
99 struct Cat { int a, b, c; }
101 align(1) struct S
103 long l;
104 ubyte b;
107 align(1) struct T
109 ubyte b;
110 long l;
113 static assert(maxSize!(int, long) == 8);
114 static assert(maxSize!(bool, byte) == 1);
115 static assert(maxSize!(bool, Cat) == 12);
116 static assert(maxSize!(char) == 1);
117 static assert(maxSize!(char, short, ubyte) == 2);
118 static assert(maxSize!(char, long, ubyte) == 8);
119 import std.algorithm.comparison : max;
120 static assert(maxSize!(long, S) == max(long.sizeof, S.sizeof));
121 static assert(maxSize!(S, T) == max(S.sizeof, T.sizeof));
122 static assert(maxSize!(int, ubyte[7]) == 7);
123 static assert(maxSize!(int, ubyte[3]) == 4);
124 static assert(maxSize!(int, int, ubyte[3]) == 4);
125 static assert(maxSize!(void, int, ubyte[3]) == 4);
126 static assert(maxSize!(void) == 1);
129 struct This;
131 private alias This2Variant(V, T...) = AliasSeq!(ReplaceTypeUnless!(isAlgebraic, This, V, T));
133 // We can't just use maxAlignment because no types might be specified
134 // to VariantN, so handle that here and then pass along the rest.
135 private template maxVariantAlignment(U...)
136 if (isTypeTuple!U)
138 static if (U.length == 0)
140 import std.algorithm.comparison : max;
141 enum maxVariantAlignment = max(real.alignof, size_t.alignof);
143 else
144 enum maxVariantAlignment = maxAlignment!(U);
148 * Back-end type seldom used directly by user
149 * code. Two commonly-used types using `VariantN` are:
151 * $(OL $(LI $(LREF Algebraic): A closed discriminated union with a
152 * limited type universe (e.g., $(D Algebraic!(int, double,
153 * string)) only accepts these three types and rejects anything
154 * else).) $(LI $(LREF Variant): An open discriminated union allowing an
155 * unbounded set of types. If any of the types in the `Variant`
156 * are larger than the largest built-in type, they will automatically
157 * be boxed. This means that even large types will only be the size
158 * of a pointer within the `Variant`, but this also implies some
159 * overhead. `Variant` can accommodate all primitive types and
160 * all user-defined types.))
162 * Both `Algebraic` and `Variant` share $(D
163 * VariantN)'s interface. (See their respective documentations below.)
165 * `VariantN` is a discriminated union type parameterized
166 * with the largest size of the types stored (`maxDataSize`)
167 * and with the list of allowed types (`AllowedTypes`). If
168 * the list is empty, then any type up of size up to $(D
169 * maxDataSize) (rounded up for alignment) can be stored in a
170 * `VariantN` object without being boxed (types larger
171 * than this will be boxed).
174 struct VariantN(size_t maxDataSize, AllowedTypesParam...)
177 The list of allowed types. If empty, any type is allowed.
179 alias AllowedTypes = This2Variant!(VariantN, AllowedTypesParam);
181 private:
182 // Compute the largest practical size from maxDataSize
183 struct SizeChecker
185 int function() fptr;
186 ubyte[maxDataSize] data;
188 enum size = SizeChecker.sizeof - (int function()).sizeof;
190 /** Tells whether a type `T` is statically _allowed for
191 * storage inside a `VariantN` object by looking
192 * `T` up in `AllowedTypes`.
194 public template allowed(T)
196 enum bool allowed
197 = is(T == VariantN)
199 //T.sizeof <= size &&
200 (AllowedTypes.length == 0 || staticIndexOf!(T, AllowedTypes) >= 0);
203 // Each internal operation is encoded with an identifier. See
204 // the "handler" function below.
205 enum OpID { getTypeInfo, get, compare, equals, testConversion, toString,
206 index, indexAssign, catAssign, copyOut, length,
207 apply, postblit, destruct }
209 // state
210 union
212 align(maxVariantAlignment!(AllowedTypes)) ubyte[size] store;
213 // conservatively mark the region as pointers
214 static if (size >= (void*).sizeof)
215 void*[size / (void*).sizeof] p;
217 ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
218 = &handler!(void);
220 // internals
221 // Handler for an uninitialized value
222 static ptrdiff_t handler(A : void)(OpID selector, ubyte[size]*, void* parm)
224 switch (selector)
226 case OpID.getTypeInfo:
227 *cast(TypeInfo *) parm = typeid(A);
228 break;
229 case OpID.copyOut:
230 auto target = cast(VariantN *) parm;
231 target.fptr = &handler!(A);
232 // no need to copy the data (it's garbage)
233 break;
234 case OpID.compare:
235 case OpID.equals:
236 auto rhs = cast(const VariantN *) parm;
237 return rhs.peek!(A)
238 ? 0 // all uninitialized are equal
239 : ptrdiff_t.min; // uninitialized variant is not comparable otherwise
240 case OpID.toString:
241 string * target = cast(string*) parm;
242 *target = "<Uninitialized VariantN>";
243 break;
244 case OpID.postblit:
245 case OpID.destruct:
246 break;
247 case OpID.get:
248 case OpID.testConversion:
249 case OpID.index:
250 case OpID.indexAssign:
251 case OpID.catAssign:
252 case OpID.length:
253 throw new VariantException(
254 "Attempt to use an uninitialized VariantN");
255 default: assert(false, "Invalid OpID");
257 return 0;
260 // Handler for all of a type's operations
261 static ptrdiff_t handler(A)(OpID selector, ubyte[size]* pStore, void* parm)
263 import std.conv : to;
264 static A* getPtr(void* untyped)
266 if (untyped)
268 static if (A.sizeof <= size)
269 return cast(A*) untyped;
270 else
271 return *cast(A**) untyped;
273 return null;
276 static ptrdiff_t compare(A* rhsPA, A* zis, OpID selector)
278 static if (is(typeof(*rhsPA == *zis)))
280 enum isEmptyStructWithoutOpEquals = is(A == struct) && A.tupleof.length == 0 &&
281 !__traits(hasMember, A, "opEquals");
282 static if (isEmptyStructWithoutOpEquals)
284 // The check above will always succeed if A is an empty struct.
285 // Don't generate unreachable code as seen in
286 // https://issues.dlang.org/show_bug.cgi?id=21231
287 return 0;
289 else
291 if (*rhsPA == *zis)
292 return 0;
293 static if (is(typeof(*zis < *rhsPA)))
295 // Many types (such as any using the default Object opCmp)
296 // will throw on an invalid opCmp, so do it only
297 // if the caller requests it.
298 if (selector == OpID.compare)
299 return *zis < *rhsPA ? -1 : 1;
300 else
301 return ptrdiff_t.min;
303 else
305 // Not equal, and type does not support ordering
306 // comparisons.
307 return ptrdiff_t.min;
311 else
313 // Type does not support comparisons at all.
314 return ptrdiff_t.min;
318 auto zis = getPtr(pStore);
319 // Input: TypeInfo object
320 // Output: target points to a copy of *me, if me was not null
321 // Returns: true iff the A can be converted to the type represented
322 // by the incoming TypeInfo
323 static bool tryPutting(A* src, TypeInfo targetType, void* target)
325 alias UA = Unqual!A;
326 static if (isStaticArray!A && is(typeof(UA.init[0])))
328 alias MutaTypes = AliasSeq!(UA, typeof(UA.init[0])[], AllImplicitConversionTargets!UA);
330 else
332 alias MutaTypes = AliasSeq!(UA, AllImplicitConversionTargets!UA);
334 alias ConstTypes = staticMap!(ConstOf, MutaTypes);
335 alias SharedTypes = staticMap!(SharedOf, MutaTypes);
336 alias SharedConstTypes = staticMap!(SharedConstOf, MutaTypes);
337 alias ImmuTypes = staticMap!(ImmutableOf, MutaTypes);
339 static if (is(A == immutable))
340 alias AllTypes = AliasSeq!(ImmuTypes, ConstTypes, SharedConstTypes);
341 else static if (is(A == shared))
343 static if (is(A == const))
344 alias AllTypes = SharedConstTypes;
345 else
346 alias AllTypes = AliasSeq!(SharedTypes, SharedConstTypes);
348 else
350 static if (is(A == const))
351 alias AllTypes = ConstTypes;
352 else
353 alias AllTypes = AliasSeq!(MutaTypes, ConstTypes);
356 foreach (T ; AllTypes)
358 if (targetType != typeid(T))
359 continue;
361 // SPECIAL NOTE: variant only will ever create a new value with
362 // tryPutting (effectively), and T is ALWAYS the same type of
363 // A, but with different modifiers (and a limited set of
364 // implicit targets). So this checks to see if we can construct
365 // a T from A, knowing that prerequisite. This handles issues
366 // where the type contains some constant data aside from the
367 // modifiers on the type itself.
368 static if (is(typeof(delegate T() {return *src;})) ||
369 is(T == const(U), U) ||
370 is(T == shared(U), U) ||
371 is(T == shared const(U), U) ||
372 is(T == immutable(U), U))
374 import core.internal.lifetime : emplaceRef;
376 auto zat = cast(T*) target;
377 if (src)
379 static if (T.sizeof > 0)
380 assert(target, "target must be non-null");
382 static if (isStaticArray!A && isDynamicArray!T)
384 auto this_ = (*src)[];
385 emplaceRef(*cast(Unqual!T*) zat, cast() cast(T) this_);
387 else
389 emplaceRef(*cast(Unqual!T*) zat, *cast(UA*) src);
393 else
395 // type T is not constructible from A
396 if (src)
397 assert(false, A.stringof);
399 return true;
401 return false;
404 switch (selector)
406 case OpID.getTypeInfo:
407 *cast(TypeInfo *) parm = typeid(A);
408 break;
409 case OpID.copyOut:
410 auto target = cast(VariantN *) parm;
411 assert(target);
413 static if (target.size < A.sizeof)
415 if (target.type.tsize < A.sizeof)
417 static if (is(A == U[n], U, size_t n))
419 A* p = cast(A*)(new U[n]).ptr;
421 else
423 A* p = new A;
425 *cast(A**)&target.store = p;
428 tryPutting(zis, typeid(A), cast(void*) getPtr(&target.store))
429 || assert(false);
430 target.fptr = &handler!(A);
431 break;
432 case OpID.get:
433 auto t = * cast(Tuple!(TypeInfo, void*)*) parm;
434 return !tryPutting(zis, t[0], t[1]);
435 case OpID.testConversion:
436 return !tryPutting(null, *cast(TypeInfo*) parm, null);
437 case OpID.compare:
438 case OpID.equals:
439 auto rhsP = cast(VariantN *) parm;
440 auto rhsType = rhsP.type;
441 // Are we the same?
442 if (rhsType == typeid(A))
444 // cool! Same type!
445 auto rhsPA = getPtr(&rhsP.store);
446 return compare(rhsPA, zis, selector);
448 else if (rhsType == typeid(void))
450 // No support for ordering comparisons with
451 // uninitialized vars
452 return ptrdiff_t.min;
454 VariantN temp;
455 // Do I convert to rhs?
456 if (tryPutting(zis, rhsType, &temp.store))
458 // cool, I do; temp's store contains my data in rhs's type!
459 // also fix up its fptr
460 temp.fptr = rhsP.fptr;
461 // now lhsWithRhsType is a full-blown VariantN of rhs's type
462 if (selector == OpID.compare)
463 return temp.opCmp(*rhsP);
464 else
465 return temp.opEquals(*rhsP) ? 0 : 1;
467 // Does rhs convert to zis?
468 auto t = tuple(typeid(A), &temp.store);
469 if (rhsP.fptr(OpID.get, &rhsP.store, &t) == 0)
471 // cool! Now temp has rhs in my type!
472 auto rhsPA = getPtr(&temp.store);
473 return compare(rhsPA, zis, selector);
475 // Generate the function below only if the Variant's type is
476 // comparable with 'null'
477 static if (__traits(compiles, () => A.init == null))
479 if (rhsType == typeid(null))
481 // if rhsType is typeof(null), then we're comparing with 'null'
482 // this takes into account 'opEquals' and 'opCmp'
483 // all types that can compare with null have to following properties:
484 // if it's 'null' then it's equal to null, otherwise it's always greater
485 // than 'null'
486 return *zis == null ? 0 : 1;
489 return ptrdiff_t.min; // dunno
490 case OpID.toString:
491 auto target = cast(string*) parm;
492 static if (is(typeof(to!(string)(*zis))))
494 *target = to!(string)(*zis);
495 break;
497 // TODO: The following test evaluates to true for shared objects.
498 // Use __traits for now until this is sorted out.
499 // else static if (is(typeof((*zis).toString)))
500 else static if (__traits(compiles, {(*zis).toString();}))
502 *target = (*zis).toString();
503 break;
505 else
507 throw new VariantException(typeid(A), typeid(string));
510 case OpID.index:
511 auto result = cast(Variant*) parm;
512 static if (isArray!(A) && !is(immutable typeof(A.init[0]) == immutable void))
514 // array type; input and output are the same VariantN
515 size_t index = result.convertsTo!(int)
516 ? result.get!(int) : result.get!(size_t);
517 *result = (*zis)[index];
518 break;
520 else static if (isAssociativeArray!(A))
522 *result = (*zis)[result.get!(typeof(A.init.keys[0]))];
523 break;
525 else
527 throw new VariantException(typeid(A), result[0].type);
530 case OpID.indexAssign:
531 // array type; result comes first, index comes second
532 auto args = cast(Variant*) parm;
533 static if (isArray!(A) && is(typeof((*zis)[0] = (*zis)[0])))
535 size_t index = args[1].convertsTo!(int)
536 ? args[1].get!(int) : args[1].get!(size_t);
537 (*zis)[index] = args[0].get!(typeof((*zis)[0]));
538 break;
540 else static if (isAssociativeArray!(A) && is(typeof((*zis)[A.init.keys[0]] = A.init.values[0])))
542 (*zis)[args[1].get!(typeof(A.init.keys[0]))]
543 = args[0].get!(typeof(A.init.values[0]));
544 break;
546 else
548 throw new VariantException(typeid(A), args[0].type);
551 case OpID.catAssign:
552 static if (!is(immutable typeof((*zis)[0]) == immutable void) &&
553 is(typeof((*zis)[0])) && is(typeof(*zis ~= *zis)))
555 // array type; parm is the element to append
556 auto arg = cast(Variant*) parm;
557 alias E = typeof((*zis)[0]);
558 if (arg[0].convertsTo!(E))
560 // append one element to the array
561 (*zis) ~= [ arg[0].get!(E) ];
563 else
565 // append a whole array to the array
566 (*zis) ~= arg[0].get!(A);
568 break;
570 else
572 throw new VariantException(typeid(A), typeid(void[]));
575 case OpID.length:
576 static if (isArray!(A) || isAssociativeArray!(A))
578 return zis.length;
580 else
582 throw new VariantException(typeid(A), typeid(void[]));
585 case OpID.apply:
586 static if (!isFunctionPointer!A && !isDelegate!A)
588 import std.conv : text;
589 import std.exception : enforce;
590 enforce(0, text("Cannot apply `()' to a value of type `",
591 A.stringof, "'."));
593 else
595 import std.conv : text;
596 import std.exception : enforce;
597 alias ParamTypes = Parameters!A;
598 auto p = cast(Variant*) parm;
599 auto argCount = p.get!size_t;
600 // To assign the tuple we need to use the unqualified version,
601 // otherwise we run into issues such as with const values.
602 // We still get the actual type from the Variant though
603 // to ensure that we retain const correctness.
604 Tuple!(staticMap!(Unqual, ParamTypes)) t;
605 enforce(t.length == argCount,
606 text("Argument count mismatch: ",
607 A.stringof, " expects ", t.length,
608 " argument(s), not ", argCount, "."));
609 auto variantArgs = p[1 .. argCount + 1];
610 foreach (i, T; ParamTypes)
612 t[i] = cast() variantArgs[i].get!T;
615 auto args = cast(Tuple!(ParamTypes))t;
616 static if (is(ReturnType!A == void))
618 (*zis)(args.expand);
619 *p = Variant.init; // void returns uninitialized Variant.
621 else
623 *p = (*zis)(args.expand);
626 break;
628 case OpID.postblit:
629 static if (hasElaborateCopyConstructor!A)
631 zis.__xpostblit();
633 break;
635 case OpID.destruct:
636 static if (hasElaborateDestructor!A)
638 zis.__xdtor();
640 break;
642 default: assert(false);
644 return 0;
647 public:
648 /** Constructs a `VariantN` value given an argument of a
649 * generic type. Statically rejects disallowed types.
652 this(T)(T value)
654 static assert(allowed!(T), "Cannot store a " ~ T.stringof
655 ~ " in a " ~ VariantN.stringof);
656 opAssign(value);
659 /// Allows assignment from a subset algebraic type
660 this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value)
661 if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
663 opAssign(value);
666 static if (!AllowedTypes.length || anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
668 this(this)
670 fptr(OpID.postblit, &store, null);
674 static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
676 ~this()
678 // Infer the safety of the provided types
679 static if (AllowedTypes.length)
681 if (0)
683 AllowedTypes var;
686 (() @trusted => fptr(OpID.destruct, &store, null))();
690 /** Assigns a `VariantN` from a generic
691 * argument. Statically rejects disallowed types. */
693 VariantN opAssign(T)(T rhs)
695 static assert(allowed!(T), "Cannot store a " ~ T.stringof
696 ~ " in a " ~ VariantN.stringof ~ ". Valid types are "
697 ~ AllowedTypes.stringof);
699 static if (is(T : VariantN))
701 rhs.fptr(OpID.copyOut, &rhs.store, &this);
703 else static if (is(T : const(VariantN)))
705 static assert(false,
706 "Assigning Variant objects from const Variant"~
707 " objects is currently not supported.");
709 else
711 import core.lifetime : copyEmplace;
713 static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
715 // Assignment should destruct previous value
716 fptr(OpID.destruct, &store, null);
719 static if (T.sizeof <= size)
720 copyEmplace(rhs, *cast(T*) &store);
721 else
723 static if (is(T == U[n], U, size_t n))
724 auto p = cast(T*) (new U[n]).ptr;
725 else
726 auto p = new T;
727 copyEmplace(rhs, *p);
728 *(cast(T**) &store) = p;
731 fptr = &handler!(T);
733 return this;
736 // Allow assignment from another variant which is a subset of this one
737 VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs)
738 if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
740 // discover which type rhs is actually storing
741 foreach (V; T.AllowedTypes)
742 if (rhs.type == typeid(V))
743 return this = rhs.get!V;
744 assert(0, T.AllowedTypes.stringof);
748 Variant opCall(P...)(auto ref P params)
750 Variant[P.length + 1] pack;
751 pack[0] = P.length;
752 foreach (i, _; params)
754 pack[i + 1] = params[i];
756 fptr(OpID.apply, &store, &pack);
757 return pack[0];
760 /** Returns true if and only if the `VariantN` object
761 * holds a valid value (has been initialized with, or assigned
762 * from, a valid value).
764 @property bool hasValue() const pure nothrow
766 // @@@BUG@@@ in compiler, the cast shouldn't be needed
767 return cast(typeof(&handler!(void))) fptr != &handler!(void);
771 version (StdDdoc)
772 @system unittest
774 Variant a;
775 assert(!a.hasValue);
776 Variant b;
777 a = b;
778 assert(!a.hasValue); // still no value
779 a = 5;
780 assert(a.hasValue);
784 * If the `VariantN` object holds a value of the
785 * $(I exact) type `T`, returns a pointer to that
786 * value. Otherwise, returns `null`. In cases
787 * where `T` is statically disallowed, $(D
788 * peek) will not compile.
790 @property inout(T)* peek(T)() inout
792 static if (!is(T == void))
793 static assert(allowed!(T), "Cannot store a " ~ T.stringof
794 ~ " in a " ~ VariantN.stringof);
795 if (type != typeid(T))
796 return null;
797 static if (T.sizeof <= size)
798 return cast(inout T*)&store;
799 else
800 return *cast(inout T**)&store;
804 version (StdDdoc)
805 @system unittest
807 Variant a = 5;
808 auto b = a.peek!(int);
809 assert(b !is null);
810 *b = 6;
811 assert(a == 6);
815 * Returns the `typeid` of the currently held value.
818 @property TypeInfo type() const nothrow @trusted
820 scope(failure) assert(0);
822 TypeInfo result;
823 fptr(OpID.getTypeInfo, null, &result);
824 return result;
828 * Returns `true` if and only if the `VariantN`
829 * object holds an object implicitly convertible to type `T`.
830 * Implicit convertibility is defined as per
831 * $(REF_ALTTEXT AllImplicitConversionTargets, AllImplicitConversionTargets, std,traits).
834 @property bool convertsTo(T)() const
836 TypeInfo info = typeid(T);
837 return fptr(OpID.testConversion, null, &info) == 0;
841 Returns the value stored in the `VariantN` object, either by specifying the
842 needed type or the index in the list of allowed types. The latter overload
843 only applies to bounded variants (e.g. $(LREF Algebraic)).
845 Params:
846 T = The requested type. The currently stored value must implicitly convert
847 to the requested type, in fact `DecayStaticToDynamicArray!T`. If an
848 implicit conversion is not possible, throws a `VariantException`.
849 index = The index of the type among `AllowedTypesParam`, zero-based.
851 @property inout(T) get(T)() inout
853 inout(T) result = void;
854 static if (is(T == shared))
855 alias R = shared Unqual!T;
856 else
857 alias R = Unqual!T;
858 auto buf = tuple(typeid(T), cast(R*)&result);
860 if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf))
862 throw new VariantException(type, typeid(T));
864 return result;
867 /// Ditto
868 @property auto get(uint index)() inout
869 if (index < AllowedTypes.length)
871 foreach (i, T; AllowedTypes)
873 static if (index == i) return get!T;
875 assert(0);
879 * Returns the value stored in the `VariantN` object,
880 * explicitly converted (coerced) to the requested type $(D
881 * T). If `T` is a string type, the value is formatted as
882 * a string. If the `VariantN` object is a string, a
883 * parse of the string to type `T` is attempted. If a
884 * conversion is not possible, throws a $(D
885 * VariantException).
888 @property T coerce(T)()
890 import std.conv : to, text;
891 static if (isNumeric!T || isBoolean!T)
893 if (convertsTo!real)
895 // maybe optimize this fella; handle ints separately
896 return to!T(get!real);
898 else if (convertsTo!(const(char)[]))
900 return to!T(get!(const(char)[]));
902 // I'm not sure why this doesn't convert to const(char),
903 // but apparently it doesn't (probably a deeper bug).
905 // Until that is fixed, this quick addition keeps a common
906 // function working. "10".coerce!int ought to work.
907 else if (convertsTo!(immutable(char)[]))
909 return to!T(get!(immutable(char)[]));
911 else
913 import std.exception : enforce;
914 enforce(false, text("Type ", type, " does not convert to ",
915 typeid(T)));
916 assert(0);
919 else static if (is(T : Object))
921 return to!(T)(get!(Object));
923 else static if (isSomeString!(T))
925 return to!(T)(toString());
927 else
929 // Fix for bug 1649
930 static assert(false, "unsupported type for coercion");
935 * Formats the stored value as a string.
938 string toString()
940 string result;
941 fptr(OpID.toString, &store, &result) == 0 || assert(false);
942 return result;
946 * Comparison for equality used by the "==" and "!=" operators.
949 // returns 1 if the two are equal
950 bool opEquals(T)(auto ref T rhs) const
951 if (allowed!T || is(immutable T == immutable VariantN))
953 static if (is(immutable T == immutable VariantN))
954 alias temp = rhs;
955 else
956 auto temp = VariantN(rhs);
957 return !fptr(OpID.equals, cast(ubyte[size]*) &store,
958 cast(void*) &temp);
961 // workaround for bug 10567 fix
962 int opCmp(ref const VariantN rhs) const
964 return (cast() this).opCmp!(VariantN)(cast() rhs);
968 * Ordering comparison used by the "<", "<=", ">", and ">="
969 * operators. In case comparison is not sensible between the held
970 * value and `rhs`, an exception is thrown.
973 int opCmp(T)(T rhs)
974 if (allowed!T) // includes T == VariantN
976 static if (is(T == VariantN))
977 alias temp = rhs;
978 else
979 auto temp = VariantN(rhs);
980 auto result = fptr(OpID.compare, &store, &temp);
981 if (result == ptrdiff_t.min)
983 throw new VariantException(type, temp.type);
986 assert(result >= -1 && result <= 1); // Should be true for opCmp.
987 return cast(int) result;
991 * Computes the hash of the held value.
994 size_t toHash() const nothrow @safe
996 return type.getHash(&store);
999 private VariantN opArithmetic(T, string op)(T other)
1001 static if (isInstanceOf!(.VariantN, T))
1003 string tryUseType(string tp)
1005 import std.format : format;
1006 return q{
1007 static if (allowed!%1$s && T.allowed!%1$s)
1008 if (convertsTo!%1$s && other.convertsTo!%1$s)
1009 return VariantN(get!%1$s %2$s other.get!%1$s);
1010 }.format(tp, op);
1013 mixin(tryUseType("uint"));
1014 mixin(tryUseType("int"));
1015 mixin(tryUseType("ulong"));
1016 mixin(tryUseType("long"));
1017 mixin(tryUseType("float"));
1018 mixin(tryUseType("double"));
1019 mixin(tryUseType("real"));
1021 else
1023 static if (allowed!T)
1024 if (auto pv = peek!T) return VariantN(mixin("*pv " ~ op ~ " other"));
1025 static if (allowed!uint && is(typeof(T.max) : uint) && isUnsigned!T)
1026 if (convertsTo!uint) return VariantN(mixin("get!(uint) " ~ op ~ " other"));
1027 static if (allowed!int && is(typeof(T.max) : int) && !isUnsigned!T)
1028 if (convertsTo!int) return VariantN(mixin("get!(int) " ~ op ~ " other"));
1029 static if (allowed!ulong && is(typeof(T.max) : ulong) && isUnsigned!T)
1030 if (convertsTo!ulong) return VariantN(mixin("get!(ulong) " ~ op ~ " other"));
1031 static if (allowed!long && is(typeof(T.max) : long) && !isUnsigned!T)
1032 if (convertsTo!long) return VariantN(mixin("get!(long) " ~ op ~ " other"));
1033 static if (allowed!float && is(T : float))
1034 if (convertsTo!float) return VariantN(mixin("get!(float) " ~ op ~ " other"));
1035 static if (allowed!double && is(T : double))
1036 if (convertsTo!double) return VariantN(mixin("get!(double) " ~ op ~ " other"));
1037 static if (allowed!real && is (T : real))
1038 if (convertsTo!real) return VariantN(mixin("get!(real) " ~ op ~ " other"));
1041 throw new VariantException("No possible match found for VariantN "~op~" "~T.stringof);
1044 private VariantN opLogic(T, string op)(T other)
1046 VariantN result;
1047 static if (is(T == VariantN))
1049 if (convertsTo!(uint) && other.convertsTo!(uint))
1050 result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
1051 else if (convertsTo!(int) && other.convertsTo!(int))
1052 result = mixin("get!(int) " ~ op ~ " other.get!(int)");
1053 else if (convertsTo!(ulong) && other.convertsTo!(ulong))
1054 result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
1055 else
1056 result = mixin("get!(long) " ~ op ~ " other.get!(long)");
1058 else
1060 if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
1061 result = mixin("get!(uint) " ~ op ~ " other");
1062 else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
1063 result = mixin("get!(int) " ~ op ~ " other");
1064 else if (is(typeof(T.max) : ulong) && T.min == 0
1065 && convertsTo!(ulong))
1066 result = mixin("get!(ulong) " ~ op ~ " other");
1067 else
1068 result = mixin("get!(long) " ~ op ~ " other");
1070 return result;
1074 * Arithmetic between `VariantN` objects and numeric
1075 * values. All arithmetic operations return a `VariantN`
1076 * object typed depending on the types of both values
1077 * involved. The conversion rules mimic D's built-in rules for
1078 * arithmetic conversions.
1080 VariantN opBinary(string op, T)(T rhs)
1081 if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "^^" || op == "%") &&
1082 is(typeof(opArithmetic!(T, op)(rhs))))
1083 { return opArithmetic!(T, op)(rhs); }
1084 ///ditto
1085 VariantN opBinary(string op, T)(T rhs)
1086 if ((op == "&" || op == "|" || op == "^" || op == ">>" || op == "<<" || op == ">>>") &&
1087 is(typeof(opLogic!(T, op)(rhs))))
1088 { return opLogic!(T, op)(rhs); }
1089 ///ditto
1090 VariantN opBinaryRight(string op, T)(T lhs)
1091 if ((op == "+" || op == "*") &&
1092 is(typeof(opArithmetic!(T, op)(lhs))))
1093 { return opArithmetic!(T, op)(lhs); }
1094 ///ditto
1095 VariantN opBinaryRight(string op, T)(T lhs)
1096 if ((op == "&" || op == "|" || op == "^") &&
1097 is(typeof(opLogic!(T, op)(lhs))))
1098 { return opLogic!(T, op)(lhs); }
1099 ///ditto
1100 VariantN opBinary(string op, T)(T rhs)
1101 if (op == "~")
1103 auto temp = this;
1104 temp ~= rhs;
1105 return temp;
1107 // ///ditto
1108 // VariantN opBinaryRight(string op, T)(T rhs)
1109 // if (op == "~")
1110 // {
1111 // VariantN temp = rhs;
1112 // temp ~= this;
1113 // return temp;
1114 // }
1116 ///ditto
1117 VariantN opOpAssign(string op, T)(T rhs)
1119 static if (op != "~")
1121 mixin("return this = this" ~ op ~ "rhs;");
1123 else
1125 auto toAppend = Variant(rhs);
1126 fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
1127 return this;
1132 * Array and associative array operations. If a $(D
1133 * VariantN) contains an (associative) array, it can be indexed
1134 * into. Otherwise, an exception is thrown.
1136 inout(Variant) opIndex(K)(K i) inout
1138 auto result = Variant(i);
1139 fptr(OpID.index, cast(ubyte[size]*) &store, &result) == 0 || assert(false);
1140 return result;
1144 version (StdDdoc)
1145 @system unittest
1147 Variant a = new int[10];
1148 a[5] = 42;
1149 assert(a[5] == 42);
1150 a[5] += 8;
1151 assert(a[5] == 50);
1153 int[int] hash = [ 42:24 ];
1154 a = hash;
1155 assert(a[42] == 24);
1156 a[42] /= 2;
1157 assert(a[42] == 12);
1160 /// ditto
1161 Variant opIndexAssign(T, N)(T value, N i)
1163 static if (AllowedTypes.length && !isInstanceOf!(.VariantN, T))
1165 enum canAssign(U) = __traits(compiles, (U u){ u[i] = value; });
1166 static assert(anySatisfy!(canAssign, AllowedTypes),
1167 "Cannot assign " ~ T.stringof ~ " to " ~ VariantN.stringof ~
1168 " indexed with " ~ N.stringof);
1170 Variant[2] args = [ Variant(value), Variant(i) ];
1171 fptr(OpID.indexAssign, &store, &args) == 0 || assert(false);
1172 return args[0];
1175 /// ditto
1176 Variant opIndexOpAssign(string op, T, N)(T value, N i)
1178 return opIndexAssign(mixin(`opIndex(i)` ~ op ~ `value`), i);
1181 /** If the `VariantN` contains an (associative) array,
1182 * returns the _length of that array. Otherwise, throws an
1183 * exception.
1185 @property size_t length()
1187 return cast(size_t) fptr(OpID.length, &store, null);
1191 If the `VariantN` contains an array, applies `dg` to each
1192 element of the array in turn. Otherwise, throws an exception.
1194 int opApply(Delegate)(scope Delegate dg)
1195 if (is(Delegate == delegate))
1197 alias A = Parameters!(Delegate)[0];
1198 if (type == typeid(A[]))
1200 auto arr = get!(A[]);
1201 foreach (ref e; arr)
1203 if (dg(e)) return 1;
1206 else static if (is(A == VariantN))
1208 foreach (i; 0 .. length)
1210 // @@@TODO@@@: find a better way to not confuse
1211 // clients who think they change values stored in the
1212 // Variant when in fact they are only changing tmp.
1213 auto tmp = this[i];
1214 debug scope(exit) assert(tmp == this[i]);
1215 if (dg(tmp)) return 1;
1218 else
1220 import std.conv : text;
1221 import std.exception : enforce;
1222 enforce(false, text("Variant type ", type,
1223 " not iterable with values of type ",
1224 A.stringof));
1226 return 0;
1231 @system unittest
1233 alias Var = VariantN!(maxSize!(int, double, string));
1235 Var a; // Must assign before use, otherwise exception ensues
1236 // Initialize with an integer; make the type int
1237 Var b = 42;
1238 assert(b.type == typeid(int));
1239 // Peek at the value
1240 assert(b.peek!(int) !is null && *b.peek!(int) == 42);
1241 // Automatically convert per language rules
1242 auto x = b.get!(real);
1244 // Assign any other type, including other variants
1245 a = b;
1246 a = 3.14;
1247 assert(a.type == typeid(double));
1248 // Implicit conversions work just as with built-in types
1249 assert(a < b);
1250 // Check for convertibility
1251 assert(!a.convertsTo!(int)); // double not convertible to int
1252 // Strings and all other arrays are supported
1253 a = "now I'm a string";
1254 assert(a == "now I'm a string");
1257 /// can also assign arrays
1258 @system unittest
1260 alias Var = VariantN!(maxSize!(int[]));
1262 Var a = new int[42];
1263 assert(a.length == 42);
1264 a[5] = 7;
1265 assert(a[5] == 7);
1268 @safe unittest
1270 alias V = VariantN!24;
1271 const alignMask = V.alignof - 1;
1272 assert(V.sizeof == ((24 + (void*).sizeof + alignMask) & ~alignMask));
1275 /// Can also assign class values
1276 @system unittest
1278 alias Var = VariantN!(maxSize!(int*)); // classes are pointers
1279 Var a;
1281 class Foo {}
1282 auto foo = new Foo;
1283 a = foo;
1284 assert(*a.peek!(Foo) == foo); // and full type information is preserved
1287 @system unittest
1289 import std.conv : to;
1290 Variant v;
1291 int foo() { return 42; }
1292 v = &foo;
1293 assert(v() == 42);
1295 static int bar(string s) { return to!int(s); }
1296 v = &bar;
1297 assert(v("43") == 43);
1300 @system unittest
1302 int[int] hash = [ 42:24 ];
1303 Variant v = hash;
1304 assert(v[42] == 24);
1305 v[42] = 5;
1306 assert(v[42] == 5);
1309 // opIndex with static arrays, https://issues.dlang.org/show_bug.cgi?id=12771
1310 @system unittest
1312 int[4] elements = [0, 1, 2, 3];
1313 Variant v = elements;
1314 assert(v == elements);
1315 assert(v[2] == 2);
1316 assert(v[3] == 3);
1317 v[2] = 6;
1318 assert(v[2] == 6);
1319 assert(v != elements);
1322 @system unittest
1324 import std.exception : assertThrown;
1325 Algebraic!(int[]) v = [2, 2];
1327 assert(v == [2, 2]);
1328 v[0] = 1;
1329 assert(v[0] == 1);
1330 assert(v != [2, 2]);
1332 // opIndexAssign from Variant
1333 v[1] = v[0];
1334 assert(v[1] == 1);
1336 static assert(!__traits(compiles, (v[1] = null)));
1337 assertThrown!VariantException(v[1] = Variant(null));
1340 // https://issues.dlang.org/show_bug.cgi?id=10879
1341 @system unittest
1343 int[10] arr = [1,2,3,4,5,6,7,8,9,10];
1344 Variant v1 = arr;
1345 Variant v2;
1346 v2 = arr;
1347 assert(v1 == arr);
1348 assert(v2 == arr);
1349 foreach (i, e; arr)
1351 assert(v1[i] == e);
1352 assert(v2[i] == e);
1354 static struct LargeStruct
1356 int[100] data;
1358 LargeStruct ls;
1359 ls.data[] = 4;
1360 v1 = ls;
1361 Variant v3 = ls;
1362 assert(v1 == ls);
1363 assert(v3 == ls);
1366 // https://issues.dlang.org/show_bug.cgi?id=8195
1367 @system unittest
1369 struct S
1371 int a;
1372 long b;
1373 string c;
1374 real d = 0.0;
1375 bool e;
1378 static assert(S.sizeof >= Variant.sizeof);
1379 alias Types = AliasSeq!(string, int, S);
1380 alias MyVariant = VariantN!(maxSize!Types, Types);
1382 auto v = MyVariant(S.init);
1383 assert(v == S.init);
1386 // https://issues.dlang.org/show_bug.cgi?id=10961
1387 @system unittest
1389 // Primarily test that we can assign a void[] to a Variant.
1390 void[] elements = cast(void[])[1, 2, 3];
1391 Variant v = elements;
1392 void[] returned = v.get!(void[]);
1393 assert(returned == elements);
1396 // https://issues.dlang.org/show_bug.cgi?id=13352
1397 @system unittest
1399 alias TP = Algebraic!(long);
1400 auto a = TP(1L);
1401 auto b = TP(2L);
1402 assert(!TP.allowed!ulong);
1403 assert(a + b == 3L);
1404 assert(a + 2 == 3L);
1405 assert(1 + b == 3L);
1407 alias TP2 = Algebraic!(long, string);
1408 auto c = TP2(3L);
1409 assert(a + c == 4L);
1412 // https://issues.dlang.org/show_bug.cgi?id=13354
1413 @system unittest
1415 alias A = Algebraic!(string[]);
1416 A a = ["a", "b"];
1417 assert(a[0] == "a");
1418 assert(a[1] == "b");
1419 a[1] = "c";
1420 assert(a[1] == "c");
1422 alias AA = Algebraic!(int[string]);
1423 AA aa = ["a": 1, "b": 2];
1424 assert(aa["a"] == 1);
1425 assert(aa["b"] == 2);
1426 aa["b"] = 3;
1427 assert(aa["b"] == 3);
1430 // https://issues.dlang.org/show_bug.cgi?id=14198
1431 @system unittest
1433 Variant a = true;
1434 assert(a.type == typeid(bool));
1437 // https://issues.dlang.org/show_bug.cgi?id=14233
1438 @system unittest
1440 alias Atom = Algebraic!(string, This[]);
1442 Atom[] values = [];
1443 auto a = Atom(values);
1446 pure nothrow @nogc
1447 @system unittest
1449 Algebraic!(int, double) a;
1450 a = 100;
1451 a = 1.0;
1454 // https://issues.dlang.org/show_bug.cgi?id=14457
1455 @system unittest
1457 alias A = Algebraic!(int, float, double);
1458 alias B = Algebraic!(int, float);
1460 A a = 1;
1461 B b = 6f;
1462 a = b;
1464 assert(a.type == typeid(float));
1465 assert(a.get!float == 6f);
1468 // https://issues.dlang.org/show_bug.cgi?id=14585
1469 @system unittest
1471 static struct S
1473 int x = 42;
1474 ~this() {assert(x == 42);}
1476 Variant(S()).get!S;
1479 // https://issues.dlang.org/show_bug.cgi?id=14586
1480 @system unittest
1482 const Variant v = new immutable Object;
1483 v.get!(immutable Object);
1486 @system unittest
1488 static struct S
1490 T opCast(T)() {assert(false);}
1492 Variant v = S();
1493 v.get!S;
1496 // https://issues.dlang.org/show_bug.cgi?id=13262
1497 @system unittest
1499 static void fun(T)(Variant v){
1500 T x;
1501 v = x;
1502 auto r = v.get!(T);
1504 Variant v;
1505 fun!(shared(int))(v);
1506 fun!(shared(int)[])(v);
1508 static struct S1
1510 int c;
1511 string a;
1514 static struct S2
1516 string a;
1517 shared int[] b;
1520 static struct S3
1522 string a;
1523 shared int[] b;
1524 int c;
1527 fun!(S1)(v);
1528 fun!(shared(S1))(v);
1529 fun!(S2)(v);
1530 fun!(shared(S2))(v);
1531 fun!(S3)(v);
1532 fun!(shared(S3))(v);
1534 // ensure structs that are shared, but don't have shared postblits
1535 // can't be used.
1536 static struct S4
1538 int x;
1539 this(this) {x = 0;}
1542 fun!(S4)(v);
1543 static assert(!is(typeof(fun!(shared(S4))(v))));
1546 @safe unittest
1548 Algebraic!(int) x;
1550 static struct SafeS
1552 @safe ~this() {}
1555 Algebraic!(SafeS) y;
1558 // https://issues.dlang.org/show_bug.cgi?id=19986
1559 @system unittest
1561 VariantN!32 v;
1562 v = const(ubyte[33]).init;
1564 struct S
1566 ubyte[33] s;
1569 VariantN!32 v2;
1570 v2 = const(S).init;
1573 // https://issues.dlang.org/show_bug.cgi?id=21021
1574 @system unittest
1576 static struct S
1578 int h;
1579 int[5] array;
1580 alias h this;
1583 S msg;
1584 msg.array[] = 3;
1585 Variant a = msg;
1586 auto other = a.get!S;
1587 assert(msg.array[0] == 3);
1588 assert(other.array[0] == 3);
1591 // https://issues.dlang.org/show_bug.cgi?id=21231
1592 // Compatibility with -preview=fieldwise
1593 @system unittest
1595 static struct Empty
1597 bool opCmp(const scope ref Empty) const
1598 { return false; }
1601 Empty a, b;
1602 assert(a == b);
1603 assert(!(a < b));
1605 VariantN!(4, Empty) v = a;
1606 assert(v == b);
1607 assert(!(v < b));
1610 // Compatibility with -preview=fieldwise
1611 @system unittest
1613 static struct Empty
1615 bool opEquals(const scope ref Empty) const
1616 { return false; }
1619 Empty a, b;
1620 assert(a != b);
1622 VariantN!(4, Empty) v = a;
1623 assert(v != b);
1626 // https://issues.dlang.org/show_bug.cgi?id=22647
1627 // Can compare with 'null'
1628 @system unittest
1630 static struct Bar
1632 int* ptr;
1633 alias ptr this;
1636 static class Foo {}
1637 int* iptr;
1638 int[] arr;
1640 Variant v = Foo.init; // 'null'
1641 assert(v != null); // can only compare objects with 'null' by using 'is'
1643 v = iptr;
1644 assert(v == null); // pointers can be compared with 'null'
1646 v = arr;
1647 assert(v == null); // arrays can be compared with 'null'
1649 v = "";
1650 assert(v == null); // strings are arrays, an empty string is considered 'null'
1652 v = Bar.init;
1653 assert(v == null); // works with alias this
1655 v = [3];
1656 assert(v != null);
1657 assert(v > null);
1658 assert(v >= null);
1659 assert(!(v < null));
1663 _Algebraic data type restricted to a closed set of possible
1664 types. It's an alias for $(LREF VariantN) with an
1665 appropriately-constructed maximum size. `Algebraic` is
1666 useful when it is desirable to restrict what a discriminated type
1667 could hold to the end of defining simpler and more efficient
1668 manipulation.
1670 $(RED Warning: $(LREF Algebraic) is outdated and not recommended for use in new
1671 code. Instead, use $(REF SumType, std,sumtype).)
1673 template Algebraic(T...)
1675 alias Algebraic = VariantN!(maxSize!T, T);
1679 @system unittest
1681 auto v = Algebraic!(int, double, string)(5);
1682 assert(v.peek!(int));
1683 v = 3.14;
1684 assert(v.peek!(double));
1685 // auto x = v.peek!(long); // won't compile, type long not allowed
1686 // v = '1'; // won't compile, type char not allowed
1690 $(H4 Self-Referential Types)
1692 A useful and popular use of algebraic data structures is for defining $(LUCKY
1693 self-referential data structures), i.e. structures that embed references to
1694 values of their own type within.
1696 This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1697 reference to the type being defined is needed. The `Algebraic` instantiation
1698 will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1699 alpha renaming) on its constituent types, replacing `This`
1700 with the self-referenced type. The structure of the type involving `This` may
1701 be arbitrarily complex.
1703 @system unittest
1705 import std.typecons : Tuple, tuple;
1707 // A tree is either a leaf or a branch of two other trees
1708 alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
1709 Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
1710 Tree!int* right = tree.get!1[1];
1711 assert(*right == 43);
1713 // An object is a double, a string, or a hash of objects
1714 alias Obj = Algebraic!(double, string, This[string]);
1715 Obj obj = "hello";
1716 assert(obj.get!1 == "hello");
1717 obj = 42.0;
1718 assert(obj.get!0 == 42);
1719 obj = ["customer": Obj("John"), "paid": Obj(23.95)];
1720 assert(obj.get!2["customer"] == "John");
1723 private struct FakeComplexReal
1725 real re, im;
1729 Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1730 `char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1731 to hold all of D's predefined types unboxed, including all numeric types,
1732 pointers, delegates, and class references. You may want to use
1733 `VariantN` directly with a different maximum size either for
1734 storing larger types unboxed, or for saving memory.
1736 alias Variant = VariantN!(maxSize!(FakeComplexReal, char[], void delegate()));
1739 @system unittest
1741 Variant a; // Must assign before use, otherwise exception ensues
1742 // Initialize with an integer; make the type int
1743 Variant b = 42;
1744 assert(b.type == typeid(int));
1745 // Peek at the value
1746 assert(b.peek!(int) !is null && *b.peek!(int) == 42);
1747 // Automatically convert per language rules
1748 auto x = b.get!(real);
1750 // Assign any other type, including other variants
1751 a = b;
1752 a = 3.14;
1753 assert(a.type == typeid(double));
1754 // Implicit conversions work just as with built-in types
1755 assert(a < b);
1756 // Check for convertibility
1757 assert(!a.convertsTo!(int)); // double not convertible to int
1758 // Strings and all other arrays are supported
1759 a = "now I'm a string";
1760 assert(a == "now I'm a string");
1763 /// can also assign arrays
1764 @system unittest
1766 Variant a = new int[42];
1767 assert(a.length == 42);
1768 a[5] = 7;
1769 assert(a[5] == 7);
1772 /// Can also assign class values
1773 @system unittest
1775 Variant a;
1777 class Foo {}
1778 auto foo = new Foo;
1779 a = foo;
1780 assert(*a.peek!(Foo) == foo); // and full type information is preserved
1784 * Returns an array of variants constructed from `args`.
1786 * This is by design. During construction the `Variant` needs
1787 * static type information about the type being held, so as to store a
1788 * pointer to function for fast retrieval.
1790 Variant[] variantArray(T...)(T args)
1792 Variant[] result;
1793 foreach (arg; args)
1795 result ~= Variant(arg);
1797 return result;
1801 @system unittest
1803 auto a = variantArray(1, 3.14, "Hi!");
1804 assert(a[1] == 3.14);
1805 auto b = Variant(a); // variant array as variant
1806 assert(b[1] == 3.14);
1810 * Thrown in three cases:
1812 * $(OL $(LI An uninitialized `Variant` is used in any way except
1813 * assignment and `hasValue`;) $(LI A `get` or
1814 * `coerce` is attempted with an incompatible target type;)
1815 * $(LI A comparison between `Variant` objects of
1816 * incompatible types is attempted.))
1820 // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE
1821 static class VariantException : Exception
1823 /// The source type in the conversion or comparison
1824 TypeInfo source;
1825 /// The target type in the conversion or comparison
1826 TypeInfo target;
1827 this(string s)
1829 super(s);
1831 this(TypeInfo source, TypeInfo target)
1833 super("Variant: attempting to use incompatible types "
1834 ~ source.toString()
1835 ~ " and " ~ target.toString());
1836 this.source = source;
1837 this.target = target;
1842 @system unittest
1844 import std.exception : assertThrown;
1846 Variant v;
1848 // uninitialized use
1849 assertThrown!VariantException(v + 1);
1850 assertThrown!VariantException(v.length);
1852 // .get with an incompatible target type
1853 assertThrown!VariantException(Variant("a").get!int);
1855 // comparison between incompatible types
1856 assertThrown!VariantException(Variant(3) < Variant("a"));
1859 @system unittest
1861 alias W1 = This2Variant!(char, int, This[int]);
1862 alias W2 = AliasSeq!(int, char[int]);
1863 static assert(is(W1 == W2));
1865 alias var_t = Algebraic!(void, string);
1866 var_t foo = "quux";
1869 @system unittest
1871 alias A = Algebraic!(real, This[], This[int], This[This]);
1872 A v1, v2, v3;
1873 v2 = 5.0L;
1874 v3 = 42.0L;
1875 //v1 = [ v2 ][];
1876 auto v = v1.peek!(A[]);
1877 //writeln(v[0]);
1878 v1 = [ 9 : v3 ];
1879 //writeln(v1);
1880 v1 = [ v3 : v3 ];
1881 //writeln(v1);
1884 @system unittest
1886 import std.conv : ConvException;
1887 import std.exception : assertThrown, collectException;
1888 // try it with an oddly small size
1889 VariantN!(1) test;
1890 assert(test.size > 1);
1892 // variantArray tests
1893 auto heterogeneous = variantArray(1, 4.5, "hi");
1894 assert(heterogeneous.length == 3);
1895 auto variantArrayAsVariant = Variant(heterogeneous);
1896 assert(variantArrayAsVariant[0] == 1);
1897 assert(variantArrayAsVariant.length == 3);
1899 // array tests
1900 auto arr = Variant([1.2].dup);
1901 auto e = arr[0];
1902 assert(e == 1.2);
1903 arr[0] = 2.0;
1904 assert(arr[0] == 2);
1905 arr ~= 4.5;
1906 assert(arr[1] == 4.5);
1908 // general tests
1909 Variant a;
1910 auto b = Variant(5);
1911 assert(!b.peek!(real) && b.peek!(int));
1912 // assign
1913 a = *b.peek!(int);
1914 // comparison
1915 assert(a == b, a.type.toString() ~ " " ~ b.type.toString());
1916 auto c = Variant("this is a string");
1917 assert(a != c);
1918 // comparison via implicit conversions
1919 a = 42; b = 42.0; assert(a == b);
1921 // try failing conversions
1922 bool failed = false;
1925 auto d = c.get!(int);
1927 catch (Exception e)
1929 //writeln(stderr, e.toString);
1930 failed = true;
1932 assert(failed); // :o)
1934 // toString tests
1935 a = Variant(42); assert(a.toString() == "42");
1936 a = Variant(42.22); assert(a.toString() == "42.22");
1938 // coerce tests
1939 a = Variant(42.22); assert(a.coerce!(int) == 42);
1940 a = cast(short) 5; assert(a.coerce!(double) == 5);
1941 a = Variant("10"); assert(a.coerce!int == 10);
1943 a = Variant(1);
1944 assert(a.coerce!bool);
1945 a = Variant(0);
1946 assert(!a.coerce!bool);
1948 a = Variant(1.0);
1949 assert(a.coerce!bool);
1950 a = Variant(0.0);
1951 assert(!a.coerce!bool);
1952 a = Variant(float.init);
1953 assertThrown!ConvException(a.coerce!bool);
1955 a = Variant("true");
1956 assert(a.coerce!bool);
1957 a = Variant("false");
1958 assert(!a.coerce!bool);
1959 a = Variant("");
1960 assertThrown!ConvException(a.coerce!bool);
1962 // Object tests
1963 class B1 {}
1964 class B2 : B1 {}
1965 a = new B2;
1966 assert(a.coerce!(B1) !is null);
1967 a = new B1;
1968 assert(collectException(a.coerce!(B2) is null));
1969 a = cast(Object) new B2; // lose static type info; should still work
1970 assert(a.coerce!(B2) !is null);
1972 // struct Big { int a[45]; }
1973 // a = Big.init;
1975 // hash
1976 assert(a.toHash() != 0);
1979 // tests adapted from
1980 // http://www.dsource.org/projects/tango/browser/trunk/tango/core/Variant.d?rev=2601
1981 @system unittest
1983 Variant v;
1985 assert(!v.hasValue);
1986 v = 42;
1987 assert( v.peek!(int) );
1988 assert( v.convertsTo!(long) );
1989 assert( v.get!(int) == 42 );
1990 assert( v.get!(long) == 42L );
1991 assert( v.get!(ulong) == 42uL );
1993 v = "Hello, World!";
1994 assert( v.peek!(string) );
1996 assert( v.get!(string) == "Hello, World!" );
1997 assert(!is(char[] : wchar[]));
1998 assert( !v.convertsTo!(wchar[]) );
1999 assert( v.get!(string) == "Hello, World!" );
2001 // Literal arrays are dynamically-typed
2002 v = cast(int[4]) [1,2,3,4];
2003 assert( v.peek!(int[4]) );
2004 assert( v.get!(int[4]) == [1,2,3,4] );
2007 v = [1,2,3,4,5];
2008 assert( v.peek!(int[]) );
2009 assert( v.get!(int[]) == [1,2,3,4,5] );
2012 v = 3.1413;
2013 assert( v.peek!(double) );
2014 assert( v.convertsTo!(real) );
2015 //@@@ BUG IN COMPILER: DOUBLE SHOULD NOT IMPLICITLY CONVERT TO FLOAT
2016 assert( v.convertsTo!(float) );
2017 assert( *v.peek!(double) == 3.1413 );
2019 auto u = Variant(v);
2020 assert( u.peek!(double) );
2021 assert( *u.peek!(double) == 3.1413 );
2023 // operators
2024 v = 38;
2025 assert( v + 4 == 42 );
2026 assert( 4 + v == 42 );
2027 assert( v - 4 == 34 );
2028 assert( Variant(4) - v == -34 );
2029 assert( v * 2 == 76 );
2030 assert( 2 * v == 76 );
2031 assert( v / 2 == 19 );
2032 assert( Variant(2) / v == 0 );
2033 assert( v % 2 == 0 );
2034 assert( Variant(2) % v == 2 );
2035 assert( (v & 6) == 6 );
2036 assert( (6 & v) == 6 );
2037 assert( (v | 9) == 47 );
2038 assert( (9 | v) == 47 );
2039 assert( (v ^ 5) == 35 );
2040 assert( (5 ^ v) == 35 );
2041 assert( v << 1 == 76 );
2042 assert( Variant(1) << Variant(2) == 4 );
2043 assert( v >> 1 == 19 );
2044 assert( Variant(4) >> Variant(2) == 1 );
2045 assert( Variant("abc") ~ "def" == "abcdef" );
2046 assert( Variant("abc") ~ Variant("def") == "abcdef" );
2048 v = 38;
2049 v += 4;
2050 assert( v == 42 );
2051 v = 38; v -= 4; assert( v == 34 );
2052 v = 38; v *= 2; assert( v == 76 );
2053 v = 38; v /= 2; assert( v == 19 );
2054 v = 38; v %= 2; assert( v == 0 );
2055 v = 38; v &= 6; assert( v == 6 );
2056 v = 38; v |= 9; assert( v == 47 );
2057 v = 38; v ^= 5; assert( v == 35 );
2058 v = 38; v <<= 1; assert( v == 76 );
2059 v = 38; v >>= 1; assert( v == 19 );
2060 v = 38; v += 1; assert( v < 40 );
2062 v = "abc";
2063 v ~= "def";
2064 assert( v == "abcdef", *v.peek!(char[]) );
2065 assert( Variant(0) < Variant(42) );
2066 assert( Variant(42) > Variant(0) );
2067 assert( Variant(42) > Variant(0.1) );
2068 assert( Variant(42.1) > Variant(1) );
2069 assert( Variant(21) == Variant(21) );
2070 assert( Variant(0) != Variant(42) );
2071 assert( Variant("bar") == Variant("bar") );
2072 assert( Variant("foo") != Variant("bar") );
2075 auto v1 = Variant(42);
2076 auto v2 = Variant("foo");
2078 int[Variant] hash;
2079 hash[v1] = 0;
2080 hash[v2] = 1;
2082 assert( hash[v1] == 0 );
2083 assert( hash[v2] == 1 );
2087 int[char[]] hash;
2088 hash["a"] = 1;
2089 hash["b"] = 2;
2090 hash["c"] = 3;
2091 Variant vhash = hash;
2093 assert( vhash.get!(int[char[]])["a"] == 1 );
2094 assert( vhash.get!(int[char[]])["b"] == 2 );
2095 assert( vhash.get!(int[char[]])["c"] == 3 );
2099 @system unittest
2101 // check comparisons incompatible with AllowedTypes
2102 Algebraic!int v = 2;
2104 assert(v == 2);
2105 assert(v < 3);
2106 static assert(!__traits(compiles, () => v == long.max));
2107 static assert(!__traits(compiles, () => v == null));
2108 static assert(!__traits(compiles, () => v < long.max));
2109 static assert(!__traits(compiles, () => v > null));
2112 // https://issues.dlang.org/show_bug.cgi?id=1558
2113 @system unittest
2115 Variant va=1;
2116 Variant vb=-2;
2117 assert((va+vb).get!(int) == -1);
2118 assert((va-vb).get!(int) == 3);
2121 @system unittest
2123 Variant a;
2124 a=5;
2125 Variant b;
2126 b=a;
2127 Variant[] c;
2128 c = variantArray(1, 2, 3.0, "hello", 4);
2129 assert(c[3] == "hello");
2132 @system unittest
2134 Variant v = 5;
2135 assert(!__traits(compiles, v.coerce!(bool delegate())));
2139 @system unittest
2141 struct Huge {
2142 real a, b, c, d, e, f, g;
2145 Huge huge;
2146 huge.e = 42;
2147 Variant v;
2148 v = huge; // Compile time error.
2149 assert(v.get!(Huge).e == 42);
2152 @system unittest
2154 const x = Variant(42);
2155 auto y1 = x.get!(const int);
2156 // @@@BUG@@@
2157 //auto y2 = x.get!(immutable int)();
2160 // test iteration
2161 @system unittest
2163 auto v = Variant([ 1, 2, 3, 4 ][]);
2164 auto j = 0;
2165 foreach (int i; v)
2167 assert(i == ++j);
2169 assert(j == 4);
2172 // test convertibility
2173 @system unittest
2175 auto v = Variant("abc".dup);
2176 assert(v.convertsTo!(char[]));
2179 // https://issues.dlang.org/show_bug.cgi?id=5424
2180 @system unittest
2182 interface A {
2183 void func1();
2185 static class AC: A {
2186 void func1() {
2190 A a = new AC();
2191 a.func1();
2192 Variant b = Variant(a);
2195 // https://issues.dlang.org/show_bug.cgi?id=7070
2196 @system unittest
2198 Variant v;
2199 v = null;
2202 // Class and interface opEquals, https://issues.dlang.org/show_bug.cgi?id=12157
2203 @system unittest
2205 class Foo { }
2207 class DerivedFoo : Foo { }
2209 Foo f1 = new Foo();
2210 Foo f2 = new DerivedFoo();
2212 Variant v1 = f1, v2 = f2;
2213 assert(v1 == f1);
2214 assert(v1 != new Foo());
2215 assert(v1 != f2);
2216 assert(v2 != v1);
2217 assert(v2 == f2);
2220 // Const parameters with opCall, https://issues.dlang.org/show_bug.cgi?id=11361
2221 @system unittest
2223 static string t1(string c) {
2224 return c ~ "a";
2227 static const(char)[] t2(const(char)[] p) {
2228 return p ~ "b";
2231 static char[] t3(int p) {
2232 import std.conv : text;
2233 return p.text.dup;
2236 Variant v1 = &t1;
2237 Variant v2 = &t2;
2238 Variant v3 = &t3;
2240 assert(v1("abc") == "abca");
2241 assert(v1("abc").type == typeid(string));
2242 assert(v2("abc") == "abcb");
2244 assert(v2(cast(char[])("abc".dup)) == "abcb");
2245 assert(v2("abc").type == typeid(const(char)[]));
2247 assert(v3(4) == ['4']);
2248 assert(v3(4).type == typeid(char[]));
2251 // https://issues.dlang.org/show_bug.cgi?id=12071
2252 @system unittest
2254 static struct Structure { int data; }
2255 alias VariantTest = Algebraic!(Structure delegate() pure nothrow @nogc @safe);
2257 bool called = false;
2258 Structure example() pure nothrow @nogc @safe
2260 called = true;
2261 return Structure.init;
2263 auto m = VariantTest(&example);
2264 m();
2265 assert(called);
2268 // Ordering comparisons of incompatible types
2269 // e.g. https://issues.dlang.org/show_bug.cgi?id=7990
2270 @system unittest
2272 import std.exception : assertThrown;
2273 assertThrown!VariantException(Variant(3) < "a");
2274 assertThrown!VariantException("a" < Variant(3));
2275 assertThrown!VariantException(Variant(3) < Variant("a"));
2277 assertThrown!VariantException(Variant.init < Variant(3));
2278 assertThrown!VariantException(Variant(3) < Variant.init);
2281 // Handling of unordered types
2282 // https://issues.dlang.org/show_bug.cgi?id=9043
2283 @system unittest
2285 import std.exception : assertThrown;
2286 static struct A { int a; }
2288 assert(Variant(A(3)) != A(4));
2290 assertThrown!VariantException(Variant(A(3)) < A(4));
2291 assertThrown!VariantException(A(3) < Variant(A(4)));
2292 assertThrown!VariantException(Variant(A(3)) < Variant(A(4)));
2295 // Handling of empty types and arrays
2296 // https://issues.dlang.org/show_bug.cgi?id=10958
2297 @system unittest
2299 class EmptyClass { }
2300 struct EmptyStruct { }
2301 alias EmptyArray = void[0];
2302 alias Alg = Algebraic!(EmptyClass, EmptyStruct, EmptyArray);
2304 Variant testEmpty(T)()
2306 T inst;
2307 Variant v = inst;
2308 assert(v.get!T == inst);
2309 assert(v.peek!T !is null);
2310 assert(*v.peek!T == inst);
2311 Alg alg = inst;
2312 assert(alg.get!T == inst);
2313 return v;
2316 testEmpty!EmptyClass();
2317 testEmpty!EmptyStruct();
2318 testEmpty!EmptyArray();
2320 // EmptyClass/EmptyStruct sizeof is 1, so we have this to test just size 0.
2321 EmptyArray arr = EmptyArray.init;
2322 Algebraic!(EmptyArray) a = arr;
2323 assert(a.length == 0);
2324 assert(a.get!EmptyArray == arr);
2327 // Handling of void function pointers / delegates
2328 // https://issues.dlang.org/show_bug.cgi?id=11360
2329 @system unittest
2331 static void t1() { }
2332 Variant v = &t1;
2333 assert(v() == Variant.init);
2335 static int t2() { return 3; }
2336 Variant v2 = &t2;
2337 assert(v2() == 3);
2340 // Using peek for large structs
2341 // https://issues.dlang.org/show_bug.cgi?id=8580
2342 @system unittest
2344 struct TestStruct(bool pad)
2346 int val1;
2347 static if (pad)
2348 ubyte[Variant.size] padding;
2349 int val2;
2352 void testPeekWith(T)()
2354 T inst;
2355 inst.val1 = 3;
2356 inst.val2 = 4;
2357 Variant v = inst;
2358 T* original = v.peek!T;
2359 assert(original.val1 == 3);
2360 assert(original.val2 == 4);
2361 original.val1 = 6;
2362 original.val2 = 8;
2363 T modified = v.get!T;
2364 assert(modified.val1 == 6);
2365 assert(modified.val2 == 8);
2368 testPeekWith!(TestStruct!false)();
2369 testPeekWith!(TestStruct!true)();
2372 // https://issues.dlang.org/show_bug.cgi?id=18780
2373 @system unittest
2375 int x = 7;
2376 Variant a = x;
2377 assert(a.convertsTo!ulong);
2378 assert(a.convertsTo!uint);
2382 * Applies a delegate or function to the given $(LREF Algebraic) depending on the held type,
2383 * ensuring that all types are handled by the visiting functions.
2385 * The delegate or function having the currently held value as parameter is called
2386 * with `variant`'s current value. Visiting handlers are passed
2387 * in the template parameter list.
2388 * It is statically ensured that all held types of
2389 * `variant` are handled across all handlers.
2390 * `visit` allows delegates and static functions to be passed
2391 * as parameters.
2393 * If a function with an untyped parameter is specified, this function is called
2394 * when the variant contains a type that does not match any other function.
2395 * This can be used to apply the same function across multiple possible types.
2396 * Exactly one generic function is allowed.
2398 * If a function without parameters is specified, this function is called
2399 * when `variant` doesn't hold a value. Exactly one parameter-less function
2400 * is allowed.
2402 * Duplicate overloads matching the same type in one of the visitors are disallowed.
2404 * Returns: The return type of visit is deduced from the visiting functions and must be
2405 * the same across all overloads.
2406 * Throws: $(LREF VariantException) if `variant` doesn't hold a value and no
2407 * parameter-less fallback function is specified.
2409 template visit(Handlers...)
2410 if (Handlers.length > 0)
2413 auto visit(VariantType)(VariantType variant)
2414 if (isAlgebraic!VariantType)
2416 return visitImpl!(true, VariantType, Handlers)(variant);
2421 @system unittest
2423 Algebraic!(int, string) variant;
2425 variant = 10;
2426 assert(variant.visit!((string s) => cast(int) s.length,
2427 (int i) => i)()
2428 == 10);
2429 variant = "string";
2430 assert(variant.visit!((int i) => i,
2431 (string s) => cast(int) s.length)()
2432 == 6);
2434 // Error function usage
2435 Algebraic!(int, string) emptyVar;
2436 auto rslt = emptyVar.visit!((string s) => cast(int) s.length,
2437 (int i) => i,
2438 () => -1)();
2439 assert(rslt == -1);
2441 // Generic function usage
2442 Algebraic!(int, float, real) number = 2;
2443 assert(number.visit!(x => x += 1) == 3);
2445 // Generic function for int/float with separate behavior for string
2446 Algebraic!(int, float, string) something = 2;
2447 assert(something.visit!((string s) => s.length, x => x) == 2); // generic
2448 something = "asdf";
2449 assert(something.visit!((string s) => s.length, x => x) == 4); // string
2451 // Generic handler and empty handler
2452 Algebraic!(int, float, real) empty2;
2453 assert(empty2.visit!(x => x + 1, () => -1) == -1);
2456 @system unittest
2458 Algebraic!(size_t, string) variant;
2460 // not all handled check
2461 static assert(!__traits(compiles, variant.visit!((size_t i){ })() ));
2463 variant = cast(size_t) 10;
2464 auto which = 0;
2465 variant.visit!( (string s) => which = 1,
2466 (size_t i) => which = 0
2467 )();
2469 // integer overload was called
2470 assert(which == 0);
2472 // mustn't compile as generic Variant not supported
2473 Variant v;
2474 static assert(!__traits(compiles, v.visit!((string s) => which = 1,
2475 (size_t i) => which = 0
2479 static size_t func(string s) {
2480 return s.length;
2483 variant = "test";
2484 assert( 4 == variant.visit!(func,
2485 (size_t i) => i
2486 )());
2488 Algebraic!(int, float, string) variant2 = 5.0f;
2489 // Shouldn' t compile as float not handled by visitor.
2490 static assert(!__traits(compiles, variant2.visit!(
2491 (int _) {},
2492 (string _) {})()));
2494 Algebraic!(size_t, string, float) variant3;
2495 variant3 = 10.0f;
2496 auto floatVisited = false;
2498 assert(variant3.visit!(
2499 (float f) { floatVisited = true; return cast(size_t) f; },
2500 func,
2501 (size_t i) { return i; }
2502 )() == 10);
2503 assert(floatVisited == true);
2505 Algebraic!(float, string) variant4;
2507 assert(variant4.visit!(func, (float f) => cast(size_t) f, () => size_t.max)() == size_t.max);
2509 // double error func check
2510 static assert(!__traits(compiles,
2511 visit!(() => size_t.max, func, (float f) => cast(size_t) f, () => size_t.max)(variant4))
2515 // disallow providing multiple generic handlers to visit
2516 // disallow a generic handler that does not apply to all types
2517 @system unittest
2519 Algebraic!(int, float) number = 2;
2520 // ok, x + 1 valid for int and float
2521 static assert( __traits(compiles, number.visit!(x => x + 1)));
2522 // bad, two generic handlers
2523 static assert(!__traits(compiles, number.visit!(x => x + 1, x => x + 2)));
2524 // bad, x ~ "a" does not apply to int or float
2525 static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2526 // bad, x ~ "a" does not apply to int or float
2527 static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2529 Algebraic!(int, string) maybenumber = 2;
2530 // ok, x ~ "a" valid for string, x + 1 valid for int, only 1 generic
2531 static assert( __traits(compiles, maybenumber.visit!((string x) => x ~ "a", x => "foobar"[0 .. x + 1])));
2532 // bad, x ~ "a" valid for string but not int
2533 static assert(!__traits(compiles, maybenumber.visit!(x => x ~ "a")));
2534 // bad, two generics, each only applies in one case
2535 static assert(!__traits(compiles, maybenumber.visit!(x => x + 1, x => x ~ "a")));
2539 * Behaves as $(LREF visit) but doesn't enforce that all types are handled
2540 * by the visiting functions.
2542 * If a parameter-less function is specified it is called when
2543 * either `variant` doesn't hold a value or holds a type
2544 * which isn't handled by the visiting functions.
2546 * Returns: The return type of tryVisit is deduced from the visiting functions and must be
2547 * the same across all overloads.
2548 * Throws: $(LREF VariantException) if `variant` doesn't hold a value or
2549 * `variant` holds a value which isn't handled by the visiting functions,
2550 * when no parameter-less fallback function is specified.
2552 template tryVisit(Handlers...)
2553 if (Handlers.length > 0)
2556 auto tryVisit(VariantType)(VariantType variant)
2557 if (isAlgebraic!VariantType)
2559 return visitImpl!(false, VariantType, Handlers)(variant);
2564 @system unittest
2566 Algebraic!(int, string) variant;
2568 variant = 10;
2569 auto which = -1;
2570 variant.tryVisit!((int i) { which = 0; })();
2571 assert(which == 0);
2573 // Error function usage
2574 variant = "test";
2575 variant.tryVisit!((int i) { which = 0; },
2576 () { which = -100; })();
2577 assert(which == -100);
2580 @system unittest
2582 import std.exception : assertThrown;
2583 Algebraic!(int, string) variant;
2585 variant = 10;
2586 auto which = -1;
2587 variant.tryVisit!((int i){ which = 0; })();
2589 assert(which == 0);
2591 variant = "test";
2593 assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })());
2595 void errorfunc()
2597 which = -1;
2600 variant.tryVisit!((int i) { which = 0; }, errorfunc)();
2602 assert(which == -1);
2605 private template isAlgebraic(Type)
2607 static if (is(Type _ == VariantN!T, T...))
2608 enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam
2609 else
2610 enum isAlgebraic = false;
2613 @system unittest
2615 static assert(!isAlgebraic!(Variant));
2616 static assert( isAlgebraic!(Algebraic!(string)));
2617 static assert( isAlgebraic!(Algebraic!(int, int[])));
2620 private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2621 if (isAlgebraic!VariantType && Handler.length > 0)
2623 alias AllowedTypes = VariantType.AllowedTypes;
2627 * Returns: Struct where `indices` is an array which
2628 * contains at the n-th position the index in Handler which takes the
2629 * n-th type of AllowedTypes. If an Handler doesn't match an
2630 * AllowedType, -1 is set. If a function in the delegates doesn't
2631 * have parameters, the field `exceptionFuncIdx` is set;
2632 * otherwise it's -1.
2634 auto visitGetOverloadMap()
2636 struct Result {
2637 int[AllowedTypes.length] indices;
2638 int exceptionFuncIdx = -1;
2639 int generalFuncIdx = -1;
2642 Result result;
2644 enum int nonmatch = ()
2646 foreach (int dgidx, dg; Handler)
2648 bool found = false;
2649 foreach (T; AllowedTypes)
2651 found |= __traits(compiles, { static assert(isSomeFunction!(dg!T)); });
2652 found |= __traits(compiles, (T t) { dg(t); });
2653 found |= __traits(compiles, dg());
2655 if (!found) return dgidx;
2657 return -1;
2658 }();
2659 static assert(nonmatch == -1, "No match for visit handler #"~
2660 nonmatch.stringof~" ("~Handler[nonmatch].stringof~")");
2662 foreach (tidx, T; AllowedTypes)
2664 bool added = false;
2665 foreach (dgidx, dg; Handler)
2667 // Handle normal function objects
2668 static if (isSomeFunction!dg)
2670 alias Params = Parameters!dg;
2671 static if (Params.length == 0)
2673 // Just check exception functions in the first
2674 // inner iteration (over delegates)
2675 if (tidx > 0)
2676 continue;
2677 else
2679 if (result.exceptionFuncIdx != -1)
2680 assert(false, "duplicate parameter-less (error-)function specified");
2681 result.exceptionFuncIdx = dgidx;
2684 else static if (is(Params[0] == T) || is(Unqual!(Params[0]) == T))
2686 if (added)
2687 assert(false, "duplicate overload specified for type '" ~ T.stringof ~ "'");
2689 added = true;
2690 result.indices[tidx] = dgidx;
2693 else static if (__traits(compiles, { static assert(isSomeFunction!(dg!T)); }))
2695 assert(result.generalFuncIdx == -1 ||
2696 result.generalFuncIdx == dgidx,
2697 "Only one generic visitor function is allowed");
2698 result.generalFuncIdx = dgidx;
2700 // Handle composite visitors with opCall overloads
2703 if (!added)
2704 result.indices[tidx] = -1;
2707 return result;
2710 enum HandlerOverloadMap = visitGetOverloadMap();
2712 if (!variant.hasValue)
2714 // Call the exception function. The HandlerOverloadMap
2715 // will have its exceptionFuncIdx field set to value != -1 if an
2716 // exception function has been specified; otherwise we just through an exception.
2717 static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2718 return Handler[ HandlerOverloadMap.exceptionFuncIdx ]();
2719 else
2720 throw new VariantException("variant must hold a value before being visited.");
2723 foreach (idx, T; AllowedTypes)
2725 if (auto ptr = variant.peek!T)
2727 enum dgIdx = HandlerOverloadMap.indices[idx];
2729 static if (dgIdx == -1)
2731 static if (HandlerOverloadMap.generalFuncIdx >= 0)
2732 return Handler[HandlerOverloadMap.generalFuncIdx](*ptr);
2733 else static if (Strict)
2734 static assert(false, "overload for type '" ~ T.stringof ~ "' hasn't been specified");
2735 else static if (HandlerOverloadMap.exceptionFuncIdx != -1)
2736 return Handler[HandlerOverloadMap.exceptionFuncIdx]();
2737 else
2738 throw new VariantException(
2739 "variant holds value of type '"
2740 ~ T.stringof ~
2741 "' but no visitor has been provided"
2744 else
2746 return Handler[ dgIdx ](*ptr);
2751 assert(false);
2754 // https://issues.dlang.org/show_bug.cgi?id=21253
2755 @system unittest
2757 static struct A { int n; }
2758 static struct B { }
2760 auto a = Algebraic!(A, B)(B());
2761 assert(a.visit!(
2762 (B _) => 42,
2763 (a ) => a.n
2764 ) == 42);
2767 @system unittest
2769 // validate that visit can be called with a const type
2770 struct Foo { int depth; }
2771 struct Bar { int depth; }
2772 alias FooBar = Algebraic!(Foo, Bar);
2774 int depth(in FooBar fb) {
2775 return fb.visit!((Foo foo) => foo.depth,
2776 (Bar bar) => bar.depth);
2779 FooBar fb = Foo(3);
2780 assert(depth(fb) == 3);
2783 // https://issues.dlang.org/show_bug.cgi?id=16383
2784 @system unittest
2786 class Foo {this() immutable {}}
2787 alias V = Algebraic!(immutable Foo);
2789 auto x = V(new immutable Foo).visit!(
2790 (immutable(Foo) _) => 3
2792 assert(x == 3);
2795 // https://issues.dlang.org/show_bug.cgi?id=5310
2796 @system unittest
2798 const Variant a;
2799 assert(a == a);
2800 Variant b;
2801 assert(a == b);
2802 assert(b == a);
2805 @system unittest
2807 const Variant a = [2];
2808 assert(a[0] == 2);
2811 // https://issues.dlang.org/show_bug.cgi?id=10017
2812 @system unittest
2814 static struct S
2816 ubyte[Variant.size + 1] s;
2819 Variant v1, v2;
2820 v1 = S(); // the payload is allocated on the heap
2821 v2 = v1; // AssertError: target must be non-null
2822 assert(v1 == v2);
2825 // https://issues.dlang.org/show_bug.cgi?id=7069
2826 @system unittest
2828 import std.exception : assertThrown;
2829 Variant v;
2831 int i = 10;
2832 v = i;
2833 static foreach (qual; AliasSeq!(Alias, ConstOf))
2835 assert(v.get!(qual!int) == 10);
2836 assert(v.get!(qual!float) == 10.0f);
2838 static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2840 assertThrown!VariantException(v.get!(qual!int));
2843 const(int) ci = 20;
2844 v = ci;
2845 static foreach (qual; AliasSeq!(ConstOf))
2847 assert(v.get!(qual!int) == 20);
2848 assert(v.get!(qual!float) == 20.0f);
2850 static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2852 assertThrown!VariantException(v.get!(qual!int));
2853 assertThrown!VariantException(v.get!(qual!float));
2856 immutable(int) ii = ci;
2857 v = ii;
2858 static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2860 assert(v.get!(qual!int) == 20);
2861 assert(v.get!(qual!float) == 20.0f);
2863 static foreach (qual; AliasSeq!(Alias, SharedOf))
2865 assertThrown!VariantException(v.get!(qual!int));
2866 assertThrown!VariantException(v.get!(qual!float));
2869 int[] ai = [1,2,3];
2870 v = ai;
2871 static foreach (qual; AliasSeq!(Alias, ConstOf))
2873 assert(v.get!(qual!(int[])) == [1,2,3]);
2874 assert(v.get!(qual!(int)[]) == [1,2,3]);
2876 static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2878 assertThrown!VariantException(v.get!(qual!(int[])));
2879 assertThrown!VariantException(v.get!(qual!(int)[]));
2882 const(int[]) cai = [4,5,6];
2883 v = cai;
2884 static foreach (qual; AliasSeq!(ConstOf))
2886 assert(v.get!(qual!(int[])) == [4,5,6]);
2887 assert(v.get!(qual!(int)[]) == [4,5,6]);
2889 static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2891 assertThrown!VariantException(v.get!(qual!(int[])));
2892 assertThrown!VariantException(v.get!(qual!(int)[]));
2895 immutable(int[]) iai = [7,8,9];
2896 v = iai;
2897 //assert(v.get!(immutable(int[])) == [7,8,9]); // Bug ??? runtime error
2898 assert(v.get!(immutable(int)[]) == [7,8,9]);
2899 assert(v.get!(const(int[])) == [7,8,9]);
2900 assert(v.get!(const(int)[]) == [7,8,9]);
2901 //assert(v.get!(shared(const(int[]))) == cast(shared const)[7,8,9]); // Bug ??? runtime error
2902 //assert(v.get!(shared(const(int))[]) == cast(shared const)[7,8,9]); // Bug ??? runtime error
2903 static foreach (qual; AliasSeq!(Alias))
2905 assertThrown!VariantException(v.get!(qual!(int[])));
2906 assertThrown!VariantException(v.get!(qual!(int)[]));
2909 class A {}
2910 class B : A {}
2911 B b = new B();
2912 v = b;
2913 static foreach (qual; AliasSeq!(Alias, ConstOf))
2915 assert(v.get!(qual!B) is b);
2916 assert(v.get!(qual!A) is b);
2917 assert(v.get!(qual!Object) is b);
2919 static foreach (qual; AliasSeq!(ImmutableOf, SharedOf, SharedConstOf))
2921 assertThrown!VariantException(v.get!(qual!B));
2922 assertThrown!VariantException(v.get!(qual!A));
2923 assertThrown!VariantException(v.get!(qual!Object));
2926 const(B) cb = new B();
2927 v = cb;
2928 static foreach (qual; AliasSeq!(ConstOf))
2930 assert(v.get!(qual!B) is cb);
2931 assert(v.get!(qual!A) is cb);
2932 assert(v.get!(qual!Object) is cb);
2934 static foreach (qual; AliasSeq!(Alias, ImmutableOf, SharedOf, SharedConstOf))
2936 assertThrown!VariantException(v.get!(qual!B));
2937 assertThrown!VariantException(v.get!(qual!A));
2938 assertThrown!VariantException(v.get!(qual!Object));
2941 immutable(B) ib = new immutable(B)();
2942 v = ib;
2943 static foreach (qual; AliasSeq!(ImmutableOf, ConstOf, SharedConstOf))
2945 assert(v.get!(qual!B) is ib);
2946 assert(v.get!(qual!A) is ib);
2947 assert(v.get!(qual!Object) is ib);
2949 static foreach (qual; AliasSeq!(Alias, SharedOf))
2951 assertThrown!VariantException(v.get!(qual!B));
2952 assertThrown!VariantException(v.get!(qual!A));
2953 assertThrown!VariantException(v.get!(qual!Object));
2956 shared(B) sb = new shared B();
2957 v = sb;
2958 static foreach (qual; AliasSeq!(SharedOf, SharedConstOf))
2960 assert(v.get!(qual!B) is sb);
2961 assert(v.get!(qual!A) is sb);
2962 assert(v.get!(qual!Object) is sb);
2964 static foreach (qual; AliasSeq!(Alias, ImmutableOf, ConstOf))
2966 assertThrown!VariantException(v.get!(qual!B));
2967 assertThrown!VariantException(v.get!(qual!A));
2968 assertThrown!VariantException(v.get!(qual!Object));
2971 shared(const(B)) scb = new shared const B();
2972 v = scb;
2973 static foreach (qual; AliasSeq!(SharedConstOf))
2975 assert(v.get!(qual!B) is scb);
2976 assert(v.get!(qual!A) is scb);
2977 assert(v.get!(qual!Object) is scb);
2979 static foreach (qual; AliasSeq!(Alias, ConstOf, ImmutableOf, SharedOf))
2981 assertThrown!VariantException(v.get!(qual!B));
2982 assertThrown!VariantException(v.get!(qual!A));
2983 assertThrown!VariantException(v.get!(qual!Object));
2987 // https://issues.dlang.org/show_bug.cgi?id=12540
2988 @system unittest
2990 static struct DummyScope
2992 alias Alias12540 = Algebraic!Class12540;
2994 static class Class12540
2996 Alias12540 entity;
3001 @system unittest
3003 // https://issues.dlang.org/show_bug.cgi?id=10194
3004 // Also test for elaborate copying
3005 static struct S
3007 @disable this();
3008 this(int dummy)
3010 ++cnt;
3013 this(this)
3015 ++cnt;
3018 @disable S opAssign();
3020 ~this()
3022 --cnt;
3023 assert(cnt >= 0);
3025 static int cnt = 0;
3029 Variant v;
3031 v = S(0);
3032 assert(S.cnt == 1);
3034 assert(S.cnt == 1);
3036 // assigning a new value should destroy the existing one
3037 v = 0;
3038 assert(S.cnt == 0);
3040 // destroying the variant should destroy it's current value
3041 v = S(0);
3042 assert(S.cnt == 1);
3044 assert(S.cnt == 0);
3047 @system unittest
3049 // https://issues.dlang.org/show_bug.cgi?id=13300
3050 static struct S
3052 this(this) {}
3053 ~this() {}
3056 static assert( hasElaborateCopyConstructor!(Variant));
3057 static assert(!hasElaborateCopyConstructor!(Algebraic!bool));
3058 static assert( hasElaborateCopyConstructor!(Algebraic!S));
3059 static assert( hasElaborateCopyConstructor!(Algebraic!(bool, S)));
3061 static assert( hasElaborateDestructor!(Variant));
3062 static assert(!hasElaborateDestructor!(Algebraic!bool));
3063 static assert( hasElaborateDestructor!(Algebraic!S));
3064 static assert( hasElaborateDestructor!(Algebraic!(bool, S)));
3066 import std.array;
3067 alias Value = Algebraic!bool;
3069 static struct T
3071 Value value;
3072 @disable this();
3074 auto a = appender!(T[]);
3077 // https://issues.dlang.org/show_bug.cgi?id=13871
3078 @system unittest
3080 alias A = Algebraic!(int, typeof(null));
3081 static struct B { A value; }
3082 alias C = std.variant.Algebraic!B;
3084 C var;
3085 var = C(B());
3088 @system unittest
3090 import std.exception : assertThrown, assertNotThrown;
3091 // Make sure Variant can handle types with opDispatch but no length field.
3092 struct SWithNoLength
3094 void opDispatch(string s)() { }
3097 struct SWithLength
3099 @property int opDispatch(string s)()
3101 // Assume that s == "length"
3102 return 5; // Any value is OK for test.
3106 SWithNoLength sWithNoLength;
3107 Variant v = sWithNoLength;
3108 assertThrown!VariantException(v.length);
3110 SWithLength sWithLength;
3111 v = sWithLength;
3112 assertNotThrown!VariantException(v.get!SWithLength.length);
3113 assertThrown!VariantException(v.length);
3116 // https://issues.dlang.org/show_bug.cgi?id=13534
3117 @system unittest
3119 static assert(!__traits(compiles, () @safe {
3120 auto foo() @system { return 3; }
3121 auto v = Variant(&foo);
3122 v(); // foo is called in safe code!?
3123 }));
3126 // https://issues.dlang.org/show_bug.cgi?id=15039
3127 @system unittest
3129 import std.typecons;
3130 import std.variant;
3132 alias IntTypedef = Typedef!int;
3133 alias Obj = Algebraic!(int, IntTypedef, This[]);
3135 Obj obj = 1;
3137 obj.visit!(
3138 (int x) {},
3139 (IntTypedef x) {},
3140 (Obj[] x) {},
3144 // https://issues.dlang.org/show_bug.cgi?id=15791
3145 @system unittest
3147 int n = 3;
3148 struct NS1 { int foo() { return n + 10; } }
3149 struct NS2 { int foo() { return n * 10; } }
3151 Variant v;
3152 v = NS1();
3153 assert(v.get!NS1.foo() == 13);
3154 v = NS2();
3155 assert(v.get!NS2.foo() == 30);
3158 // https://issues.dlang.org/show_bug.cgi?id=15827
3159 @system unittest
3161 static struct Foo15827 { Variant v; this(Foo15827 v) {} }
3162 Variant v = Foo15827.init;
3165 // https://issues.dlang.org/show_bug.cgi?id=18934
3166 @system unittest
3168 static struct S
3170 const int x;
3173 auto s = S(42);
3174 Variant v = s;
3175 auto s2 = v.get!S;
3176 assert(s2.x == 42);
3177 Variant v2 = v; // support copying from one variant to the other
3178 v2 = S(2);
3179 v = v2;
3180 assert(v.get!S.x == 2);
3183 // https://issues.dlang.org/show_bug.cgi?id=19200
3184 @system unittest
3186 static struct S
3188 static int opBinaryRight(string op : "|", T)(T rhs)
3190 return 3;
3194 S s;
3195 Variant v;
3196 auto b = v | s;
3197 assert(b == 3);
3200 // https://issues.dlang.org/show_bug.cgi?id=11061
3201 @system unittest
3203 int[4] el = [0, 1, 2, 3];
3204 int[3] nl = [0, 1, 2];
3205 Variant v1 = el;
3206 assert(v1 == el); // Compare Var(static) to static
3207 assert(v1 != nl); // Compare static arrays of different length
3208 assert(v1 == [0, 1, 2, 3]); // Compare Var(static) to dynamic.
3209 assert(v1 != [0, 1, 2]);
3210 int[] dyn = [0, 1, 2, 3];
3211 v1 = dyn;
3212 assert(v1 == el); // Compare Var(dynamic) to static.
3213 assert(v1 == [0, 1] ~ [2, 3]); // Compare Var(dynamic) to dynamic
3216 // https://issues.dlang.org/show_bug.cgi?id=15940
3217 @system unittest
3219 class C { }
3220 struct S
3222 C a;
3223 alias a this;
3225 S s = S(new C());
3226 auto v = Variant(s); // compile error
3229 @system unittest
3231 // Test if we don't have scoping issues.
3232 Variant createVariant(int[] input)
3234 int[2] el = [input[0], input[1]];
3235 Variant v = el;
3236 return v;
3238 Variant v = createVariant([0, 1]);
3239 createVariant([2, 3]);
3240 assert(v == [0,1]);
3243 // https://issues.dlang.org/show_bug.cgi?id=19994
3244 @safe unittest
3246 alias Inner = Algebraic!(This*);
3247 alias Outer = Algebraic!(Inner, This*);
3249 static assert(is(Outer.AllowedTypes == AliasSeq!(Inner, Outer*)));
3252 // https://issues.dlang.org/show_bug.cgi?id=21296
3253 @system unittest
3255 immutable aa = ["0": 0];
3256 auto v = Variant(aa); // compile error