]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/src/std/variant.d
Add D front-end, libphobos library, and D2 testsuite.
[thirdparty/gcc.git] / libphobos / src / std / variant.d
1 // Written in the D programming language.
2
3 /**
4 This module implements a
5 $(HTTP erdani.org/publications/cuj-04-2002.html,discriminated union)
6 type (a.k.a.
7 $(HTTP en.wikipedia.org/wiki/Tagged_union,tagged union),
8 $(HTTP en.wikipedia.org/wiki/Algebraic_data_type,algebraic type)).
9 Such types are useful
10 for type-uniform binary interfaces, interfacing with scripting
11 languages, and comfortable exploratory programming.
12
13 A $(LREF Variant) object can hold a value of any type, with very few
14 restrictions (such as `shared` types and noncopyable types). Setting the value
15 is as immediate as assigning to the `Variant` object. To read back the value of
16 the appropriate type `T`, use the $(LREF get!T) call. To query whether a
17 `Variant` currently holds a value of type `T`, use $(LREF peek!T). To fetch the
18 exact type currently held, call $(LREF type), which returns the `TypeInfo` of
19 the current value.
20
21 In addition to $(LREF Variant), this module also defines the $(LREF Algebraic)
22 type constructor. Unlike `Variant`, `Algebraic` only allows a finite set of
23 types, which are specified in the instantiation (e.g. $(D Algebraic!(int,
24 string)) may only hold an `int` or a `string`).
25
26 Credits: Reviewed by Brad Roberts. Daniel Keep provided a detailed code review
27 prompting the following improvements: (1) better support for arrays; (2) support
28 for associative arrays; (3) friendlier behavior towards the garbage collector.
29 Copyright: Copyright Andrei Alexandrescu 2007 - 2015.
30 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
31 Authors: $(HTTP erdani.org, Andrei Alexandrescu)
32 Source: $(PHOBOSSRC std/_variant.d)
33 */
34 module std.variant;
35
36 import std.meta, std.traits, std.typecons;
37
38 ///
39 @system unittest
40 {
41 Variant a; // Must assign before use, otherwise exception ensues
42 // Initialize with an integer; make the type int
43 Variant b = 42;
44 assert(b.type == typeid(int));
45 // Peek at the value
46 assert(b.peek!(int) !is null && *b.peek!(int) == 42);
47 // Automatically convert per language rules
48 auto x = b.get!(real);
49
50 // Assign any other type, including other variants
51 a = b;
52 a = 3.14;
53 assert(a.type == typeid(double));
54 // Implicit conversions work just as with built-in types
55 assert(a < b);
56 // Check for convertibility
57 assert(!a.convertsTo!(int)); // double not convertible to int
58 // Strings and all other arrays are supported
59 a = "now I'm a string";
60 assert(a == "now I'm a string");
61
62 // can also assign arrays
63 a = new int[42];
64 assert(a.length == 42);
65 a[5] = 7;
66 assert(a[5] == 7);
67
68 // Can also assign class values
69 class Foo {}
70 auto foo = new Foo;
71 a = foo;
72 assert(*a.peek!(Foo) == foo); // and full type information is preserved
73 }
74
75 /++
76 Gives the $(D sizeof) the largest type given.
77 +/
78 template maxSize(T...)
79 {
80 static if (T.length == 1)
81 {
82 enum size_t maxSize = T[0].sizeof;
83 }
84 else
85 {
86 import std.algorithm.comparison : max;
87 enum size_t maxSize = max(T[0].sizeof, maxSize!(T[1 .. $]));
88 }
89 }
90
91 ///
92 @safe unittest
93 {
94 static assert(maxSize!(int, long) == 8);
95 static assert(maxSize!(bool, byte) == 1);
96
97 struct Cat { int a, b, c; }
98 static assert(maxSize!(bool, Cat) == 12);
99 }
100
101 struct This;
102
103 private alias This2Variant(V, T...) = AliasSeq!(ReplaceType!(This, V, T));
104
105 /**
106 * Back-end type seldom used directly by user
107 * code. Two commonly-used types using $(D VariantN) are:
108 *
109 * $(OL $(LI $(LREF Algebraic): A closed discriminated union with a
110 * limited type universe (e.g., $(D Algebraic!(int, double,
111 * string)) only accepts these three types and rejects anything
112 * else).) $(LI $(LREF Variant): An open discriminated union allowing an
113 * unbounded set of types. If any of the types in the $(D Variant)
114 * are larger than the largest built-in type, they will automatically
115 * be boxed. This means that even large types will only be the size
116 * of a pointer within the $(D Variant), but this also implies some
117 * overhead. $(D Variant) can accommodate all primitive types and
118 * all user-defined types.))
119 *
120 * Both $(D Algebraic) and $(D Variant) share $(D
121 * VariantN)'s interface. (See their respective documentations below.)
122 *
123 * $(D VariantN) is a discriminated union type parameterized
124 * with the largest size of the types stored ($(D maxDataSize))
125 * and with the list of allowed types ($(D AllowedTypes)). If
126 * the list is empty, then any type up of size up to $(D
127 * maxDataSize) (rounded up for alignment) can be stored in a
128 * $(D VariantN) object without being boxed (types larger
129 * than this will be boxed).
130 *
131 */
132 struct VariantN(size_t maxDataSize, AllowedTypesParam...)
133 {
134 /**
135 The list of allowed types. If empty, any type is allowed.
136 */
137 alias AllowedTypes = This2Variant!(VariantN, AllowedTypesParam);
138
139 private:
140 // Compute the largest practical size from maxDataSize
141 struct SizeChecker
142 {
143 int function() fptr;
144 ubyte[maxDataSize] data;
145 }
146 enum size = SizeChecker.sizeof - (int function()).sizeof;
147
148 /** Tells whether a type $(D T) is statically _allowed for
149 * storage inside a $(D VariantN) object by looking
150 * $(D T) up in $(D AllowedTypes).
151 */
152 public template allowed(T)
153 {
154 enum bool allowed
155 = is(T == VariantN)
156 ||
157 //T.sizeof <= size &&
158 (AllowedTypes.length == 0 || staticIndexOf!(T, AllowedTypes) >= 0);
159 }
160
161 // Each internal operation is encoded with an identifier. See
162 // the "handler" function below.
163 enum OpID { getTypeInfo, get, compare, equals, testConversion, toString,
164 index, indexAssign, catAssign, copyOut, length,
165 apply, postblit, destruct }
166
167 // state
168 ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
169 = &handler!(void);
170 union
171 {
172 ubyte[size] store;
173 // conservatively mark the region as pointers
174 static if (size >= (void*).sizeof)
175 void*[size / (void*).sizeof] p;
176 }
177
178 // internals
179 // Handler for an uninitialized value
180 static ptrdiff_t handler(A : void)(OpID selector, ubyte[size]*, void* parm)
181 {
182 switch (selector)
183 {
184 case OpID.getTypeInfo:
185 *cast(TypeInfo *) parm = typeid(A);
186 break;
187 case OpID.copyOut:
188 auto target = cast(VariantN *) parm;
189 target.fptr = &handler!(A);
190 // no need to copy the data (it's garbage)
191 break;
192 case OpID.compare:
193 case OpID.equals:
194 auto rhs = cast(const VariantN *) parm;
195 return rhs.peek!(A)
196 ? 0 // all uninitialized are equal
197 : ptrdiff_t.min; // uninitialized variant is not comparable otherwise
198 case OpID.toString:
199 string * target = cast(string*) parm;
200 *target = "<Uninitialized VariantN>";
201 break;
202 case OpID.postblit:
203 case OpID.destruct:
204 break;
205 case OpID.get:
206 case OpID.testConversion:
207 case OpID.index:
208 case OpID.indexAssign:
209 case OpID.catAssign:
210 case OpID.length:
211 throw new VariantException(
212 "Attempt to use an uninitialized VariantN");
213 default: assert(false, "Invalid OpID");
214 }
215 return 0;
216 }
217
218 // Handler for all of a type's operations
219 static ptrdiff_t handler(A)(OpID selector, ubyte[size]* pStore, void* parm)
220 {
221 import std.conv : to;
222 static A* getPtr(void* untyped)
223 {
224 if (untyped)
225 {
226 static if (A.sizeof <= size)
227 return cast(A*) untyped;
228 else
229 return *cast(A**) untyped;
230 }
231 return null;
232 }
233
234 static ptrdiff_t compare(A* rhsPA, A* zis, OpID selector)
235 {
236 static if (is(typeof(*rhsPA == *zis)))
237 {
238 if (*rhsPA == *zis)
239 {
240 return 0;
241 }
242 static if (is(typeof(*zis < *rhsPA)))
243 {
244 // Many types (such as any using the default Object opCmp)
245 // will throw on an invalid opCmp, so do it only
246 // if the caller requests it.
247 if (selector == OpID.compare)
248 return *zis < *rhsPA ? -1 : 1;
249 else
250 return ptrdiff_t.min;
251 }
252 else
253 {
254 // Not equal, and type does not support ordering
255 // comparisons.
256 return ptrdiff_t.min;
257 }
258 }
259 else
260 {
261 // Type does not support comparisons at all.
262 return ptrdiff_t.min;
263 }
264 }
265
266 auto zis = getPtr(pStore);
267 // Input: TypeInfo object
268 // Output: target points to a copy of *me, if me was not null
269 // Returns: true iff the A can be converted to the type represented
270 // by the incoming TypeInfo
271 static bool tryPutting(A* src, TypeInfo targetType, void* target)
272 {
273 alias UA = Unqual!A;
274 alias MutaTypes = AliasSeq!(UA, ImplicitConversionTargets!UA);
275 alias ConstTypes = staticMap!(ConstOf, MutaTypes);
276 alias SharedTypes = staticMap!(SharedOf, MutaTypes);
277 alias SharedConstTypes = staticMap!(SharedConstOf, MutaTypes);
278 alias ImmuTypes = staticMap!(ImmutableOf, MutaTypes);
279
280 static if (is(A == immutable))
281 alias AllTypes = AliasSeq!(ImmuTypes, ConstTypes, SharedConstTypes);
282 else static if (is(A == shared))
283 {
284 static if (is(A == const))
285 alias AllTypes = SharedConstTypes;
286 else
287 alias AllTypes = AliasSeq!(SharedTypes, SharedConstTypes);
288 }
289 else
290 {
291 static if (is(A == const))
292 alias AllTypes = ConstTypes;
293 else
294 alias AllTypes = AliasSeq!(MutaTypes, ConstTypes);
295 }
296
297 foreach (T ; AllTypes)
298 {
299 if (targetType != typeid(T))
300 continue;
301
302 static if (is(typeof(*cast(T*) target = *src)) ||
303 is(T == const(U), U) ||
304 is(T == shared(U), U) ||
305 is(T == shared const(U), U) ||
306 is(T == immutable(U), U))
307 {
308 import std.conv : emplaceRef;
309
310 auto zat = cast(T*) target;
311 if (src)
312 {
313 static if (T.sizeof > 0)
314 assert(target, "target must be non-null");
315
316 emplaceRef(*cast(Unqual!T*) zat, *cast(UA*) src);
317 }
318 }
319 else
320 {
321 // type T is not constructible from A
322 if (src)
323 assert(false, A.stringof);
324 }
325 return true;
326 }
327 return false;
328 }
329
330 switch (selector)
331 {
332 case OpID.getTypeInfo:
333 *cast(TypeInfo *) parm = typeid(A);
334 break;
335 case OpID.copyOut:
336 auto target = cast(VariantN *) parm;
337 assert(target);
338
339 static if (target.size < A.sizeof)
340 {
341 if (target.type.tsize < A.sizeof)
342 *cast(A**)&target.store = new A;
343 }
344 tryPutting(zis, typeid(A), cast(void*) getPtr(&target.store))
345 || assert(false);
346 target.fptr = &handler!(A);
347 break;
348 case OpID.get:
349 auto t = * cast(Tuple!(TypeInfo, void*)*) parm;
350 return !tryPutting(zis, t[0], t[1]);
351 case OpID.testConversion:
352 return !tryPutting(null, *cast(TypeInfo*) parm, null);
353 case OpID.compare:
354 case OpID.equals:
355 auto rhsP = cast(VariantN *) parm;
356 auto rhsType = rhsP.type;
357 // Are we the same?
358 if (rhsType == typeid(A))
359 {
360 // cool! Same type!
361 auto rhsPA = getPtr(&rhsP.store);
362 return compare(rhsPA, zis, selector);
363 }
364 else if (rhsType == typeid(void))
365 {
366 // No support for ordering comparisons with
367 // uninitialized vars
368 return ptrdiff_t.min;
369 }
370 VariantN temp;
371 // Do I convert to rhs?
372 if (tryPutting(zis, rhsType, &temp.store))
373 {
374 // cool, I do; temp's store contains my data in rhs's type!
375 // also fix up its fptr
376 temp.fptr = rhsP.fptr;
377 // now lhsWithRhsType is a full-blown VariantN of rhs's type
378 if (selector == OpID.compare)
379 return temp.opCmp(*rhsP);
380 else
381 return temp.opEquals(*rhsP) ? 0 : 1;
382 }
383 // Does rhs convert to zis?
384 auto t = tuple(typeid(A), &temp.store);
385 if (rhsP.fptr(OpID.get, &rhsP.store, &t) == 0)
386 {
387 // cool! Now temp has rhs in my type!
388 auto rhsPA = getPtr(&temp.store);
389 return compare(rhsPA, zis, selector);
390 }
391 return ptrdiff_t.min; // dunno
392 case OpID.toString:
393 auto target = cast(string*) parm;
394 static if (is(typeof(to!(string)(*zis))))
395 {
396 *target = to!(string)(*zis);
397 break;
398 }
399 // TODO: The following test evaluates to true for shared objects.
400 // Use __traits for now until this is sorted out.
401 // else static if (is(typeof((*zis).toString)))
402 else static if (__traits(compiles, {(*zis).toString();}))
403 {
404 *target = (*zis).toString();
405 break;
406 }
407 else
408 {
409 throw new VariantException(typeid(A), typeid(string));
410 }
411
412 case OpID.index:
413 auto result = cast(Variant*) parm;
414 static if (isArray!(A) && !is(Unqual!(typeof(A.init[0])) == void))
415 {
416 // array type; input and output are the same VariantN
417 size_t index = result.convertsTo!(int)
418 ? result.get!(int) : result.get!(size_t);
419 *result = (*zis)[index];
420 break;
421 }
422 else static if (isAssociativeArray!(A))
423 {
424 *result = (*zis)[result.get!(typeof(A.init.keys[0]))];
425 break;
426 }
427 else
428 {
429 throw new VariantException(typeid(A), result[0].type);
430 }
431
432 case OpID.indexAssign:
433 // array type; result comes first, index comes second
434 auto args = cast(Variant*) parm;
435 static if (isArray!(A) && is(typeof((*zis)[0] = (*zis)[0])))
436 {
437 size_t index = args[1].convertsTo!(int)
438 ? args[1].get!(int) : args[1].get!(size_t);
439 (*zis)[index] = args[0].get!(typeof((*zis)[0]));
440 break;
441 }
442 else static if (isAssociativeArray!(A))
443 {
444 (*zis)[args[1].get!(typeof(A.init.keys[0]))]
445 = args[0].get!(typeof(A.init.values[0]));
446 break;
447 }
448 else
449 {
450 throw new VariantException(typeid(A), args[0].type);
451 }
452
453 case OpID.catAssign:
454 static if (!is(Unqual!(typeof((*zis)[0])) == void) && is(typeof((*zis)[0])) && is(typeof((*zis) ~= *zis)))
455 {
456 // array type; parm is the element to append
457 auto arg = cast(Variant*) parm;
458 alias E = typeof((*zis)[0]);
459 if (arg[0].convertsTo!(E))
460 {
461 // append one element to the array
462 (*zis) ~= [ arg[0].get!(E) ];
463 }
464 else
465 {
466 // append a whole array to the array
467 (*zis) ~= arg[0].get!(A);
468 }
469 break;
470 }
471 else
472 {
473 throw new VariantException(typeid(A), typeid(void[]));
474 }
475
476 case OpID.length:
477 static if (isArray!(A) || isAssociativeArray!(A))
478 {
479 return zis.length;
480 }
481 else
482 {
483 throw new VariantException(typeid(A), typeid(void[]));
484 }
485
486 case OpID.apply:
487 static if (!isFunctionPointer!A && !isDelegate!A)
488 {
489 import std.conv : text;
490 import std.exception : enforce;
491 enforce(0, text("Cannot apply `()' to a value of type `",
492 A.stringof, "'."));
493 }
494 else
495 {
496 import std.conv : text;
497 import std.exception : enforce;
498 alias ParamTypes = Parameters!A;
499 auto p = cast(Variant*) parm;
500 auto argCount = p.get!size_t;
501 // To assign the tuple we need to use the unqualified version,
502 // otherwise we run into issues such as with const values.
503 // We still get the actual type from the Variant though
504 // to ensure that we retain const correctness.
505 Tuple!(staticMap!(Unqual, ParamTypes)) t;
506 enforce(t.length == argCount,
507 text("Argument count mismatch: ",
508 A.stringof, " expects ", t.length,
509 " argument(s), not ", argCount, "."));
510 auto variantArgs = p[1 .. argCount + 1];
511 foreach (i, T; ParamTypes)
512 {
513 t[i] = cast() variantArgs[i].get!T;
514 }
515
516 auto args = cast(Tuple!(ParamTypes))t;
517 static if (is(ReturnType!A == void))
518 {
519 (*zis)(args.expand);
520 *p = Variant.init; // void returns uninitialized Variant.
521 }
522 else
523 {
524 *p = (*zis)(args.expand);
525 }
526 }
527 break;
528
529 case OpID.postblit:
530 static if (hasElaborateCopyConstructor!A)
531 {
532 typeid(A).postblit(zis);
533 }
534 break;
535
536 case OpID.destruct:
537 static if (hasElaborateDestructor!A)
538 {
539 typeid(A).destroy(zis);
540 }
541 break;
542
543 default: assert(false);
544 }
545 return 0;
546 }
547
548 enum doUnittest = is(VariantN == Variant);
549
550 public:
551 /** Constructs a $(D VariantN) value given an argument of a
552 * generic type. Statically rejects disallowed types.
553 */
554
555 this(T)(T value)
556 {
557 static assert(allowed!(T), "Cannot store a " ~ T.stringof
558 ~ " in a " ~ VariantN.stringof);
559 opAssign(value);
560 }
561
562 /// Allows assignment from a subset algebraic type
563 this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value)
564 if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
565 {
566 opAssign(value);
567 }
568
569 static if (!AllowedTypes.length || anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
570 {
571 this(this)
572 {
573 fptr(OpID.postblit, &store, null);
574 }
575 }
576
577 static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
578 {
579 ~this()
580 {
581 fptr(OpID.destruct, &store, null);
582 }
583 }
584
585 /** Assigns a $(D VariantN) from a generic
586 * argument. Statically rejects disallowed types. */
587
588 VariantN opAssign(T)(T rhs)
589 {
590 //writeln(typeid(rhs));
591 static assert(allowed!(T), "Cannot store a " ~ T.stringof
592 ~ " in a " ~ VariantN.stringof ~ ". Valid types are "
593 ~ AllowedTypes.stringof);
594
595 static if (is(T : VariantN))
596 {
597 rhs.fptr(OpID.copyOut, &rhs.store, &this);
598 }
599 else static if (is(T : const(VariantN)))
600 {
601 static assert(false,
602 "Assigning Variant objects from const Variant"~
603 " objects is currently not supported.");
604 }
605 else
606 {
607 static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes))
608 {
609 // Assignment should destruct previous value
610 fptr(OpID.destruct, &store, null);
611 }
612
613 static if (T.sizeof <= size)
614 {
615 import core.stdc.string : memcpy;
616 // If T is a class we're only copying the reference, so it
617 // should be safe to cast away shared so the memcpy will work.
618 //
619 // TODO: If a shared class has an atomic reference then using
620 // an atomic load may be more correct. Just make sure
621 // to use the fastest approach for the load op.
622 static if (is(T == class) && is(T == shared))
623 memcpy(&store, cast(const(void*)) &rhs, rhs.sizeof);
624 else
625 memcpy(&store, &rhs, rhs.sizeof);
626 static if (hasElaborateCopyConstructor!T)
627 {
628 typeid(T).postblit(&store);
629 }
630 }
631 else
632 {
633 import core.stdc.string : memcpy;
634 static if (__traits(compiles, {new T(T.init);}))
635 {
636 auto p = new T(rhs);
637 }
638 else
639 {
640 auto p = new T;
641 *p = rhs;
642 }
643 memcpy(&store, &p, p.sizeof);
644 }
645 fptr = &handler!(T);
646 }
647 return this;
648 }
649
650 // Allow assignment from another variant which is a subset of this one
651 VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs)
652 if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
653 {
654 // discover which type rhs is actually storing
655 foreach (V; T.AllowedTypes)
656 if (rhs.type == typeid(V))
657 return this = rhs.get!V;
658 assert(0, T.AllowedTypes.stringof);
659 }
660
661
662 Variant opCall(P...)(auto ref P params)
663 {
664 Variant[P.length + 1] pack;
665 pack[0] = P.length;
666 foreach (i, _; params)
667 {
668 pack[i + 1] = params[i];
669 }
670 fptr(OpID.apply, &store, &pack);
671 return pack[0];
672 }
673
674 /** Returns true if and only if the $(D VariantN) object
675 * holds a valid value (has been initialized with, or assigned
676 * from, a valid value).
677 */
678 @property bool hasValue() const pure nothrow
679 {
680 // @@@BUG@@@ in compiler, the cast shouldn't be needed
681 return cast(typeof(&handler!(void))) fptr != &handler!(void);
682 }
683
684 ///
685 static if (doUnittest)
686 @system unittest
687 {
688 Variant a;
689 assert(!a.hasValue);
690 Variant b;
691 a = b;
692 assert(!a.hasValue); // still no value
693 a = 5;
694 assert(a.hasValue);
695 }
696
697 /**
698 * If the $(D VariantN) object holds a value of the
699 * $(I exact) type $(D T), returns a pointer to that
700 * value. Otherwise, returns $(D null). In cases
701 * where $(D T) is statically disallowed, $(D
702 * peek) will not compile.
703 */
704 @property inout(T)* peek(T)() inout
705 {
706 static if (!is(T == void))
707 static assert(allowed!(T), "Cannot store a " ~ T.stringof
708 ~ " in a " ~ VariantN.stringof);
709 if (type != typeid(T))
710 return null;
711 static if (T.sizeof <= size)
712 return cast(inout T*)&store;
713 else
714 return *cast(inout T**)&store;
715 }
716
717 ///
718 static if (doUnittest)
719 @system unittest
720 {
721 Variant a = 5;
722 auto b = a.peek!(int);
723 assert(b !is null);
724 *b = 6;
725 assert(a == 6);
726 }
727
728 /**
729 * Returns the $(D typeid) of the currently held value.
730 */
731
732 @property TypeInfo type() const nothrow @trusted
733 {
734 scope(failure) assert(0);
735
736 TypeInfo result;
737 fptr(OpID.getTypeInfo, null, &result);
738 return result;
739 }
740
741 /**
742 * Returns $(D true) if and only if the $(D VariantN)
743 * object holds an object implicitly convertible to type `T`.
744 * Implicit convertibility is defined as per
745 * $(REF_ALTTEXT ImplicitConversionTargets, ImplicitConversionTargets, std,traits).
746 */
747
748 @property bool convertsTo(T)() const
749 {
750 TypeInfo info = typeid(T);
751 return fptr(OpID.testConversion, null, &info) == 0;
752 }
753
754 /**
755 Returns the value stored in the `VariantN` object, either by specifying the
756 needed type or the index in the list of allowed types. The latter overload
757 only applies to bounded variants (e.g. $(LREF Algebraic)).
758
759 Params:
760 T = The requested type. The currently stored value must implicitly convert
761 to the requested type, in fact `DecayStaticToDynamicArray!T`. If an
762 implicit conversion is not possible, throws a `VariantException`.
763 index = The index of the type among `AllowedTypesParam`, zero-based.
764 */
765 @property inout(T) get(T)() inout
766 {
767 inout(T) result = void;
768 static if (is(T == shared))
769 alias R = shared Unqual!T;
770 else
771 alias R = Unqual!T;
772 auto buf = tuple(typeid(T), cast(R*)&result);
773
774 if (fptr(OpID.get, cast(ubyte[size]*) &store, &buf))
775 {
776 throw new VariantException(type, typeid(T));
777 }
778 return result;
779 }
780
781 /// Ditto
782 @property auto get(uint index)() inout
783 if (index < AllowedTypes.length)
784 {
785 foreach (i, T; AllowedTypes)
786 {
787 static if (index == i) return get!T;
788 }
789 assert(0);
790 }
791
792 /**
793 * Returns the value stored in the $(D VariantN) object,
794 * explicitly converted (coerced) to the requested type $(D
795 * T). If $(D T) is a string type, the value is formatted as
796 * a string. If the $(D VariantN) object is a string, a
797 * parse of the string to type $(D T) is attempted. If a
798 * conversion is not possible, throws a $(D
799 * VariantException).
800 */
801
802 @property T coerce(T)()
803 {
804 import std.conv : to, text;
805 static if (isNumeric!T || isBoolean!T)
806 {
807 if (convertsTo!real)
808 {
809 // maybe optimize this fella; handle ints separately
810 return to!T(get!real);
811 }
812 else if (convertsTo!(const(char)[]))
813 {
814 return to!T(get!(const(char)[]));
815 }
816 // I'm not sure why this doesn't convert to const(char),
817 // but apparently it doesn't (probably a deeper bug).
818 //
819 // Until that is fixed, this quick addition keeps a common
820 // function working. "10".coerce!int ought to work.
821 else if (convertsTo!(immutable(char)[]))
822 {
823 return to!T(get!(immutable(char)[]));
824 }
825 else
826 {
827 import std.exception : enforce;
828 enforce(false, text("Type ", type, " does not convert to ",
829 typeid(T)));
830 assert(0);
831 }
832 }
833 else static if (is(T : Object))
834 {
835 return to!(T)(get!(Object));
836 }
837 else static if (isSomeString!(T))
838 {
839 return to!(T)(toString());
840 }
841 else
842 {
843 // Fix for bug 1649
844 static assert(false, "unsupported type for coercion");
845 }
846 }
847
848 /**
849 * Formats the stored value as a string.
850 */
851
852 string toString()
853 {
854 string result;
855 fptr(OpID.toString, &store, &result) == 0 || assert(false);
856 return result;
857 }
858
859 /**
860 * Comparison for equality used by the "==" and "!=" operators.
861 */
862
863 // returns 1 if the two are equal
864 bool opEquals(T)(auto ref T rhs) const
865 if (allowed!T || is(Unqual!T == VariantN))
866 {
867 static if (is(Unqual!T == VariantN))
868 alias temp = rhs;
869 else
870 auto temp = VariantN(rhs);
871 return !fptr(OpID.equals, cast(ubyte[size]*) &store,
872 cast(void*) &temp);
873 }
874
875 // workaround for bug 10567 fix
876 int opCmp(ref const VariantN rhs) const
877 {
878 return (cast() this).opCmp!(VariantN)(cast() rhs);
879 }
880
881 /**
882 * Ordering comparison used by the "<", "<=", ">", and ">="
883 * operators. In case comparison is not sensible between the held
884 * value and $(D rhs), an exception is thrown.
885 */
886
887 int opCmp(T)(T rhs)
888 if (allowed!T) // includes T == VariantN
889 {
890 static if (is(T == VariantN))
891 alias temp = rhs;
892 else
893 auto temp = VariantN(rhs);
894 auto result = fptr(OpID.compare, &store, &temp);
895 if (result == ptrdiff_t.min)
896 {
897 throw new VariantException(type, temp.type);
898 }
899
900 assert(result >= -1 && result <= 1); // Should be true for opCmp.
901 return cast(int) result;
902 }
903
904 /**
905 * Computes the hash of the held value.
906 */
907
908 size_t toHash() const nothrow @safe
909 {
910 return type.getHash(&store);
911 }
912
913 private VariantN opArithmetic(T, string op)(T other)
914 {
915 static if (isInstanceOf!(.VariantN, T))
916 {
917 string tryUseType(string tp)
918 {
919 import std.format : format;
920 return q{
921 static if (allowed!%1$s && T.allowed!%1$s)
922 if (convertsTo!%1$s && other.convertsTo!%1$s)
923 return VariantN(get!%1$s %2$s other.get!%1$s);
924 }.format(tp, op);
925 }
926
927 mixin(tryUseType("uint"));
928 mixin(tryUseType("int"));
929 mixin(tryUseType("ulong"));
930 mixin(tryUseType("long"));
931 mixin(tryUseType("float"));
932 mixin(tryUseType("double"));
933 mixin(tryUseType("real"));
934 }
935 else
936 {
937 static if (allowed!T)
938 if (auto pv = peek!T) return VariantN(mixin("*pv " ~ op ~ " other"));
939 static if (allowed!uint && is(typeof(T.max) : uint) && isUnsigned!T)
940 if (convertsTo!uint) return VariantN(mixin("get!(uint) " ~ op ~ " other"));
941 static if (allowed!int && is(typeof(T.max) : int) && !isUnsigned!T)
942 if (convertsTo!int) return VariantN(mixin("get!(int) " ~ op ~ " other"));
943 static if (allowed!ulong && is(typeof(T.max) : ulong) && isUnsigned!T)
944 if (convertsTo!ulong) return VariantN(mixin("get!(ulong) " ~ op ~ " other"));
945 static if (allowed!long && is(typeof(T.max) : long) && !isUnsigned!T)
946 if (convertsTo!long) return VariantN(mixin("get!(long) " ~ op ~ " other"));
947 static if (allowed!float && is(T : float))
948 if (convertsTo!float) return VariantN(mixin("get!(float) " ~ op ~ " other"));
949 static if (allowed!double && is(T : double))
950 if (convertsTo!double) return VariantN(mixin("get!(double) " ~ op ~ " other"));
951 static if (allowed!real && is (T : real))
952 if (convertsTo!real) return VariantN(mixin("get!(real) " ~ op ~ " other"));
953 }
954
955 throw new VariantException("No possible match found for VariantN "~op~" "~T.stringof);
956 }
957
958 private VariantN opLogic(T, string op)(T other)
959 {
960 VariantN result;
961 static if (is(T == VariantN))
962 {
963 if (convertsTo!(uint) && other.convertsTo!(uint))
964 result = mixin("get!(uint) " ~ op ~ " other.get!(uint)");
965 else if (convertsTo!(int) && other.convertsTo!(int))
966 result = mixin("get!(int) " ~ op ~ " other.get!(int)");
967 else if (convertsTo!(ulong) && other.convertsTo!(ulong))
968 result = mixin("get!(ulong) " ~ op ~ " other.get!(ulong)");
969 else
970 result = mixin("get!(long) " ~ op ~ " other.get!(long)");
971 }
972 else
973 {
974 if (is(typeof(T.max) : uint) && T.min == 0 && convertsTo!(uint))
975 result = mixin("get!(uint) " ~ op ~ " other");
976 else if (is(typeof(T.max) : int) && T.min < 0 && convertsTo!(int))
977 result = mixin("get!(int) " ~ op ~ " other");
978 else if (is(typeof(T.max) : ulong) && T.min == 0
979 && convertsTo!(ulong))
980 result = mixin("get!(ulong) " ~ op ~ " other");
981 else
982 result = mixin("get!(long) " ~ op ~ " other");
983 }
984 return result;
985 }
986
987 /**
988 * Arithmetic between $(D VariantN) objects and numeric
989 * values. All arithmetic operations return a $(D VariantN)
990 * object typed depending on the types of both values
991 * involved. The conversion rules mimic D's built-in rules for
992 * arithmetic conversions.
993 */
994
995 // Adapted from http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/Variant
996 // arithmetic
997 VariantN opAdd(T)(T rhs) { return opArithmetic!(T, "+")(rhs); }
998 ///ditto
999 VariantN opSub(T)(T rhs) { return opArithmetic!(T, "-")(rhs); }
1000
1001 // Commenteed all _r versions for now because of ambiguities
1002 // arising when two Variants are used
1003
1004 // ///ditto
1005 // VariantN opSub_r(T)(T lhs)
1006 // {
1007 // return VariantN(lhs).opArithmetic!(VariantN, "-")(this);
1008 // }
1009 ///ditto
1010 VariantN opMul(T)(T rhs) { return opArithmetic!(T, "*")(rhs); }
1011 ///ditto
1012 VariantN opDiv(T)(T rhs) { return opArithmetic!(T, "/")(rhs); }
1013 // ///ditto
1014 // VariantN opDiv_r(T)(T lhs)
1015 // {
1016 // return VariantN(lhs).opArithmetic!(VariantN, "/")(this);
1017 // }
1018 ///ditto
1019 VariantN opMod(T)(T rhs) { return opArithmetic!(T, "%")(rhs); }
1020 // ///ditto
1021 // VariantN opMod_r(T)(T lhs)
1022 // {
1023 // return VariantN(lhs).opArithmetic!(VariantN, "%")(this);
1024 // }
1025 ///ditto
1026 VariantN opAnd(T)(T rhs) { return opLogic!(T, "&")(rhs); }
1027 ///ditto
1028 VariantN opOr(T)(T rhs) { return opLogic!(T, "|")(rhs); }
1029 ///ditto
1030 VariantN opXor(T)(T rhs) { return opLogic!(T, "^")(rhs); }
1031 ///ditto
1032 VariantN opShl(T)(T rhs) { return opLogic!(T, "<<")(rhs); }
1033 // ///ditto
1034 // VariantN opShl_r(T)(T lhs)
1035 // {
1036 // return VariantN(lhs).opLogic!(VariantN, "<<")(this);
1037 // }
1038 ///ditto
1039 VariantN opShr(T)(T rhs) { return opLogic!(T, ">>")(rhs); }
1040 // ///ditto
1041 // VariantN opShr_r(T)(T lhs)
1042 // {
1043 // return VariantN(lhs).opLogic!(VariantN, ">>")(this);
1044 // }
1045 ///ditto
1046 VariantN opUShr(T)(T rhs) { return opLogic!(T, ">>>")(rhs); }
1047 // ///ditto
1048 // VariantN opUShr_r(T)(T lhs)
1049 // {
1050 // return VariantN(lhs).opLogic!(VariantN, ">>>")(this);
1051 // }
1052 ///ditto
1053 VariantN opCat(T)(T rhs)
1054 {
1055 auto temp = this;
1056 temp ~= rhs;
1057 return temp;
1058 }
1059 // ///ditto
1060 // VariantN opCat_r(T)(T rhs)
1061 // {
1062 // VariantN temp = rhs;
1063 // temp ~= this;
1064 // return temp;
1065 // }
1066
1067 ///ditto
1068 VariantN opAddAssign(T)(T rhs) { return this = this + rhs; }
1069 ///ditto
1070 VariantN opSubAssign(T)(T rhs) { return this = this - rhs; }
1071 ///ditto
1072 VariantN opMulAssign(T)(T rhs) { return this = this * rhs; }
1073 ///ditto
1074 VariantN opDivAssign(T)(T rhs) { return this = this / rhs; }
1075 ///ditto
1076 VariantN opModAssign(T)(T rhs) { return this = this % rhs; }
1077 ///ditto
1078 VariantN opAndAssign(T)(T rhs) { return this = this & rhs; }
1079 ///ditto
1080 VariantN opOrAssign(T)(T rhs) { return this = this | rhs; }
1081 ///ditto
1082 VariantN opXorAssign(T)(T rhs) { return this = this ^ rhs; }
1083 ///ditto
1084 VariantN opShlAssign(T)(T rhs) { return this = this << rhs; }
1085 ///ditto
1086 VariantN opShrAssign(T)(T rhs) { return this = this >> rhs; }
1087 ///ditto
1088 VariantN opUShrAssign(T)(T rhs) { return this = this >>> rhs; }
1089 ///ditto
1090 VariantN opCatAssign(T)(T rhs)
1091 {
1092 auto toAppend = Variant(rhs);
1093 fptr(OpID.catAssign, &store, &toAppend) == 0 || assert(false);
1094 return this;
1095 }
1096
1097 /**
1098 * Array and associative array operations. If a $(D
1099 * VariantN) contains an (associative) array, it can be indexed
1100 * into. Otherwise, an exception is thrown.
1101 */
1102 inout(Variant) opIndex(K)(K i) inout
1103 {
1104 auto result = Variant(i);
1105 fptr(OpID.index, cast(ubyte[size]*) &store, &result) == 0 || assert(false);
1106 return result;
1107 }
1108
1109 ///
1110 static if (doUnittest)
1111 @system unittest
1112 {
1113 Variant a = new int[10];
1114 a[5] = 42;
1115 assert(a[5] == 42);
1116 a[5] += 8;
1117 assert(a[5] == 50);
1118
1119 int[int] hash = [ 42:24 ];
1120 a = hash;
1121 assert(a[42] == 24);
1122 a[42] /= 2;
1123 assert(a[42] == 12);
1124 }
1125
1126 /// ditto
1127 Variant opIndexAssign(T, N)(T value, N i)
1128 {
1129 static if (AllowedTypes.length && !isInstanceOf!(.VariantN, T))
1130 {
1131 enum canAssign(U) = __traits(compiles, (U u){ u[i] = value; });
1132 static assert(anySatisfy!(canAssign, AllowedTypes),
1133 "Cannot assign " ~ T.stringof ~ " to " ~ VariantN.stringof ~
1134 " indexed with " ~ N.stringof);
1135 }
1136 Variant[2] args = [ Variant(value), Variant(i) ];
1137 fptr(OpID.indexAssign, &store, &args) == 0 || assert(false);
1138 return args[0];
1139 }
1140
1141 /// ditto
1142 Variant opIndexOpAssign(string op, T, N)(T value, N i)
1143 {
1144 return opIndexAssign(mixin(`opIndex(i)` ~ op ~ `value`), i);
1145 }
1146
1147 /** If the $(D VariantN) contains an (associative) array,
1148 * returns the _length of that array. Otherwise, throws an
1149 * exception.
1150 */
1151 @property size_t length()
1152 {
1153 return cast(size_t) fptr(OpID.length, &store, null);
1154 }
1155
1156 /**
1157 If the $(D VariantN) contains an array, applies $(D dg) to each
1158 element of the array in turn. Otherwise, throws an exception.
1159 */
1160 int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate))
1161 {
1162 alias A = Parameters!(Delegate)[0];
1163 if (type == typeid(A[]))
1164 {
1165 auto arr = get!(A[]);
1166 foreach (ref e; arr)
1167 {
1168 if (dg(e)) return 1;
1169 }
1170 }
1171 else static if (is(A == VariantN))
1172 {
1173 foreach (i; 0 .. length)
1174 {
1175 // @@@TODO@@@: find a better way to not confuse
1176 // clients who think they change values stored in the
1177 // Variant when in fact they are only changing tmp.
1178 auto tmp = this[i];
1179 debug scope(exit) assert(tmp == this[i]);
1180 if (dg(tmp)) return 1;
1181 }
1182 }
1183 else
1184 {
1185 import std.conv : text;
1186 import std.exception : enforce;
1187 enforce(false, text("Variant type ", type,
1188 " not iterable with values of type ",
1189 A.stringof));
1190 }
1191 return 0;
1192 }
1193 }
1194
1195 @system unittest
1196 {
1197 import std.conv : to;
1198 Variant v;
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
1328 pure nothrow @nogc
1329 @system unittest
1330 {
1331 Algebraic!(int, double) a;
1332 a = 100;
1333 a = 1.0;
1334 }
1335
1336 // Issue 14457
1337 @system unittest
1338 {
1339 alias A = Algebraic!(int, float, double);
1340 alias B = Algebraic!(int, float);
1341
1342 A a = 1;
1343 B b = 6f;
1344 a = b;
1345
1346 assert(a.type == typeid(float));
1347 assert(a.get!float == 6f);
1348 }
1349
1350 // Issue 14585
1351 @system unittest
1352 {
1353 static struct S
1354 {
1355 int x = 42;
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
1381 types. It's an alias for $(LREF VariantN) with an
1382 appropriately-constructed maximum size. `Algebraic` is
1383 useful when it is desirable to restrict what a discriminated type
1384 could hold to the end of defining simpler and more efficient
1385 manipulation.
1386
1387 */
1388 template Algebraic(T...)
1389 {
1390 alias Algebraic = VariantN!(maxSize!T, T);
1391 }
1392
1393 ///
1394 @system unittest
1395 {
1396 auto v = Algebraic!(int, double, string)(5);
1397 assert(v.peek!(int));
1398 v = 3.14;
1399 assert(v.peek!(double));
1400 // auto x = v.peek!(long); // won't compile, type long not allowed
1401 // v = '1'; // won't compile, type char not allowed
1402 }
1403
1404 /**
1405 $(H4 Self-Referential Types)
1406
1407 A useful and popular use of algebraic data structures is for defining $(LUCKY
1408 self-referential data structures), i.e. structures that embed references to
1409 values of their own type within.
1410
1411 This is achieved with `Algebraic` by using `This` as a placeholder whenever a
1412 reference to the type being defined is needed. The `Algebraic` instantiation
1413 will perform $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
1414 alpha renaming) on its constituent types, replacing `This`
1415 with the self-referenced type. The structure of the type involving `This` may
1416 be arbitrarily complex.
1417 */
1418 @system unittest
1419 {
1420 import std.typecons : Tuple, tuple;
1421
1422 // A tree is either a leaf or a branch of two other trees
1423 alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*));
1424 Tree!int tree = tuple(new Tree!int(42), new Tree!int(43));
1425 Tree!int* right = tree.get!1[1];
1426 assert(*right == 43);
1427
1428 // An object is a double, a string, or a hash of objects
1429 alias Obj = Algebraic!(double, string, This[string]);
1430 Obj obj = "hello";
1431 assert(obj.get!1 == "hello");
1432 obj = 42.0;
1433 assert(obj.get!0 == 42);
1434 obj = ["customer": Obj("John"), "paid": Obj(23.95)];
1435 assert(obj.get!2["customer"] == "John");
1436 }
1437
1438 /**
1439 Alias for $(LREF VariantN) instantiated with the largest size of `creal`,
1440 `char[]`, and `void delegate()`. This ensures that `Variant` is large enough
1441 to hold all of D's predefined types unboxed, including all numeric types,
1442 pointers, delegates, and class references. You may want to use
1443 $(D VariantN) directly with a different maximum size either for
1444 storing larger types unboxed, or for saving memory.
1445 */
1446 alias Variant = VariantN!(maxSize!(creal, char[], void delegate()));
1447
1448 /**
1449 * Returns an array of variants constructed from $(D args).
1450 *
1451 * This is by design. During construction the $(D Variant) needs
1452 * static type information about the type being held, so as to store a
1453 * pointer to function for fast retrieval.
1454 */
1455 Variant[] variantArray(T...)(T args)
1456 {
1457 Variant[] result;
1458 foreach (arg; args)
1459 {
1460 result ~= Variant(arg);
1461 }
1462 return result;
1463 }
1464
1465 ///
1466 @system unittest
1467 {
1468 auto a = variantArray(1, 3.14, "Hi!");
1469 assert(a[1] == 3.14);
1470 auto b = Variant(a); // variant array as variant
1471 assert(b[1] == 3.14);
1472 }
1473
1474 /**
1475 * Thrown in three cases:
1476 *
1477 * $(OL $(LI An uninitialized `Variant` is used in any way except
1478 * assignment and $(D hasValue);) $(LI A $(D get) or
1479 * $(D coerce) is attempted with an incompatible target type;)
1480 * $(LI A comparison between $(D Variant) objects of
1481 * incompatible types is attempted.))
1482 *
1483 */
1484
1485 // @@@ BUG IN COMPILER. THE 'STATIC' BELOW SHOULD NOT COMPILE
1486 static class VariantException : Exception
1487 {
1488 /// The source type in the conversion or comparison
1489 TypeInfo source;
1490 /// The target type in the conversion or comparison
1491 TypeInfo target;
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 */
2045 template visit(Handlers...)
2046 if (Handlers.length > 0)
2047 {
2048 ///
2049 auto visit(VariantType)(VariantType variant)
2050 if (isAlgebraic!VariantType)
2051 {
2052 return visitImpl!(true, VariantType, Handlers)(variant);
2053 }
2054 }
2055
2056 ///
2057 @system unittest
2058 {
2059 Algebraic!(int, string) variant;
2060
2061 variant = 10;
2062 assert(variant.visit!((string s) => cast(int) s.length,
2063 (int i) => i)()
2064 == 10);
2065 variant = "string";
2066 assert(variant.visit!((int i) => i,
2067 (string s) => cast(int) s.length)()
2068 == 6);
2069
2070 // Error function usage
2071 Algebraic!(int, string) emptyVar;
2072 auto rslt = emptyVar.visit!((string s) => cast(int) s.length,
2073 (int i) => i,
2074 () => -1)();
2075 assert(rslt == -1);
2076
2077 // Generic function usage
2078 Algebraic!(int, float, real) number = 2;
2079 assert(number.visit!(x => x += 1) == 3);
2080
2081 // Generic function for int/float with separate behavior for string
2082 Algebraic!(int, float, string) something = 2;
2083 assert(something.visit!((string s) => s.length, x => x) == 2); // generic
2084 something = "asdf";
2085 assert(something.visit!((string s) => s.length, x => x) == 4); // string
2086
2087 // Generic handler and empty handler
2088 Algebraic!(int, float, real) empty2;
2089 assert(empty2.visit!(x => x + 1, () => -1) == -1);
2090 }
2091
2092 @system unittest
2093 {
2094 Algebraic!(size_t, string) variant;
2095
2096 // not all handled check
2097 static assert(!__traits(compiles, variant.visit!((size_t i){ })() ));
2098
2099 variant = cast(size_t) 10;
2100 auto which = 0;
2101 variant.visit!( (string s) => which = 1,
2102 (size_t i) => which = 0
2103 )();
2104
2105 // integer overload was called
2106 assert(which == 0);
2107
2108 // mustn't compile as generic Variant not supported
2109 Variant v;
2110 static assert(!__traits(compiles, v.visit!((string s) => which = 1,
2111 (size_t i) => which = 0
2112 )()
2113 ));
2114
2115 static size_t func(string s) {
2116 return s.length;
2117 }
2118
2119 variant = "test";
2120 assert( 4 == variant.visit!(func,
2121 (size_t i) => i
2122 )());
2123
2124 Algebraic!(int, float, string) variant2 = 5.0f;
2125 // Shouldn' t compile as float not handled by visitor.
2126 static assert(!__traits(compiles, variant2.visit!(
2127 (int _) {},
2128 (string _) {})()));
2129
2130 Algebraic!(size_t, string, float) variant3;
2131 variant3 = 10.0f;
2132 auto floatVisited = false;
2133
2134 assert(variant3.visit!(
2135 (float f) { floatVisited = true; return cast(size_t) f; },
2136 func,
2137 (size_t i) { return i; }
2138 )() == 10);
2139 assert(floatVisited == true);
2140
2141 Algebraic!(float, string) variant4;
2142
2143 assert(variant4.visit!(func, (float f) => cast(size_t) f, () => size_t.max)() == size_t.max);
2144
2145 // double error func check
2146 static assert(!__traits(compiles,
2147 visit!(() => size_t.max, func, (float f) => cast(size_t) f, () => size_t.max)(variant4))
2148 );
2149 }
2150
2151 // disallow providing multiple generic handlers to visit
2152 // disallow a generic handler that does not apply to all types
2153 @system unittest
2154 {
2155 Algebraic!(int, float) number = 2;
2156 // ok, x + 1 valid for int and float
2157 static assert( __traits(compiles, number.visit!(x => x + 1)));
2158 // bad, two generic handlers
2159 static assert(!__traits(compiles, number.visit!(x => x + 1, x => x + 2)));
2160 // bad, x ~ "a" does not apply to int or float
2161 static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2162 // bad, x ~ "a" does not apply to int or float
2163 static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2164
2165 Algebraic!(int, string) maybenumber = 2;
2166 // ok, x ~ "a" valid for string, x + 1 valid for int, only 1 generic
2167 static assert( __traits(compiles, number.visit!((string x) => x ~ "a", x => x + 1)));
2168 // bad, x ~ "a" valid for string but not int
2169 static assert(!__traits(compiles, number.visit!(x => x ~ "a")));
2170 // bad, two generics, each only applies in one case
2171 static assert(!__traits(compiles, number.visit!(x => x + 1, x => x ~ "a")));
2172 }
2173
2174 /**
2175 * Behaves as $(LREF visit) but doesn't enforce that all types are handled
2176 * by the visiting functions.
2177 *
2178 * If a parameter-less function is specified it is called when
2179 * either $(D variant) doesn't hold a value or holds a type
2180 * which isn't handled by the visiting functions.
2181 *
2182 * Returns: The return type of tryVisit is deduced from the visiting functions and must be
2183 * the same across all overloads.
2184 * Throws: $(LREF VariantException) if `variant` doesn't hold a value or
2185 * `variant` holds a value which isn't handled by the visiting functions,
2186 * when no parameter-less fallback function is specified.
2187 */
2188 template tryVisit(Handlers...)
2189 if (Handlers.length > 0)
2190 {
2191 ///
2192 auto tryVisit(VariantType)(VariantType variant)
2193 if (isAlgebraic!VariantType)
2194 {
2195 return visitImpl!(false, VariantType, Handlers)(variant);
2196 }
2197 }
2198
2199 ///
2200 @system unittest
2201 {
2202 Algebraic!(int, string) variant;
2203
2204 variant = 10;
2205 auto which = -1;
2206 variant.tryVisit!((int i) { which = 0; })();
2207 assert(which == 0);
2208
2209 // Error function usage
2210 variant = "test";
2211 variant.tryVisit!((int i) { which = 0; },
2212 () { which = -100; })();
2213 assert(which == -100);
2214 }
2215
2216 @system unittest
2217 {
2218 import std.exception : assertThrown;
2219 Algebraic!(int, string) variant;
2220
2221 variant = 10;
2222 auto which = -1;
2223 variant.tryVisit!((int i){ which = 0; })();
2224
2225 assert(which == 0);
2226
2227 variant = "test";
2228
2229 assertThrown!VariantException(variant.tryVisit!((int i) { which = 0; })());
2230
2231 void errorfunc()
2232 {
2233 which = -1;
2234 }
2235
2236 variant.tryVisit!((int i) { which = 0; }, errorfunc)();
2237
2238 assert(which == -1);
2239 }
2240
2241 private template isAlgebraic(Type)
2242 {
2243 static if (is(Type _ == VariantN!T, T...))
2244 enum isAlgebraic = T.length >= 2; // T[0] == maxDataSize, T[1..$] == AllowedTypesParam
2245 else
2246 enum isAlgebraic = false;
2247 }
2248
2249 @system unittest
2250 {
2251 static assert(!isAlgebraic!(Variant));
2252 static assert( isAlgebraic!(Algebraic!(string)));
2253 static assert( isAlgebraic!(Algebraic!(int, int[])));
2254 }
2255
2256 private auto visitImpl(bool Strict, VariantType, Handler...)(VariantType variant)
2257 if (isAlgebraic!VariantType && Handler.length > 0)
2258 {
2259 alias AllowedTypes = VariantType.AllowedTypes;
2260
2261
2262 /**
2263 * Returns: Struct where $(D indices) is an array which
2264 * contains at the n-th position the index in Handler which takes the
2265 * n-th type of AllowedTypes. If an Handler doesn't match an
2266 * AllowedType, -1 is set. If a function in the delegates doesn't
2267 * have parameters, the field $(D exceptionFuncIdx) is set;
2268 * otherwise it's -1.
2269 */
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 }