1 /** 2 * The variant module contains a variant, or polymorphic type. 3 * 4 * Copyright: Copyright (C) 2005-2009 The Tango Team. All rights reserved. 5 * License: BSD style: $(LICENSE) 6 * Authors: Daniel Keep, Sean Kelly 7 */ 8 module tango.core.Variant; 9 10 private import tango.core.Memory : GC; 11 private import tango.core.Vararg; 12 private import tango.core.Traits; 13 private import tango.core.Tuple; 14 15 private import tango.core.Compiler; 16 17 private extern(C) Object _d_toObject(void*); 18 19 /* 20 * This is to control when we compile in vararg support. Vararg is a complete 21 * pain in the arse. I haven't been able to test under GDC at all (and 22 * support for it may disappear soon anyway) and LDC refuses to build for me. 23 * 24 * As other compilers are tested and verified to work, they should be added 25 * below. It would also probably be a good idea to verify the platforms for 26 * which it works. 27 */ 28 29 version( DigitalMars ) 30 { 31 version( X86 ) 32 { 33 version( Windows ) 34 { 35 version=EnableVararg; 36 } 37 else version( Posix ) 38 { 39 version=EnableVararg; 40 } 41 } 42 version( X86_64 ) 43 { 44 version( Windows ) 45 { 46 version=EnableVararg; 47 } 48 else version( Posix ) 49 { 50 version=EnableVararg; 51 } 52 53 version = DigitalMarsX64; 54 55 import tango.math.Math : max; 56 57 } 58 } 59 else version( LDC ) 60 { 61 version( X86 ) 62 { 63 version( linux ) 64 { 65 version=EnableVararg; // thanks rawler 66 } 67 } 68 else version( X86_64 ) 69 { 70 version( linux ) 71 { 72 version=EnableVararg; // thanks mwarning 73 } 74 75 import tango.math.Math : max; 76 } 77 } 78 else version( DDoc ) 79 { 80 // Let's hope DDoc is smart enough to catch this... 81 version=EnableVararg; 82 } 83 84 version( EnableVararg ) {} else 85 { 86 pragma(msg, "Note: Variant vararg functionality not supported for this " ~ 87 "compiler/platform combination."); 88 pragma(msg, "To override and enable vararg support anyway, compile with " ~ 89 "the EnableVararg version."); 90 } 91 92 private 93 { 94 /* 95 * This is used to store the actual value being kept in a Variant. 96 */ 97 struct VariantStorage 98 { 99 union 100 { 101 /* 102 * Contains heap-allocated storage for values which are too large 103 * to fit into the Variant directly. 104 */ 105 void[] heap; 106 107 /* 108 * Used to store arrays directly. Note that this is NOT an actual 109 * array; using a void[] causes the length to change, which screws 110 * up the ptr() property. 111 * 112 * WARNING: this structure MUST match the ABI for arrays for this 113 * platform. AFAIK, all compilers implement arrays this way. 114 * There needs to be a case in the unit test to ensure this. 115 */ 116 struct Array 117 { 118 size_t length; 119 const(void)* ptr; 120 } 121 Array array; 122 123 // Used to simplify dealing with objects. 124 Object obj; 125 126 // Used to address storage as an array. 127 ubyte[array.sizeof] data; 128 } 129 130 /* 131 * This is used to set the array structure safely. We're essentially 132 * just ensuring that if a garbage collection happens mid-assign, we 133 * don't accidentally mark bits of memory we shouldn't. 134 * 135 * Of course, the compiler could always re-order the length and ptr 136 * assignment. Oh well. 137 */ 138 void setArray(const(void)* ptr, size_t length) 139 { 140 array.length = 0; 141 array.ptr = ptr; 142 array.length = length; 143 } 144 } 145 146 // Determines if the given type is an Object (class) type. 147 template isObject(T) 148 { 149 static if( is( T : Object ) ) 150 enum isObject = true; 151 else 152 enum isObject = false; 153 } 154 155 // Determines if the given type is an interface 156 template isInterface(T) 157 { 158 static if( is( T == interface ) ) 159 enum isInterface = true; 160 else 161 enum isInterface = false; 162 } 163 164 // A list of all basic types 165 alias Tuple!(bool, char, wchar, dchar, 166 byte, short, int, long, //cent, 167 ubyte, ushort, uint, ulong, //ucent, 168 float, double, real, 169 ifloat, idouble, ireal, 170 cfloat, cdouble, creal) BasicTypes; 171 172 // see isBasicType 173 template isBasicTypeImpl(T, U) 174 { 175 enum isBasicTypeImpl = is( T == U ); 176 } 177 178 // see isBasicType 179 template isBasicTypeImpl(T, U, Us...) 180 { 181 static if( is( T == U ) ) 182 enum isBasicTypeImpl = true; 183 else 184 enum isBasicTypeImpl = isBasicTypeImpl!(T, Us); 185 } 186 187 // Determines if the given type is one of the basic types. 188 template isBasicType(T) 189 { 190 enum isBasicType = isBasicTypeImpl!(T, BasicTypes); 191 } 192 193 /* 194 * Used to determine if we can cast a value of the given TypeInfo to the 195 * specified type implicitly. This should be somewhat faster than the 196 * version in RuntimeTraits since we can basically eliminate half of the 197 * tests. 198 */ 199 bool canImplicitCastToType(dsttypeT)(const TypeInfo srctype) 200 { 201 /* 202 * First, we'll generate tests for the basic types. The list of 203 * things which can be cast TO basic types is finite and easily 204 * computed. 205 */ 206 foreach( T ; BasicTypes ) 207 { 208 // If the current type is the target... 209 static if( is( dsttypeT == T ) ) 210 { 211 // ... then for all of the other basic types ... 212 foreach( U ; BasicTypes ) 213 { 214 static if 215 ( 216 // ... if that type is smaller than ... 217 U.sizeof < T.sizeof 218 219 // ... or the same size and signed-ness ... 220 || ( U.sizeof == T.sizeof && 221 ((isCharType!(T) || isUnsignedIntegerType!(T)) 222 ^ !(isCharType!(U) || isUnsignedIntegerType!(U))) 223 ) 224 ) 225 { 226 // ... test. 227 if( srctype is typeid(U) ) 228 return true; 229 } 230 } 231 // Nothing matched; no implicit casting. 232 return false; 233 } 234 } 235 236 /* 237 * Account for static arrays being implicitly convertible to dynamic 238 * arrays. 239 */ 240 static if( is( T[] : dsttypeT ) ) 241 { 242 if( typeid(T[]) is srctype ) 243 return true; 244 245 if( auto ti_sa = cast(const(TypeInfo_StaticArray)) srctype ) 246 return ti_sa.next is typeid(T); 247 248 return false; 249 } 250 251 /* 252 * Any pointer can be cast to void*. 253 */ 254 else static if( is( dsttypeT == void* ) ) 255 return (cast(const(TypeInfo_Pointer)) srctype) !is null; 256 257 /* 258 * Any array can be cast to void[], however remember that it has to 259 * be manually adjusted to preserve the correct length. 260 */ 261 else static if( is( dsttypeT == void[] ) ) 262 return ((cast(const(TypeInfo_Array)) srctype) !is null) 263 || ((cast(const(TypeInfo_StaticArray)) srctype) !is null); 264 265 else return false; 266 } 267 268 /* 269 * Aliases itself to the type used to return a value of type T out of a 270 * function. This is basically a work-around for not being able to return 271 * static arrays. 272 */ 273 template returnT(T) 274 { 275 static if( isStaticArrayType!(T) ) 276 alias typeof(T.dup) returnT; 277 else 278 alias T returnT; 279 } 280 281 /* 282 * Here are some tests that perform runtime versions of the compile-time 283 * traits functions. 284 */ 285 286 bool isBasicTypeInfo(const(TypeInfo) ti) 287 { 288 foreach( T ; BasicTypes ) 289 if( ti is typeid(T) ) 290 return true; 291 return false; 292 } 293 294 private import RuntimeTraits = tango.core.RuntimeTraits; 295 296 alias RuntimeTraits.isStaticArray isStaticArrayTypeInfo; 297 alias RuntimeTraits.isClass isObjectTypeInfo; 298 alias RuntimeTraits.isInterface isInterfaceTypeInfo; 299 } 300 301 /** 302 * This exception is thrown whenever you attempt to get the value of a Variant 303 * without using a compatible type. 304 */ 305 class VariantTypeMismatchException : Exception 306 { 307 this(const(TypeInfo) expected, const(TypeInfo) got) 308 { 309 super("cannot convert "~expected.toString() 310 ~" value to a "~got.toString()); 311 } 312 } 313 314 /** 315 * This exception is thrown when you attempt to use an empty Variant with 316 * varargs. 317 */ 318 class VariantVoidVarargException : Exception 319 { 320 this() 321 { 322 super("cannot use Variants containing a void with varargs"); 323 } 324 } 325 326 /** 327 * The Variant type is used to dynamically store values of different types at 328 * runtime. 329 * 330 * You can create a Variant using either the pseudo-constructor or direct 331 * assignment. 332 * 333 * ----- 334 * Variant v = Variant(42); 335 * v = "abc"; 336 * ----- 337 */ 338 struct Variant 339 { 340 /** 341 * This pseudo-constructor is used to place a value into a new Variant. 342 * 343 * Params: 344 * value = The value you wish to put in the Variant. 345 * 346 * Returns: 347 * The new Variant. 348 * 349 * Example: 350 * ----- 351 * auto v = Variant(42); 352 * ----- 353 */ 354 static Variant opCall(T)(T value) 355 { 356 Variant _this; 357 358 static if( isStaticArrayType!(T) ) 359 _this = value.dup; 360 361 else 362 _this = value; 363 364 return _this; 365 } 366 367 /** 368 * This pseudo-constructor creates a new Variant using a specified 369 * TypeInfo and raw pointer to the value. 370 * 371 * Params: 372 * type = Type of the value. 373 * ptr = Pointer to the value. 374 * 375 * Returns: 376 * The new Variant. 377 * 378 * Example: 379 * ----- 380 * int life = 42; 381 * auto v = Variant(typeid(typeof(life)), &life); 382 * ----- 383 */ 384 static Variant opCall()(const TypeInfo type, void* ptr) 385 { 386 Variant _this; 387 Variant.fromPtr(type, ptr, _this); 388 return _this; 389 } 390 391 /** 392 * This operator allows you to assign arbitrary values directly into an 393 * existing Variant. 394 * 395 * Params: 396 * value = The value you wish to put in the Variant. 397 * 398 * Returns: 399 * The new value of the assigned-to variant. 400 * 401 * Example: 402 * ----- 403 * Variant v; 404 * v = 42; 405 * ----- 406 */ 407 Variant opAssign(T)(T value) 408 { 409 static if( isStaticArrayType!(T) ) 410 { 411 return (this = value.dup); 412 } 413 else static if( is(T == Variant) ) 414 { 415 type = value.type; 416 this.value = value.value; 417 return this; 418 } 419 else 420 { 421 type = typeid(T); 422 423 static if( isDynamicArrayType!(T) ) 424 { 425 this.value.setArray(value.ptr, value.length); 426 } 427 else static if( isInterface!(T) ) 428 { 429 this.value.obj = cast(Object) value; 430 } 431 else 432 { 433 /* 434 * If the value is small enough to fit in the storage 435 * available, do so. If it isn't, then make a heap copy. 436 * 437 * Obviously, this pretty clearly breaks value semantics for 438 * large values, but without a postblit operator, there's not 439 * much we can do. :( 440 */ 441 static if( T.sizeof <= this.value.data.length ) 442 { 443 this.value.data[0..T.sizeof] = 444 (cast(ubyte*)&value)[0..T.sizeof]; 445 } 446 else 447 { 448 auto buffer = (cast(ubyte*)&value)[0..T.sizeof].dup; 449 this.value.heap = cast(void[])buffer; 450 } 451 } 452 return this; 453 } 454 } 455 456 /** 457 * This member can be used to determine if the value stored in the Variant 458 * is of the specified type. Note that this comparison is exact: it does 459 * not take implicit casting rules into account. 460 * 461 * Returns: 462 * true if the Variant contains a value of type T, false otherwise. 463 * 464 * Example: 465 * ----- 466 * auto v = Variant(cast(int) 42); 467 * assert( v.isA!(int) ); 468 * assert( ! v.isA!(short) ); // note no implicit conversion 469 * ----- 470 */ 471 @property bool isA(T)() 472 { 473 return cast(bool)(typeid(T) is type); 474 } 475 476 /** 477 * This member can be used to determine if the value stored in the Variant 478 * is of the specified type. This comparison attempts to take implicit 479 * conversion rules into account. 480 * 481 * Returns: 482 * true if the Variant contains a value of type T, or if the Variant 483 * contains a value that can be implicitly cast to type T; false 484 * otherwise. 485 * 486 * Example: 487 * ----- 488 * auto v = Variant(cast(int) 42); 489 * assert( v.isA!(int) ); 490 * assert( v.isA!(short) ); // note implicit conversion 491 * ----- 492 */ 493 @property bool isImplicitly(T)() 494 { 495 static if( is( T == class ) || is( T == interface ) ) 496 { 497 // Check for classes and interfaces first. 498 if( cast(TypeInfo_Class) type || cast(TypeInfo_Interface) type ) 499 return (cast(T) value.obj) !is null; 500 501 else 502 // We're trying to cast TO an object, but we don't have 503 // an object stored. 504 return false; 505 } 506 else 507 { 508 // Test for basic types (oh, and dynamic->static arrays and 509 // pointers.) 510 return ( cast(bool)(typeid(T) is type) 511 || canImplicitCastToType!(T)(type) ); 512 } 513 } 514 515 /** 516 * This determines whether the Variant has an assigned value or not. It 517 * is simply short-hand for calling the isA member with a type of void. 518 * 519 * Returns: 520 * true if the Variant does not contain a value, false otherwise. 521 */ 522 @property bool isEmpty() 523 { 524 return isA!(void); 525 } 526 527 /** 528 * This member will clear the Variant, returning it to an empty state. 529 */ 530 void clear() 531 { 532 _type = typeid(void); 533 value = value.init; 534 } 535 536 version( DDoc ) 537 { 538 /** 539 * This is the primary mechanism for extracting a value from a Variant. 540 * Given a destination type S, it will attempt to extract the value of the 541 * Variant into that type. If the value contained within the Variant 542 * cannot be implicitly cast to the given type S, it will throw an 543 * exception. 544 * 545 * You can check to see if this operation will fail by calling the 546 * isImplicitly member with the type S. 547 * 548 * Note that attempting to get a statically-sized array will result in a 549 * dynamic array being returned; this is a language limitation. 550 * 551 * Returns: 552 * The value stored within the Variant. 553 */ 554 @property T get(T)() 555 { 556 // For actual implementation, see below. 557 } 558 } 559 else 560 { 561 @property returnT!(S) get(S)() 562 { 563 alias returnT!(S) T; 564 565 // If we're not dealing with the exact same type as is being 566 // stored, we fail NOW if the type in question isn't an object (we 567 // can let the runtime do the test) and if it isn't something we 568 // know we can implicitly cast to. 569 if( type !is typeid(T) 570 // Let D do runtime check itself 571 && !isObject!(T) 572 && !isInterface!(T) 573 574 // Allow implicit upcasts 575 && !canImplicitCastToType!(T)(type) 576 ) 577 throw new VariantTypeMismatchException(type,typeid(T)); 578 579 // Handle basic types, since they account for most of the implicit 580 // casts. 581 static if( isBasicType!(T) ) 582 { 583 if( type is typeid(T) ) 584 { 585 // We got lucky; the types match exactly. If the type is 586 // small, grab it out of storage; otherwise, copy it from 587 // the heap. 588 static if( T.sizeof <= value.sizeof ) 589 return *cast(T*)(&value); 590 591 else 592 return *cast(T*)(value.heap.ptr); 593 } 594 else 595 { 596 // This handles implicit coercion. What it does is finds 597 // the basic type U which is actually being stored. It 598 // then unpacks the value of type U stored in the Variant 599 // and casts it to type T. 600 // 601 // It is assumed that this is valid to perform since we 602 // should have already eliminated invalid coercions. 603 foreach( U ; BasicTypes ) 604 { 605 if( type is typeid(U) ) 606 { 607 static if( U.sizeof <= value.sizeof ) 608 return cast(T) *cast(U*)(&value); 609 610 else 611 return cast(T) *cast(U*)(value.heap.ptr); 612 } 613 } 614 throw new VariantTypeMismatchException(type,typeid(T)); 615 } 616 } 617 else static if( isDynamicArrayType!(T) ) 618 { 619 return (cast(typeof(T.init.ptr)) value.array.ptr) 620 [0..value.array.length]; 621 } 622 else static if( isObject!(T) || isInterface!(T) ) 623 { 624 return cast(T)this.value.obj; 625 } 626 else 627 { 628 static if( T.sizeof <= this.value.data.length ) 629 { 630 T result; 631 (cast(ubyte*)&result)[0..T.sizeof] = 632 this.value.data[0..T.sizeof]; 633 return result; 634 } 635 else 636 { 637 T result; 638 (cast(ubyte*)&result)[0..T.sizeof] = 639 (cast(ubyte[])this.value.heap)[0..T.sizeof]; 640 return result; 641 } 642 } 643 } 644 } 645 646 /** 647 * The following operator overloads are defined for the sake of 648 * convenience. It is important to understand that they do not allow you 649 * to use a Variant as both the left-hand and right-hand sides of an 650 * expression. One side of the operator must be a concrete type in order 651 * for the Variant to know what code to generate. 652 */ 653 auto opBinary(immutable(char)[] op, T)(T rhs) 654 { 655 mixin("return get!(T) " ~ op ~ " rhs;"); 656 } 657 658 auto opBinaryRight(immutable(char)[] op, T)(T lhs) 659 { 660 mixin("return lhs " ~ op ~ " get!(T);"); 661 } 662 663 Variant opOpAssign(immutable(char)[] op, T)(T value) 664 { 665 mixin("return (this = get!(T) " ~ op ~ " value);"); 666 } 667 668 /** 669 * The following operators can be used with Variants on both sides. Note 670 * that these operators do not follow the standard rules of 671 * implicit conversions. 672 */ 673 int opEquals(T)(T rhs) 674 { 675 static if( is( T == Variant ) ) 676 return opEqualsVariant(rhs); 677 678 else 679 return get!(T) == rhs; 680 } 681 682 bool opEquals(const ref Variant other) const 683 { 684 return opEqualsVariant(other) != 0; 685 } 686 687 /* This opCmp is not detectable as one for the purposes of TypeInfo_Struct.xopCmp. 688 * Try doing opCmp(const ref Variant) and opCmp(...). My tests indicate that this may work. */ 689 /// ditto 690 int opCmp(T)(T rhs) 691 { 692 static if( is( T == Variant ) ) 693 return opCmpVariant(rhs); 694 else 695 { 696 auto lhs = get!(T); 697 return (lhs < rhs) ? -1 : (lhs == rhs) ? 0 : 1; 698 } 699 } 700 701 /// ditto 702 hash_t toHash() const nothrow @safe 703 { 704 return type.getHash(this.ptr); 705 } 706 707 /** 708 * Returns a string representation of the type being stored in this 709 * Variant. 710 * 711 * Returns: 712 * The string representation of the type contained within the Variant. 713 */ 714 string toString() 715 { 716 return type.toString(); 717 } 718 719 /** 720 * This can be used to retrieve the TypeInfo for the currently stored 721 * value. 722 */ 723 @property const(TypeInfo) type() const nothrow @safe 724 { 725 return _type; 726 } 727 728 /** 729 * This can be used to retrieve a pointer to the value stored in the 730 * variant. 731 */ 732 @property inout(void*) ptr() inout nothrow @trusted 733 { 734 if( type.tsize <= value.sizeof ) 735 return &value; 736 737 else 738 return value.heap.ptr; 739 } 740 741 version( EnableVararg ) 742 { 743 /** 744 * Converts a vararg function argument list into an array of Variants. 745 */ 746 static Variant[] fromVararg(const(TypeInfo[]) types, void* args) 747 { 748 auto vs = new Variant[](types.length); 749 750 foreach( i, ref v ; vs ) 751 { 752 version(DigitalMarsX64) 753 { 754 scope void[] buffer = new void[types[i].tsize]; 755 va_arg(*cast(va_list*)&args, cast(TypeInfo)types[i], buffer.ptr); 756 Variant.fromPtr(types[i], buffer.ptr, v); 757 } 758 else 759 { 760 args = Variant.fromPtr(types[i], args, v); 761 } 762 } 763 764 return vs; 765 } 766 767 /// ditto 768 static Variant[] fromVararg(...) 769 { 770 return Variant.fromVararg(_arguments, _argptr); 771 } 772 773 /+ 774 /** 775 * Converts an array of Variants into a vararg function argument list. 776 * 777 * This will allocate memory to store the arguments in; you may destroy 778 * this memory when you are done with it if you feel so inclined. 779 */ 780 deprecated static void toVararg(Variant[] vars, out TypeInfo[] types, out va_list args) 781 { 782 // First up, compute the total amount of space we'll need. While 783 // we're at it, work out if any of the values we're storing have 784 // pointers. If they do, we'll need to tell the GC. 785 size_t size = 0; 786 bool noptr = true; 787 foreach( ref v ; vars ) 788 { 789 auto ti = v.type; 790 size += (ti.tsize + size_t.sizeof-1) & ~(size_t.sizeof-1); 791 noptr = noptr && (ti.flags & 2); 792 } 793 794 // Create the storage, and tell the GC whether it needs to be scanned 795 // or not. 796 auto storage = new ubyte[size]; 797 GC.setAttr(storage.ptr, 798 (GC.getAttr(storage.ptr) & ~GC.BlkAttr.NO_SCAN) 799 | (noptr ? GC.BlkAttr.NO_SCAN : 0)); 800 801 // Dump the variants into the storage. 802 args = storage.ptr; 803 auto arg_temp = args; 804 805 types = new TypeInfo[vars.length]; 806 807 foreach( i, ref v ; vars ) 808 { 809 types[i] = v.type; 810 arg_temp = v.toPtr(arg_temp); 811 } 812 } 813 +/ 814 } // version( EnableVararg ) 815 816 private: 817 TypeInfo _type = typeid(void); 818 VariantStorage value; 819 820 @property const(TypeInfo) type(const(TypeInfo) v) 821 { 822 return (_type = cast(TypeInfo)v); 823 } 824 825 /* 826 * Creates a Variant using a given TypeInfo and a void*. Returns the 827 * given pointer adjusted for the next vararg. 828 */ 829 static void* fromPtr(const TypeInfo type, void* ptr, out Variant r) 830 in 831 { 832 assert(type !is null); 833 } 834 do 835 { 836 /* 837 * This function basically duplicates the functionality of 838 * opAssign, except that we can't generate code based on the 839 * type of the data we're storing. 840 */ 841 842 if( type is typeid(void) ) 843 throw new VariantVoidVarargException; 844 845 r.type = type; 846 847 if( isStaticArrayTypeInfo(type) ) 848 { 849 /* 850 * Static arrays are passed by-value; for example, if type is 851 * typeid(int[4]), then ptr is a pointer to 16 bytes of memory 852 * (four 32-bit integers). 853 * 854 * It's possible that the memory being pointed to is on the 855 * stack, so we need to copy it before storing it. type.tsize 856 * tells us exactly how many bytes we need to copy. 857 * 858 * Sadly, we can't directly construct the dynamic array version 859 * of type. We'll store the static array type and cope with it 860 * in isImplicitly(S) and get(S). 861 */ 862 r.value.heap = ptr[0 .. type.tsize].dup; 863 } 864 else 865 { 866 if( isObjectTypeInfo(type) 867 || isInterfaceTypeInfo(type) ) 868 { 869 /* 870 * We have to call into the core runtime to turn this pointer 871 * into an actual Object reference. 872 */ 873 r.value.obj = _d_toObject(*cast(void**)ptr); 874 } 875 else 876 { 877 if( type.tsize <= this.value.data.length ) 878 { 879 // Copy into storage 880 r.value.data[0 .. type.tsize] = 881 (cast(ubyte*)ptr)[0 .. type.tsize]; 882 } 883 else 884 { 885 // Store in heap 886 auto buffer = (cast(ubyte*)ptr)[0 .. type.tsize].dup; 887 r.value.heap = cast(void[])buffer; 888 } 889 } 890 } 891 892 // Compute the "advanced" pointer. 893 return ptr + ( (type.tsize + size_t.sizeof-1) & ~(size_t.sizeof-1) ); 894 } 895 896 /+version( EnableVararg ) 897 { 898 /* 899 * Takes the current Variant, and dumps its contents into memory pointed 900 * at by a void*, suitable for vararg calls. 901 * 902 * It also returns the supplied pointer adjusted by the size of the data 903 * written to memory. 904 */ 905 void* toPtr(void* ptr) 906 { 907 version( GNU ) 908 { 909 pragma(msg, "WARNING: tango.core.Variant's vararg support has " 910 "not been tested with this compiler." ); 911 } 912 version( LDC ) 913 { 914 pragma(msg, "WARNING: tango.core.Variant's vararg support has " 915 "not been tested with this compiler." ); 916 } 917 918 if( type is typeid(void) ) 919 throw new VariantVoidVarargException; 920 921 if( isStaticArrayTypeInfo(type) ) 922 { 923 // Just dump straight 924 ptr[0 .. type.tsize] = this.value.heap[0 .. type.tsize]; 925 } 926 else 927 { 928 if( isInterfaceTypeInfo(type) ) 929 { 930 /* 931 * This is tricky. What we actually have stored in 932 * value.obj is an Object, not an interface. What we 933 * need to do is manually "cast" value.obj to the correct 934 * interface. 935 * 936 * We have the original interface's TypeInfo. This gives us 937 * the interface's ClassInfo. We can also obtain the object's 938 * ClassInfo which contains a list of Interfaces. 939 * 940 * So what we need to do is loop over the interfaces obj 941 * implements until we find the one we're interested in. Then 942 * we just read out the interface's offset and adjust obj 943 * accordingly. 944 */ 945 auto type_i = cast(TypeInfo_Interface) type; 946 bool found = false; 947 foreach( i ; this.value.obj.classinfo.interfaces ) 948 { 949 if( i.classinfo is type_i.info ) 950 { 951 // Found it 952 void* i_ptr = (cast(void*) this.value.obj) + i.offset; 953 *cast(void**)ptr = i_ptr; 954 found = true; 955 break; 956 } 957 } 958 assert(found,"Could not convert Object to interface; " 959 "bad things have happened."); 960 } 961 else 962 { 963 if( type.tsize <= this.value.data.length ) 964 { 965 // Value stored in storage 966 ptr[0 .. type.tsize] = this.value.data[0 .. type.tsize]; 967 } 968 else 969 { 970 // Value stored on heap 971 ptr[0 .. type.tsize] = this.value.heap[0 .. type.tsize]; 972 } 973 } 974 } 975 976 // Compute the "advanced" pointer. 977 return ptr + ( (type.tsize + size_t.sizeof-1) & ~(size_t.sizeof-1) ); 978 } 979 } // version( EnableVararg ) 980 +/ 981 982 /* 983 * Performs a type-dependant comparison. Note that this obviously doesn't 984 * take into account things like implicit conversions. 985 */ 986 int opEqualsVariant(const ref Variant rhs) const 987 { 988 if( type != rhs.type ) return false; 989 return cast(bool) type.equals(this.ptr, rhs.ptr); 990 } 991 992 /* 993 * Same as opEqualsVariant except it does opCmp. 994 */ 995 int opCmpVariant(Variant rhs) 996 { 997 if( type != rhs.type ) 998 throw new VariantTypeMismatchException(type, rhs.type); 999 return type.compare(this.ptr, rhs.ptr); 1000 } 1001 } 1002 1003 debug( UnitTest ) 1004 { 1005 /* 1006 * Language tests. 1007 */ 1008 1009 unittest 1010 { 1011 { 1012 int[2] a; 1013 void[] b = a; 1014 int[] c = cast(int[]) b; 1015 assert( b.length == 2*int.sizeof ); 1016 assert( c.length == a.length ); 1017 } 1018 1019 { 1020 struct A { size_t l; void* p; } 1021 const(char)[] b = "123"; 1022 A a = *cast(A*)(&b); 1023 1024 assert( a.l == b.length ); 1025 assert( a.p == b.ptr ); 1026 } 1027 } 1028 1029 /* 1030 * Basic tests. 1031 */ 1032 1033 unittest 1034 { 1035 Variant v; 1036 assert( v.isA!(void), v.type.toString() ); 1037 assert( v.isEmpty, v.type.toString() ); 1038 1039 // Test basic integer storage and implicit casting support 1040 v = 42; 1041 assert( v.isA!(int), v.type.toString() ); 1042 assert( v.isImplicitly!(long), v.type.toString() ); 1043 assert( v.isImplicitly!(ulong), v.type.toString() ); 1044 assert( !v.isImplicitly!(uint), v.type.toString() ); 1045 assert( v.get!(int) == 42 ); 1046 assert( v.get!(long) == 42L ); 1047 assert( v.get!(ulong) == 42uL ); 1048 1049 // Test clearing 1050 v.clear(); 1051 assert( v.isA!(void), v.type.toString() ); 1052 assert( v.isEmpty, v.type.toString() ); 1053 1054 // Test strings 1055 v = "Hello, World!"c; 1056 assert( v.isA!(immutable(char)[]), v.type.toString() ); 1057 assert( !v.isImplicitly!(wchar[]), v.type.toString() ); 1058 assert( v.get!(immutable(char)[]) == "Hello, World!" ); 1059 1060 // Test array storage 1061 v = [1,2,3,4,5]; 1062 assert( v.isA!(int[]), v.type.toString() ); 1063 assert( v.get!(int[]) == [1,2,3,4,5] ); 1064 1065 // Make sure arrays are correctly stored so that .ptr works. 1066 { 1067 int[] a = [1,2,3,4,5]; 1068 v = a; 1069 auto b = *cast(int[]*)(v.ptr); 1070 1071 assert( a.ptr == b.ptr ); 1072 assert( a.length == b.length ); 1073 } 1074 1075 // Test pointer storage 1076 v = &v; 1077 assert( v.isA!(Variant*), v.type.toString() ); 1078 assert( !v.isImplicitly!(int*), v.type.toString() ); 1079 assert( v.isImplicitly!(void*), v.type.toString() ); 1080 assert( v.get!(Variant*) == &v ); 1081 1082 // Test object storage 1083 { 1084 scope o = new Object; 1085 v = o; 1086 assert( v.isA!(Object), v.type.toString() ); 1087 assert( v.get!(Object) is o ); 1088 } 1089 1090 // Test interface support 1091 { 1092 interface A {} 1093 interface B : A {} 1094 class C : B {} 1095 class D : C {} 1096 1097 A a = new D; 1098 Variant v2 = a; 1099 B b = v2.get!(B); 1100 C c = v2.get!(C); 1101 D d = v2.get!(D); 1102 } 1103 1104 // Test class/interface implicit casting 1105 { 1106 class G {} 1107 interface H {} 1108 class I : G {} 1109 class J : H {} 1110 struct K {} 1111 1112 scope a = new G; 1113 scope c = new I; 1114 scope d = new J; 1115 K e; 1116 1117 Variant v2 = a; 1118 assert( v2.isImplicitly!(Object), v2.type.toString() ); 1119 assert( v2.isImplicitly!(G), v2.type.toString() ); 1120 assert(!v2.isImplicitly!(I), v2.type.toString() ); 1121 1122 v2 = c; 1123 assert( v2.isImplicitly!(Object), v2.type.toString() ); 1124 assert( v2.isImplicitly!(G), v2.type.toString() ); 1125 assert( v2.isImplicitly!(I), v2.type.toString() ); 1126 1127 v2 = d; 1128 assert( v2.isImplicitly!(Object), v2.type.toString() ); 1129 assert(!v2.isImplicitly!(G), v2.type.toString() ); 1130 assert( v2.isImplicitly!(H), v2.type.toString() ); 1131 assert( v2.isImplicitly!(J), v2.type.toString() ); 1132 1133 v2 = e; 1134 assert(!v2.isImplicitly!(Object), v2.type.toString() ); 1135 } 1136 1137 // Test doubles and implicit casting 1138 v = 3.1413; 1139 assert( v.isA!(double), v.type.toString() ); 1140 assert( v.isImplicitly!(real), v.type.toString() ); 1141 assert( !v.isImplicitly!(float), v.type.toString() ); 1142 assert( v.get!(double) == 3.1413 ); 1143 1144 // Test storage transitivity 1145 auto u = Variant(v); 1146 assert( u.isA!(double), u.type.toString() ); 1147 assert( u.get!(double) == 3.1413 ); 1148 1149 // Test operators 1150 v = 38; 1151 assert( v + 4 == 42 ); 1152 assert( 4 + v == 42 ); 1153 assert( v - 4 == 34 ); 1154 assert( 4 - v == -34 ); 1155 assert( v * 2 == 76 ); 1156 assert( 2 * v == 76 ); 1157 assert( v / 2 == 19 ); 1158 assert( 2 / v == 0 ); 1159 assert( v % 2 == 0 ); 1160 assert( 2 % v == 2 ); 1161 assert( (v & 6) == 6 ); 1162 assert( (6 & v) == 6 ); 1163 assert( (v | 9) == 47 ); 1164 assert( (9 | v) == 47 ); 1165 assert( (v ^ 5) == 35 ); 1166 assert( (5 ^ v) == 35 ); 1167 assert( v << 1 == 76 ); 1168 assert( 1 << Variant(2) == 4 ); 1169 assert( v >> 1 == 19 ); 1170 assert( 4 >> Variant(2) == 1 ); 1171 1172 assert( Variant("abc") ~ "def" == "abcdef" ); 1173 assert( "abc" ~ Variant("def") == "abcdef" ); 1174 1175 // Test op= operators 1176 v = 38; v += 4; assert( v == 42 ); 1177 v = 38; v -= 4; assert( v == 34 ); 1178 v = 38; v *= 2; assert( v == 76 ); 1179 v = 38; v /= 2; assert( v == 19 ); 1180 v = 38; v %= 2; assert( v == 0 ); 1181 v = 38; v &= 6; assert( v == 6 ); 1182 v = 38; v |= 9; assert( v == 47 ); 1183 v = 38; v ^= 5; assert( v == 35 ); 1184 v = 38; v <<= 1; assert( v == 76 ); 1185 v = 38; v >>= 1; assert( v == 19 ); 1186 1187 v = "abc"; v ~= "def"; assert( v == "abcdef" ); 1188 1189 // Test comparison 1190 assert( Variant(0) < Variant(42) ); 1191 assert( Variant(42) > Variant(0) ); 1192 assert( Variant(21) == Variant(21) ); 1193 assert( Variant(0) != Variant(42) ); 1194 assert( Variant("bar") == Variant("bar") ); 1195 assert( Variant("foo") != Variant("bar") ); 1196 1197 // Test variants as AA keys 1198 static if(DMDFE_Version != 2065 && DMDFE_Version != 2066) 1199 { 1200 { 1201 auto v1 = Variant(42); 1202 auto v2 = Variant("foo"); 1203 auto v3 = Variant(1+2.0i); 1204 1205 int[Variant] hash; 1206 hash[v1] = 0; 1207 hash[v2] = 1; 1208 hash[v3] = 2; 1209 1210 assert( hash[v1] == 0 ); 1211 assert( hash[v2] == 1 ); 1212 assert( hash[v3] == 2 ); 1213 } 1214 } 1215 1216 // Test AA storage 1217 { 1218 int[char[]] hash; 1219 hash["a"] = 1; 1220 hash["b"] = 2; 1221 hash["c"] = 3; 1222 Variant vhash = hash; 1223 1224 assert( vhash.get!(int[char[]])["a"] == 1 ); 1225 assert( vhash.get!(int[char[]])["b"] == 2 ); 1226 assert( vhash.get!(int[char[]])["c"] == 3 ); 1227 } 1228 } 1229 1230 /* 1231 * Vararg tests. 1232 */ 1233 1234 version( EnableVararg ) 1235 { 1236 private import tango.core.Vararg; 1237 1238 unittest 1239 { 1240 class A 1241 { 1242 @property const(char)[] msg() { return "A"; } 1243 } 1244 class B : A 1245 { 1246 @property override const(char)[] msg() { return "B"; } 1247 } 1248 interface C 1249 { 1250 @property const(char)[] name(); 1251 } 1252 class D : B, C 1253 { 1254 @property override const(char)[] msg() { return "D"; } 1255 @property override const(char)[] name() { return "phil"; } 1256 } 1257 1258 struct S { int a, b, c, d; } 1259 1260 Variant[] scoop(...) 1261 { 1262 return Variant.fromVararg(_arguments, _argptr); 1263 } 1264 1265 auto va_0 = cast(char) '?'; 1266 auto va_1 = cast(short) 42; 1267 auto va_2 = cast(int) 1701; 1268 auto va_3 = cast(long) 9001; 1269 auto va_4 = cast(float) 3.14; 1270 auto va_5 = cast(double)2.14; 1271 auto va_6 = cast(real) 0.1; 1272 auto va_7 = "abcd"[]; 1273 S va_8 = { 1, 2, 3, 4 }; 1274 A va_9 = new A; 1275 B va_a = new B; 1276 C va_b = new D; 1277 D va_c = new D; 1278 1279 auto vs = scoop(va_0, va_1, va_2, va_3, 1280 va_4, va_5, va_6, va_7, 1281 va_8, va_9, va_a, va_b, va_c); 1282 1283 assert( vs[0x0].get!(typeof(va_0)) == va_0 ); 1284 assert( vs[0x1].get!(typeof(va_1)) == va_1 ); 1285 assert( vs[0x2].get!(typeof(va_2)) == va_2 ); 1286 assert( vs[0x3].get!(typeof(va_3)) == va_3 ); 1287 assert( vs[0x4].get!(typeof(va_4)) == va_4 ); 1288 assert( vs[0x5].get!(typeof(va_5)) == va_5 ); 1289 assert( vs[0x6].get!(typeof(va_6)) == va_6 ); 1290 assert( vs[0x7].get!(typeof(va_7)) == va_7 ); 1291 assert( vs[0x8].get!(typeof(va_8)) == va_8 ); 1292 assert( vs[0x9].get!(typeof(va_9)) is va_9 ); 1293 assert( vs[0xa].get!(typeof(va_a)) is va_a ); 1294 assert( vs[0xb].get!(typeof(va_b)) is va_b ); 1295 assert( vs[0xc].get!(typeof(va_c)) is va_c ); 1296 1297 assert( vs[0x9].get!(typeof(va_9)).msg == "A" ); 1298 assert( vs[0xa].get!(typeof(va_a)).msg == "B" ); 1299 assert( vs[0xc].get!(typeof(va_c)).msg == "D" ); 1300 1301 assert( vs[0xb].get!(typeof(va_b)).name == "phil" ); 1302 assert( vs[0xc].get!(typeof(va_c)).name == "phil" ); 1303 1304 /+ 1305 version (none) version(X86) // TODO toVararg won't work in x86_64 as it is now 1306 { 1307 TypeInfo[] types; 1308 void* args; 1309 1310 Variant.toVararg(vs, types, args); 1311 1312 assert( types[0x0] is typeid(typeof(va_0)) ); 1313 assert( types[0x1] is typeid(typeof(va_1)) ); 1314 assert( types[0x2] is typeid(typeof(va_2)) ); 1315 assert( types[0x3] is typeid(typeof(va_3)) ); 1316 assert( types[0x4] is typeid(typeof(va_4)) ); 1317 assert( types[0x5] is typeid(typeof(va_5)) ); 1318 assert( types[0x6] is typeid(typeof(va_6)) ); 1319 assert( types[0x7] is typeid(typeof(va_7)) ); 1320 assert( types[0x8] is typeid(typeof(va_8)) ); 1321 assert( types[0x9] is typeid(typeof(va_9)) ); 1322 assert( types[0xa] is typeid(typeof(va_a)) ); 1323 assert( types[0xb] is typeid(typeof(va_b)) ); 1324 assert( types[0xc] is typeid(typeof(va_c)) ); 1325 1326 auto ptr = args; 1327 1328 auto vb_0 = va_arg!(typeof(va_0))(ptr); 1329 auto vb_1 = va_arg!(typeof(va_1))(ptr); 1330 auto vb_2 = va_arg!(typeof(va_2))(ptr); 1331 auto vb_3 = va_arg!(typeof(va_3))(ptr); 1332 auto vb_4 = va_arg!(typeof(va_4))(ptr); 1333 auto vb_5 = va_arg!(typeof(va_5))(ptr); 1334 auto vb_6 = va_arg!(typeof(va_6))(ptr); 1335 auto vb_7 = va_arg!(typeof(va_7))(ptr); 1336 auto vb_8 = va_arg!(typeof(va_8))(ptr); 1337 auto vb_9 = va_arg!(typeof(va_9))(ptr); 1338 auto vb_a = va_arg!(typeof(va_a))(ptr); 1339 auto vb_b = va_arg!(typeof(va_b))(ptr); 1340 auto vb_c = va_arg!(typeof(va_c))(ptr); 1341 1342 assert( vb_0 == va_0 ); 1343 assert( vb_1 == va_1 ); 1344 assert( vb_2 == va_2 ); 1345 assert( vb_3 == va_3 ); 1346 assert( vb_4 == va_4 ); 1347 assert( vb_5 == va_5 ); 1348 assert( vb_6 == va_6 ); 1349 assert( vb_7 == va_7 ); 1350 assert( vb_8 == va_8 ); 1351 assert( vb_9 is va_9 ); 1352 assert( vb_a is va_a ); 1353 assert( vb_b is va_b ); 1354 assert( vb_c is va_c ); 1355 1356 assert( vb_9.msg == "A" ); 1357 assert( vb_a.msg == "B" ); 1358 assert( vb_c.msg == "D" ); 1359 1360 assert( vb_b.name == "phil" ); 1361 assert( vb_c.name == "phil" ); 1362 } 1363 +/ 1364 } 1365 } 1366 }