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