Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 1753

Show
Ignore:
Timestamp:
07/13/10 01:12:45 (14 years ago)
Author:
rsinfu
Message:

[devel] Moved typecons.Any -> variant.Algebraic with a few improvements.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/devel/stdio-native-codeset/phobos/std/typecons.d

    r1737 r1753  
    21962196            auto another = this; 
    21972197            return another; 
    21982198        } 
    21992199    } 
    22002200    auto a = A(4); 
    22012201    auto b = a.copy(); 
    22022202    if (a.x._refCountedStore._count != 2) { 
    22032203        stderr.writeln("*** BUG 4356 still unfixed"); 
    22042204    } 
    22052205} 
    2206  
    2207  
    2208 /*-* 
    2209  * Provides ad-hoc polymorphism on a specific group of objects that 
    2210  * have the same interface (duck-typed). 
    2211  */ 
    2212 package struct Any(Ducks...) 
    2213 { 
    2214     /** 
    2215      * Invokes the method $(D op) on the active object. 
    2216      * 
    2217      * The allowed operation $(D op) is the intersection of the allowed 
    2218      * operations on all $(D Ducks). 
    2219      * 
    2220      * Throws: 
    2221      * $(UL 
    2222      *   $(LI $(D Error) if this $(D Any) object is empty) 
    2223      * ) 
    2224      */ 
    2225     @system auto ref opDispatch(string op, Args...)(auto ref Args args) 
    2226         if (_canDispatch!(op, Args)) 
    2227     { 
    2228         if (_which == size_t.max) 
    2229             throw new Error("dispatching " ~ op ~ Args.stringof 
    2230                     ~ " on an empty " ~ typeof(this).stringof); 
    2231  
    2232         mixin (_onActiveDuck!( 
    2233             q{ 
    2234                 return mixin("_storageAs!Duck()." 
    2235                         ~ (args.length == 0 ? op : op ~ "(args)")); 
    2236             })); 
    2237         assert(0); 
    2238     } 
    2239  
    2240  
    2241     /** 
    2242      * If $(D T) is one of the $(D Ducks), alters the contained object 
    2243      * with $(D rhs); otherwise assigns $(D rhs) on the active object. 
    2244      */ 
    2245     @system void opAssign(T)(T rhs) 
    2246         if (_canAssign!(T)) 
    2247     { 
    2248         if (_which == size_t.max) 
    2249             _grab(rhs); 
    2250         else 
    2251             _assign(rhs); 
    2252     } 
    2253  
    2254     @trusted void opAssign(T)(T rhs) 
    2255         if (is(T == typeof(this))) 
    2256     { 
    2257         swap(this, rhs); 
    2258     } 
    2259  
    2260     // @@@BUG4424@@@ workaround 
    2261     private template _workaround4424() 
    2262         { @disable void opAssign(...) { assert(0); } } 
    2263     mixin _workaround4424 _workaround4424_; 
    2264  
    2265  
    2266     //----------------------------------------------------------------// 
    2267  
    2268     // operator overloads 
    2269  
    2270     @system auto ref opUnary(string op)() 
    2271     { 
    2272         if (_which == size_t.max) 
    2273             throw new Error("unary " ~ op ~ " on an empty " 
    2274                     ~ typeof(this).stringof); 
    2275  
    2276         mixin (_onActiveDuck!( 
    2277             q{ 
    2278                 return mixin(op ~ "_storageAs!Duck"); 
    2279             })); 
    2280         assert(0); 
    2281     } 
    2282  
    2283     @system auto ref opIndexUnary(string op, Indices...)(Indices indices) 
    2284     { 
    2285         if (_which == size_t.max) 
    2286             throw new Error("unary " ~ to!string(Indices.length) 
    2287                     ~ "-indexing " ~ op ~ " on an empty " 
    2288                     ~ typeof(this).stringof); 
    2289  
    2290         mixin (_onActiveDuck!( 
    2291             q{ 
    2292                 return mixin(op ~ "_storageAs!Duck[" ~ 
    2293                         _commaExpand!("indices", Indices.length) ~ "]"); 
    2294             })); 
    2295         assert(0); 
    2296     } 
    2297  
    2298     @system auto ref opSliceUnary(string op, I, J)(I i, J j) 
    2299     { 
    2300         if (_which == size_t.max) 
    2301             throw new Error("unary slicing " ~ op ~ " on an empty " 
    2302                     ~ typeof(this).stringof); 
    2303  
    2304         mixin (_onActiveDuck!( 
    2305             q{ 
    2306                 return mixin(op ~ "_storageAs!Duck[i .. j]"); 
    2307             })); 
    2308         assert(0); 
    2309     } 
    2310  
    2311     @system auto ref opSliceUnary(string op)() 
    2312     { 
    2313         if (_which == size_t.max) 
    2314             throw new Error("unary slicing " ~ op ~ " on an empty " 
    2315                     ~ typeof(this).stringof); 
    2316  
    2317         mixin (_onActiveDuck!( 
    2318             q{ 
    2319                 return mixin(op ~ "_storageAs!Duck[]"); 
    2320             })); 
    2321         assert(0); 
    2322     } 
    2323  
    2324     @system auto ref opCast(T)() 
    2325     { 
    2326         if (_which == size_t.max) 
    2327             throw new Error("casting an empty " ~ typeof(this).stringof 
    2328                     ~ " to " ~ T.stringof); 
    2329  
    2330         mixin (_onActiveDuck!( 
    2331             q{ 
    2332                 static if (is(T == Duck)) 
    2333                     return         _storageAs!Duck; 
    2334                 else 
    2335                     return cast(T) _storageAs!Duck; 
    2336             })); 
    2337         assert(0); 
    2338     } 
    2339  
    2340     @system auto ref opBinary(string op, RHS)(RHS rhs) 
    2341     { 
    2342         if (_which == size_t.max) 
    2343             throw new Error("binary " ~ op ~ " on an empty LHS " 
    2344                     ~ typeof(this).stringof ~ " and RHS " ~ RHS.stringof); 
    2345  
    2346         mixin (_onActiveDuck!( 
    2347             q{ 
    2348                 return mixin("_storageAs!Duck() " ~ op ~ " rhs"); 
    2349             })); 
    2350         assert(0); 
    2351     } 
    2352  
    2353     @system auto ref opBinaryRight(string op, LHS)(LHS lhs) 
    2354     { 
    2355         if (_which == size_t.max) 
    2356             throw new Error("binary " ~ op ~ " on LHS " ~ LHS.stringof 
    2357                     ~ "and an empty RHS " ~ typeof(this).stringof); 
    2358  
    2359         mixin (_onActiveDuck!( 
    2360             q{ 
    2361                 return mixin("lhs " ~ op ~ "_storageAs!Duck"); 
    2362             })); 
    2363         assert(0); 
    2364     } 
    2365  
    2366     @system bool opEquals(RHS)(auto ref RHS rhs) const 
    2367     { 
    2368         if (_which == size_t.max) 
    2369             throw new Error("comparing an empty " ~ typeof(this).stringof 
    2370                     ~ " with " ~ RHS.stringof); 
    2371  
    2372         mixin (_onActiveDuck!( 
    2373             q{ 
    2374                 return _storageAs_const!Duck() == rhs; 
    2375             })); 
    2376         assert(0); 
    2377     } 
    2378  
    2379     @system bool opEquals(RHS : typeof(this))(ref const RHS rhs) const 
    2380     { 
    2381         if (_which != size_t.max && _which == rhs._which) 
    2382         { 
    2383             mixin (_onActiveDuck!( 
    2384                 q{ 
    2385                     return _storageAs_const!Duck() == 
    2386                             rhs._storageAs_const!Duck; 
    2387                 })); 
    2388             assert(0); 
    2389         } 
    2390         else 
    2391         { 
    2392             return false; 
    2393         } 
    2394     } 
    2395  
    2396     @system int opCmp(RHS)(auto ref RHS rhs) const 
    2397     { 
    2398         if (_which == size_t.max) 
    2399             throw new Error("comparing an empty " ~ typeof(this).stringof 
    2400                     ~ " with " ~ RHS.stringof); 
    2401  
    2402         mixin (_onActiveDuck!( 
    2403             q{ 
    2404                 return (_storageAs_const!Duck < rhs) ? -1 : 
    2405                        (_storageAs_const!Duck > rhs) ?  1 : 0; 
    2406             })); 
    2407         assert(0); 
    2408     } 
    2409  
    2410     @system int opCmp(RHS : typeof(this))(ref const RHS rhs) const 
    2411     { 
    2412         if (_which == size_t.max || rhs._which == size_t.max) 
    2413             throw new Error("comparing empty " ~ typeof(this).stringof 
    2414                     ~ " objects"); 
    2415  
    2416         mixin (_onActiveDuck!( 
    2417             q{ 
    2418                 return -rhs.opCmp(_storageAs_const!Duck); 
    2419             })); 
    2420         assert(0); 
    2421     } 
    2422  
    2423     @system auto ref opCall(Args...)(auto ref Args args) 
    2424     { 
    2425         if (_which == size_t.max) 
    2426             throw new Error("calling an empty " ~ typeof(this).stringof 
    2427                     ~ " object"); 
    2428  
    2429         mixin (_onActiveDuck!( 
    2430             q{ 
    2431                 return _storageAs!Duck()(args); 
    2432             })); 
    2433         assert(0); 
    2434     } 
    2435  
    2436     @system auto ref opOpAssign(string op, RHS)(RHS rhs) 
    2437     { 
    2438         mixin (_onActiveDuck!( 
    2439             q{ 
    2440                 return mixin("_storageAs!Duck() " ~ op ~ "= rhs"); 
    2441             })); 
    2442         assert(0); 
    2443     } 
    2444  
    2445     @system auto ref opIndexOpAssign(string op, RHS, Indices...) 
    2446         (RHS rhs, Indices indices) 
    2447     { 
    2448         mixin (_onActiveDuck!( 
    2449             q{ 
    2450                 return mixin("_storageAs!Duck[" ~ 
    2451                         _commaExpand!("indices", Indices.length) ~ 
    2452                     "] " ~ op ~ "= rhs"); 
    2453             })); 
    2454         assert(0); 
    2455     } 
    2456  
    2457     @system auto ref opSliceOpAssign(string op, RHS, I, J)(RHS rhs, I i, J j) 
    2458     { 
    2459         mixin (_onActiveDuck!( 
    2460             q{ 
    2461                 return mixin("_storageAs!Duck[i .. j] " ~ op ~ "= rhs"); 
    2462             })); 
    2463         assert(0); 
    2464     } 
    2465  
    2466     @system auto ref opSliceOpAssign(string op, RHS)(RHS rhs) 
    2467     { 
    2468         mixin (_onActiveDuck!( 
    2469             q{ 
    2470                 return mixin("_storageAs!Duck[] " ~ op ~ "= rhs"); 
    2471             })); 
    2472         assert(0); 
    2473     } 
    2474  
    2475     @system auto ref opIndex(Indices...)(Indices indices) 
    2476     { 
    2477         mixin (_onActiveDuck!( 
    2478             q{ 
    2479                 return mixin("_storageAs!Duck[" ~ 
    2480                     _commaExpand!("indices", Indices.length) ~ "]"); 
    2481             })); 
    2482         assert(0); 
    2483     } 
    2484  
    2485     @system auto ref opSlice(I, J)(I i, J j) 
    2486     { 
    2487         mixin (_onActiveDuck!( 
    2488             q{ 
    2489                 return _storageAs!Duck[i .. j]; 
    2490             })); 
    2491         assert(0); 
    2492     } 
    2493  
    2494     @system auto ref opSlice(_Dummy = void)() 
    2495     { 
    2496         mixin (_onActiveDuck!( 
    2497             q{ 
    2498                 return _storageAs!Duck[]; 
    2499             })); 
    2500         assert(0); 
    2501     } 
    2502  
    2503     /+ 
    2504     // @@@ cannot coexist with input range primitives 
    2505     @system int opApply(Args...)(int delegate(ref Args) dg) 
    2506     { 
    2507         mixin (_onActiveDuck!( 
    2508             q{ 
    2509                 return _storageAs!Duck().opApply(dg); 
    2510             })); 
    2511     } 
    2512     +/ 
    2513  
    2514  
    2515     //----------------------------------------------------------------// 
    2516  
    2517     /** 
    2518      * Invokes the copy constructor on the active object if any. 
    2519      */ 
    2520     @system this(this) 
    2521     { 
    2522         if (_which != size_t.max) 
    2523             _postblit(); 
    2524     } 
    2525  
    2526  
    2527     /** 
    2528      * Invokes the destructor on the active object if any. 
    2529      */ 
    2530     @system ~this() 
    2531     { 
    2532         if (_which != size_t.max) 
    2533             _dispose(); 
    2534     } 
    2535  
    2536  
    2537     /** 
    2538      * The $(D Any) namespace provides various 'meta' methods 
    2539      * for operating on this $(D Any) object itself, not a 
    2540      * contained object. 
    2541      * 
    2542      * Example: 
    2543 -------------------- 
    2544 Any!(A, B) ab; 
    2545  
    2546 assert(ab.Any.empty); 
    2547 assert(ab.Any.allows!A); 
    2548  
    2549 ab = A(); 
    2550 assert(ab.Any.isActive!A); 
    2551  
    2552 A a = ab.Any.instance!A; 
    2553 -------------------- 
    2554      */ 
    2555     template _Any() 
    2556     { 
    2557         /** 
    2558          * A tuple of types that are considered homogeneous in this 
    2559          * object, i.e. the $(D Ducks). 
    2560          */ 
    2561         alias Ducks Types; 
    2562  
    2563  
    2564         /** 
    2565          * Returns $(D true) if type $(D T) is listed in the type 
    2566          * list $(D Types). 
    2567          */ 
    2568         template allows(T) // FIXME the name 
    2569         { 
    2570             enum bool allows = _homogenizes!T; 
    2571         } 
    2572  
    2573  
    2574         /** 
    2575          * Returns $(D true) if this $(D Any) object contains 
    2576          * nothing. 
    2577          */ 
    2578         @safe @property bool empty() const nothrow 
    2579         { 
    2580             return _which == size_t.max; 
    2581         } 
    2582  
    2583  
    2584         /** 
    2585          * Returns $(D true) if the type of the active object is $(D T). 
    2586          */ 
    2587         @safe bool isActive(T)() const nothrow 
    2588         { 
    2589             return _which != size_t.max && _which == _duckID!T; 
    2590         } 
    2591  
    2592  
    2593         /** 
    2594          * Touch the active object directly (by ref).  The type $(D T) 
    2595          * must be the active one, i.e. $(D isActive!T == true). 
    2596          * 
    2597          * Throws: 
    2598          * $(UL 
    2599          *   $(LI $(D assertion) fails if the $(D Any) object is 
    2600          *        empty or $(D T) is not active) 
    2601          * ) 
    2602          */ 
    2603         @trusted @property ref T instance(T)() nothrow 
    2604             if (allows!(T)) 
    2605         in 
    2606         { 
    2607             assert(_which == _duckID!T); 
    2608         } 
    2609         body 
    2610         { 
    2611             return _storageAs!T; 
    2612         } 
    2613         /+ // @@@BUG3748@@@ 
    2614         @trusted @property ref inout(T) instance(T)() inout nothrow 
    2615         +/ 
    2616     } 
    2617  
    2618     /// Ditto 
    2619     alias _Any!() Any; 
    2620  
    2621  
    2622     //----------------------------------------------------------------// 
    2623 private: 
    2624     // The internal symbols are prefixed with an underscore so that 
    2625     // opDispatch will not be blocked. @@@ 
    2626  
    2627     /* 
    2628      * Determines if the operation $(D op) is supported on all the ducks 
    2629      * and the return types are compatible. 
    2630      */ 
    2631     template _canDispatch(string op, Args...) 
    2632     { 
    2633         enum bool _canDispatch = __traits(compiles, 
    2634                 function(Args args) 
    2635                 { 
    2636                     // The operation must be supported by all ducks, and 
    2637                     // the return types must be compatible. 
    2638                     foreach (Duck; Ducks) 
    2639                     { 
    2640                         Duck duck; 
    2641                         static if (Args.length == 0) 
    2642                             return mixin("duck." ~ op); 
    2643                         else 
    2644                             return mixin("duck." ~ op ~ "(args)"); 
    2645                     } 
    2646                     assert(0); 
    2647                 }); 
    2648     } 
    2649  
    2650  
    2651     /* 
    2652      * Determines if a value of $(D T) can be assigned to at least one 
    2653      * of the ducks. 
    2654      */ 
    2655     template _canAssign(T, size_t i = 0) 
    2656     { 
    2657         static if (i < Ducks.length) 
    2658             enum bool _canAssign = 
    2659                 is(Ducks[i] == T) || 
    2660                 __traits(compiles, 
    2661                     function(ref Ducks[i] duck, T rhs) 
    2662                     { 
    2663                         duck = rhs; 
    2664                     }) 
    2665                 || _canAssign!(T, i + 1); 
    2666         else 
    2667             enum bool _canAssign = false; 
    2668     } 
    2669  
    2670     unittest 
    2671     { 
    2672         foreach (Duck; Ducks) 
    2673             assert(_canAssign!(Duck)); 
    2674         struct Unknown {} 
    2675         assert(!_canAssign!(Unknown)); 
    2676     } 
    2677  
    2678  
    2679     /* 
    2680      * Returns $(D true) if the type $(D T) is in the set of types 
    2681      * $(D Ducks). 
    2682      */ 
    2683     template _homogenizes(T) 
    2684     { 
    2685         enum bool _homogenizes = (_duckID!T != size_t.max); 
    2686     } 
    2687  
    2688     unittest 
    2689     { 
    2690         foreach (Duck; Ducks) 
    2691             assert(_homogenizes!(Duck)); 
    2692         struct Unknown {} 
    2693         assert(!_homogenizes!(Unknown)); 
    2694     } 
    2695  
    2696  
    2697     /* 
    2698      * Returns the ID of the duck of type $(D T), or $(D size_t.max) if 
    2699      * $(D T) is not in the set of the types. 
    2700      */ 
    2701     template _duckID(T, size_t id = 0) 
    2702     { 
    2703         static if (id < Ducks.length) 
    2704         { 
    2705             static if (is(T == Ducks[id])) 
    2706                 enum size_t _duckID = id; 
    2707             else 
    2708                 enum size_t _duckID = _duckID!(T, id + 1); 
    2709         } 
    2710         else 
    2711         { 
    2712             enum size_t _duckID = size_t.max; 
    2713         } 
    2714     } 
    2715  
    2716  
    2717     /* 
    2718      * Generates code for operating on the active duck. 
    2719      */ 
    2720     template _onActiveDuck(string stmt) 
    2721     { 
    2722         enum string _onActiveDuck = 
    2723                 "assert(_which != size_t.max);" ~ 
    2724             "L_chooseActive:" ~ 
    2725                 "final switch (_which) {" ~ 
    2726                     "foreach (Duck; Ducks) {" ~ 
    2727                         "case _duckID!Duck:" ~ 
    2728                             stmt ~ 
    2729                             "break L_chooseActive;" ~ 
    2730                     "}" ~ 
    2731                 "}"; 
    2732     } 
    2733  
    2734  
    2735     /* 
    2736      * Set $(D rhs) in the storage. 
    2737      */ 
    2738     @trusted void _grab(T)(ref T rhs) 
    2739     in 
    2740     { 
    2741         assert(_which == size_t.max); 
    2742     } 
    2743     body 
    2744     { 
    2745         static if (_homogenizes!(T)) 
    2746         { 
    2747             // Simple blit. 
    2748             _init(_storageAs!T); 
    2749             swap(_storageAs!T, rhs); 
    2750             _which = _duckID!T; 
    2751         } 
    2752         else 
    2753         { 
    2754             // Use the first-matching opAssign. 
    2755             foreach (Duck; Ducks) 
    2756             { 
    2757                 static if (__traits(compiles, _storageAs!Duck() = rhs)) 
    2758                 { 
    2759                     _init(_storageAs!Duck); 
    2760                     _storageAs!Duck() = rhs; 
    2761                     _which = _duckID!Duck; 
    2762                     break; 
    2763                 } 
    2764             } 
    2765         } 
    2766     } 
    2767  
    2768  
    2769     /* 
    2770      * Assigns $(D rhs) to the existing active object. 
    2771      */ 
    2772     @trusted void _assign(T)(ref T rhs) 
    2773     in 
    2774     { 
    2775         assert(_which != size_t.max); 
    2776     } 
    2777     body 
    2778     { 
    2779         mixin (_onActiveDuck!( 
    2780             q{ 
    2781                 static if (__traits(compiles, _storageAs!Duck() = rhs)) 
    2782                     return _storageAs!Duck() = rhs; 
    2783             })); 
    2784  
    2785         // Or, alter the content with rhs. 
    2786         _dispose(); 
    2787         _grab(rhs); 
    2788     } 
    2789  
    2790  
    2791     /* 
    2792      * Returns a reference to the holded object as an instance of 
    2793      * type $(D T).  This does not validate the type. 
    2794      */ 
    2795     @system ref T _storageAs(T)() nothrow 
    2796         if (_homogenizes!(T)) 
    2797     { 
    2798         foreach (Duck; Ducks) 
    2799         { 
    2800             static if (_duckID!T == _duckID!Duck) 
    2801                 return *cast(Duck*) _storage.ptr; 
    2802         } 
    2803         assert(0); 
    2804     } 
    2805     /+ // @@@BUG3748@@@ 
    2806     @system ref inout(T) storageAs(T)() inout nothrow 
    2807     +/ 
    2808  
    2809     @system ref const(T) _storageAs_const(T)() const nothrow 
    2810         if (_homogenizes!(T)) 
    2811     { 
    2812         foreach (Duck; Ducks) 
    2813         { 
    2814             static if (_duckID!T == _duckID!Duck) 
    2815                 return *cast(const Duck*) _storage.ptr; 
    2816         } 
    2817         assert(0); 
    2818     } 
    2819  
    2820  
    2821  
    2822     /* 
    2823      * Runs the copy constructor on the active object. 
    2824      */ 
    2825     @trusted void _postblit() 
    2826     in 
    2827     { 
    2828         assert(_which != size_t.max); 
    2829     } 
    2830     body 
    2831     { 
    2832         mixin (_onActiveDuck!( 
    2833             q{ 
    2834                 static if (__traits(compiles, _storageAs!Duck().__postblit())) 
    2835                     _storageAs!Duck().__postblit(); 
    2836                 return; 
    2837             })); 
    2838         assert(0); 
    2839     } 
    2840  
    2841  
    2842     /* 
    2843      * Destroys the active object (if it's a struct) and markes this 
    2844      * $(D Any) object empty. 
    2845      */ 
    2846     @trusted void _dispose() 
    2847     in 
    2848     { 
    2849         assert(_which != size_t.max); 
    2850     } 
    2851     out 
    2852     { 
    2853         assert(_which == size_t.max); 
    2854     } 
    2855     body 
    2856     { 
    2857         mixin (_onActiveDuck!( 
    2858             q{ 
    2859                 static if (__traits(compiles, _storageAs!Duck.__dtor())) 
    2860                     _storageAs!Duck.__dtor(); 
    2861                 _which = size_t.max; 
    2862                 return; 
    2863             })); 
    2864         assert(0); 
    2865     } 
    2866  
    2867  
    2868     //----------------------------------------------------------------// 
    2869  
    2870     // @@@ workaround 
    2871     static if (_canDispatch!("front") && _canDispatch!("empty") && 
    2872             _canDispatch!("popFront")) 
    2873     public @system 
    2874     { 
    2875         @property bool empty() 
    2876         { 
    2877             return opDispatch!("empty")(); 
    2878         } 
    2879         @property auto ref front() 
    2880         { 
    2881             return opDispatch!("front")(); 
    2882         } 
    2883         void popFront() 
    2884         { 
    2885             opDispatch!("popFront")(); 
    2886         } 
    2887     } 
    2888  
    2889  
    2890     //----------------------------------------------------------------// 
    2891 private: 
    2892     size_t _which = size_t.max;     // ID of the 'active' Duck 
    2893     union 
    2894     { 
    2895         ubyte[_maxSize!(0, Ducks)]                  _storage; 
    2896         void*[_maxSize!(0, Ducks) / (void*).sizeof] _mark; 
    2897     } 
    2898 } 
    2899  
    2900 // These templates are prefixed by _ because templates are always public 
    2901 // even if they have the private attribute. 
    2902  
    2903 private template _maxSize(size_t max, TT...) 
    2904 { 
    2905     static if (TT.length > 0) 
    2906     { 
    2907         static if (max < TT[0].sizeof) 
    2908             enum _maxSize = _maxSize!(TT[0].sizeof, TT[1 .. $]); 
    2909         else 
    2910             enum _maxSize = _maxSize!(         max, TT[1 .. $]); 
    2911     } 
    2912     else 
    2913     { 
    2914         enum _maxSize = max; 
    2915     } 
    2916 } 
    2917  
    2918 private @trusted void _init(T)(ref T obj) 
    2919 { 
    2920     static if (is(T == struct)) 
    2921     { 
    2922         auto buf  = (cast(void*) &obj   )[0 .. T.sizeof]; 
    2923         auto init = (cast(void*) &T.init)[0 .. T.sizeof]; 
    2924         buf[] = init[]; 
    2925     } 
    2926     else 
    2927     { 
    2928         obj = T.init; 
    2929     } 
    2930 } 
    2931  
    2932 private template _commaExpand(string array, size_t N) 
    2933     if (N >= 1) 
    2934 { 
    2935     static if (N == 1) 
    2936         enum string _commaExpand = array ~ "[0]"; 
    2937     else 
    2938         enum string _commaExpand = _commaExpand!(array, N - 1) 
    2939             ~ ", " ~ array ~ "[" ~ N.stringof ~ " - 1]"; 
    2940 } 
    2941  
    2942  
    2943 version (unittest) private 
    2944 { 
    2945     bool eq(S)(S a, S b) 
    2946     { 
    2947         foreach (i, _; a.tupleof) 
    2948         { 
    2949             if (a.tupleof[i] != b.tupleof[i]) 
    2950                 return false; 
    2951         } 
    2952         return true; 
    2953     } 
    2954  
    2955     bool fails(lazy void expr) 
    2956     { 
    2957         try { expr; } catch (Error e) { return true; } 
    2958         return false; 
    2959     } 
    2960 } 
    2961  
    2962 unittest 
    2963 { 
    2964     // copy constructor & destructor 
    2965     struct Counter 
    2966     { 
    2967         int* copies; 
    2968         this(this) { copies && ++*copies; } 
    2969         ~this()    { copies && --*copies; } 
    2970     } 
    2971     Any!(Counter) a; 
    2972     a = Counter(new int); 
    2973     assert(*a.copies == 0); 
    2974     { 
    2975         auto b = a; 
    2976         assert(*a.copies == 1); 
    2977         { 
    2978             auto c = a; 
    2979             assert(*a.copies == 2); 
    2980         } 
    2981         assert(*a.copies == 1); 
    2982     } 
    2983     assert(*a.copies == 0); 
    2984 } 
    2985  
    2986 unittest 
    2987 { 
    2988     // basic use 
    2989     int afoo, bfoo; 
    2990     struct A { 
    2991         int inc() { return ++afoo; } 
    2992         int dec() { return --afoo; } 
    2993     } 
    2994     struct B { 
    2995         int inc() { return --bfoo; } 
    2996         int dec() { return ++bfoo; } 
    2997     } 
    2998     Any!(A, B) ab; 
    2999     ab = A(); 
    3000     assert(ab.inc() == 1 && afoo == 1); 
    3001     assert(ab.dec() == 0 && afoo == 0); 
    3002     ab = B(); 
    3003     assert(ab.inc() == -1 && bfoo == -1); 
    3004     assert(ab.dec() ==  0 && bfoo ==  0); 
    3005 } 
    3006  
    3007 unittest 
    3008 { 
    3009     // ref argument & ref return 
    3010     struct K { 
    3011         ref int foo(ref int a, ref int b) { ++b; return a; } 
    3012     } 
    3013     Any!(K) k; 
    3014     int v, w; 
    3015     k = K(); 
    3016     assert(&(k.foo(v, w)) == &v); 
    3017     assert(w == 1); 
    3018 } 
    3019  
    3020 unittest 
    3021 { 
    3022     // meta interface 
    3023     Any!(int, real) a; 
    3024  
    3025     assert(is(a.Any.Types == TypeTuple!(int, real))); 
    3026     assert(a.Any.allows!int); 
    3027     assert(a.Any.allows!real); 
    3028     assert(!a.Any.allows!string); 
    3029  
    3030     assert(a.Any.empty); 
    3031  
    3032     a = 42; 
    3033     assert(!a.Any.empty); 
    3034     assert( a.Any.isActive!int); 
    3035     assert(!a.Any.isActive!real); 
    3036     assert(!a.Any.isActive!string); 
    3037     int* i = &(a.Any.instance!int()); 
    3038     assert(*i == 42); 
    3039  
    3040     a = -21.0L; 
    3041     assert(!a.Any.empty); 
    3042     assert(!a.Any.isActive!int); 
    3043     assert( a.Any.isActive!real); 
    3044     assert(!a.Any.isActive!string); 
    3045     real* r = &(a.Any.instance!real()); 
    3046     assert(*r == -21.0L); 
    3047  
    3048     a = a.init; 
    3049     assert(a.Any.empty); 
    3050 } 
    3051  
    3052 unittest 
    3053 { 
    3054     // implicit convertion 
    3055     Any!(real, const(char)[]) a; 
    3056     a = 42; 
    3057     assert(a.Any.isActive!real); 
    3058     a = "abc"; 
    3059     assert(a.Any.isActive!(const(char)[])); 
    3060 } 
    3061  
    3062 unittest 
    3063 { 
    3064     // foreach over input range 
    3065     Any!(string, wstring) str; 
    3066  
    3067     str = cast(string) "a"; 
    3068     assert(str.length == 1); 
    3069     assert(str.front == 'a'); 
    3070     str.popFront; 
    3071     assert(str.empty); 
    3072  
    3073     str = cast(wstring) "bc"; 
    3074     assert(str.length == 2); 
    3075     str.popFront; 
    3076     assert(str.front == 'c'); 
    3077     assert(!str.empty); 
    3078  
    3079     size_t i; 
    3080     str = "\u3067\u3043\u30fc"; 
    3081     foreach (e; str) 
    3082         assert(e == "\u3067\u3043\u30fc"d[i++]); 
    3083 } 
    3084  
    3085 unittest 
    3086 { 
    3087     // null dereference 
    3088     Any!(short[], int[]) x; 
    3089  
    3090     assert(fails(x.length)); 
    3091  
    3092     x = new int[4]; 
    3093     assert(x.length == 4); 
    3094  
    3095     x = typeof(x).init; 
    3096     assert(fails(x.length)); 
    3097 } 
    3098  
    3099 // operator overloads 
    3100  
    3101 unittest 
    3102 { 
    3103     // opDispatch 
    3104     struct Tag { string op; int n; } 
    3105     struct OpEcho { 
    3106         Tag opDispatch(string op)(int n) { 
    3107             return Tag(op, n); 
    3108         } 
    3109     } 
    3110     Any!(OpEcho) obj; 
    3111  
    3112     obj = OpEcho(); 
    3113     auto r = obj.foo(42); 
    3114     assert(eq( r, Tag("foo", 42) )); 
    3115 } 
    3116  
    3117 unittest 
    3118 { 
    3119     // opAssign 
    3120     struct Tag { string op; int n; } 
    3121     struct OpEcho { 
    3122         int n; 
    3123         void opAssign(int n) { 
    3124             this.n = n; 
    3125         } 
    3126     } 
    3127     Any!(OpEcho) obj; 
    3128  
    3129     obj = OpEcho(); 
    3130     obj = 42; 
    3131     assert(obj.n == 42); 
    3132 } 
    3133  
    3134 unittest 
    3135 { 
    3136     // opUnary 
    3137     struct Tag { string op; } 
    3138     struct OpEcho { 
    3139         Tag opUnary(string op)() { 
    3140             return Tag(op); 
    3141         } 
    3142     } 
    3143     Any!(OpEcho) obj; 
    3144  
    3145     obj = OpEcho(); 
    3146     foreach (op; TypeTuple!("+", "-", "~", "*", "++", "--")) 
    3147     { 
    3148         auto r = mixin(op ~ "obj"); 
    3149         assert(eq( r, Tag(op) )); 
    3150     } 
    3151 } 
    3152  
    3153 unittest 
    3154 { 
    3155     // opIndexUnary 
    3156     struct Tag { string op; int x; real y; } 
    3157     struct OpEcho { 
    3158         Tag opIndexUnary(string op)(int x, real y) { 
    3159             return Tag(op, x, y); 
    3160         } 
    3161     } 
    3162     Any!(OpEcho) obj; 
    3163  
    3164     obj = OpEcho(); 
    3165     foreach (op; TypeTuple!("+", "-", "~", "*", "++", "--")) 
    3166     { 
    3167         auto r = mixin(op ~ "obj[4, 2.5]"); 
    3168         assert(eq( r, Tag(op, 4, 2.5) )); 
    3169     } 
    3170 } 
    3171  
    3172 unittest 
    3173 { 
    3174     // opSliceUnary 
    3175     struct Tag { string op; int x; real y; } 
    3176     struct OpEcho { 
    3177         Tag opSliceUnary(string op, int k = 2)(int x, real y) { 
    3178             return Tag(op, x, y); 
    3179         } 
    3180         Tag opSliceUnary(string op, int k = 0)() { 
    3181             return Tag(op, -1, -1); 
    3182         } 
    3183     } 
    3184     Any!(OpEcho) obj; 
    3185  
    3186     obj = OpEcho(); 
    3187     foreach (op; TypeTuple!("+", "-", "~", "*", "++", "--")) 
    3188     { 
    3189         auto r = mixin(op ~ "obj[4 .. 5.5]"); 
    3190         assert(eq( r, Tag(op, 4, 5.5) )); 
    3191  
    3192         auto s = mixin(op ~ "obj[]"); 
    3193         assert(eq( s, Tag(op, -1, -1) )); 
    3194     } 
    3195 } 
    3196  
    3197 unittest 
    3198 { 
    3199     // opCast 
    3200     struct OpEcho { 
    3201         T opCast(T)() { return T.init; } 
    3202     } 
    3203     Any!(OpEcho) obj; 
    3204  
    3205     obj = OpEcho(); 
    3206     foreach (T; TypeTuple!(int, string, OpEcho)) 
    3207     { 
    3208         auto r = cast(T) obj; 
    3209         assert(is(typeof(r) == T)); 
    3210     } 
    3211 } 
    3212  
    3213 unittest 
    3214 { 
    3215     // opBinary, opBinaryRight 
    3216     struct LTag { string op; int v; } 
    3217     struct RTag { string op; int v; } 
    3218     struct OpEcho { 
    3219         LTag opBinary(string op)(int v) { 
    3220             return LTag(op, v); 
    3221         } 
    3222         RTag opBinaryRight(string op)(int v) { 
    3223             return RTag(op, v); 
    3224         } 
    3225     } 
    3226     Any!(OpEcho) obj; 
    3227  
    3228     obj = OpEcho(); 
    3229     foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
    3230                 "|", "^", "<<", ">>", ">>>", "~"/+, "in" @@@BUG ??@@@+/)) 
    3231     { 
    3232         auto r = mixin("obj " ~ op ~ " 42"); 
    3233         assert(eq( r, LTag(op, 42) )); 
    3234         auto s = mixin("76 " ~ op ~ " obj"); 
    3235         assert(eq( s, RTag(op, 76) )); 
    3236     } 
    3237 } 
    3238  
    3239 unittest 
    3240 { 
    3241     // opEquals (forward) 
    3242     struct Dummy { 
    3243         bool opEquals(int v) const { 
    3244             return v > 0; 
    3245         } 
    3246         bool opEquals(ref const Dummy) const { assert(0); } 
    3247     } 
    3248     Any!(Dummy) obj; 
    3249  
    3250     obj = Dummy(); 
    3251     assert(obj ==  1); 
    3252     assert(obj !=  0); 
    3253     assert(obj != -1); 
    3254 } 
    3255  
    3256 unittest 
    3257 { 
    3258     // opEquals (meta) 
    3259     struct Dummy(int k) { 
    3260         bool opEquals(int kk)(ref const Dummy!kk rhs) const { 
    3261             return k == kk; 
    3262         } 
    3263     } 
    3264     Any!(Dummy!0, Dummy!1) a, b; 
    3265  
    3266     a = Dummy!0(); 
    3267     b = Dummy!1(); 
    3268     assert(a == a); 
    3269     assert(a != b); 
    3270     assert(b == b); 
    3271 } 
    3272  
    3273 unittest 
    3274 { 
    3275     // opCmp (forward) 
    3276     struct Dummy { 
    3277         int opCmp(int v) const { 
    3278             return 0 - v; 
    3279         } 
    3280         int opCmp(ref const Dummy) const { assert(0); } 
    3281     } 
    3282     Any!(Dummy) a; 
    3283  
    3284     a = Dummy(); 
    3285     assert(a >= 0); 
    3286     assert(a > -1); 
    3287     assert(a < 1); 
    3288 } 
    3289  
    3290 unittest 
    3291 { 
    3292     // opCmp (meta) 
    3293     struct Dummy(int k) { 
    3294         int opCmp(int kk)(ref const Dummy!kk r) const { 
    3295             return k - kk; 
    3296         } 
    3297     } 
    3298     Any!(Dummy!0, Dummy!1) a, b; 
    3299  
    3300     a = Dummy!0(); 
    3301     b = Dummy!1(); 
    3302     assert(a >= a); 
    3303     assert(a <= b); 
    3304     assert(a < b); 
    3305     assert(b >= a); 
    3306     assert(b <= b); 
    3307     assert(b > a); 
    3308 } 
    3309  
    3310 unittest 
    3311 { 
    3312     // opCall 
    3313     struct Tag { int x; real y; } 
    3314     struct OpEcho { 
    3315         Tag opCall(int x, real y) { 
    3316             return Tag(x, y); 
    3317         } 
    3318     } 
    3319     Any!(OpEcho) obj; 
    3320  
    3321 //  obj = OpEcho(); // @@@BUG@@@ 
    3322     obj = OpEcho.init; 
    3323     auto r = obj(4, 8.5); 
    3324     assert(r == Tag(4, 8.5)); 
    3325 } 
    3326  
    3327 unittest 
    3328 { 
    3329     // opOpAssign 
    3330     struct Tag { string op; int v; } 
    3331     struct OpEcho { 
    3332         Tag opOpAssign(string op)(int v) { 
    3333             return Tag(op, v); 
    3334         } 
    3335     } 
    3336     Any!(OpEcho) obj; 
    3337  
    3338     obj = OpEcho(); 
    3339     foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
    3340                 "|", "^", "<<", ">>", ">>>", "~")) 
    3341     { 
    3342         auto r = mixin("obj " ~ op ~ "= 97"); 
    3343         assert(eq( r, Tag(op, 97) )); 
    3344     } 
    3345 } 
    3346  
    3347 unittest 
    3348 { 
    3349     // opIndexOpAssign 
    3350     struct Tag { string op; int v; int x; real y; } 
    3351     struct OpEcho { 
    3352         Tag opIndexOpAssign(string op)(int v, int x, real y) { 
    3353             return Tag(op, v, x, y); 
    3354         } 
    3355     } 
    3356     Any!(OpEcho) obj; 
    3357  
    3358     obj = OpEcho(); 
    3359     foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
    3360                 "|", "^", "<<", ">>", ">>>", "~")) 
    3361     { 
    3362         auto r = mixin("obj[4, 7.5] " ~ op ~ "= 42"); 
    3363         assert(eq( r, Tag(op, 42, 4, 7.5) )); 
    3364     } 
    3365 } 
    3366  
    3367 unittest 
    3368 { 
    3369     // opSliceOpAssign 
    3370     struct Tag { string op; int v; int i; real j; } 
    3371     struct OpEcho { 
    3372         Tag opSliceOpAssign(string op, int k = 2)(int v, int i, real j) { 
    3373             return Tag(op, v, i, j); 
    3374         } 
    3375         Tag opSliceOpAssign(string op, int k = 0)(int v) { 
    3376             return Tag(op, v, -1, -1); 
    3377         } 
    3378     } 
    3379     Any!(OpEcho) obj; 
    3380  
    3381     obj = OpEcho(); 
    3382     foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
    3383                 "|", "^", "<<", ">>", ">>>", "~")) 
    3384     { 
    3385         auto r = mixin("obj[4 .. 7.5] " ~ op ~ "= 42"); 
    3386         assert(eq( r, Tag(op, 42, 4, 7.5) )); 
    3387  
    3388         auto s = mixin("obj[] " ~ op ~ "= 42"); 
    3389         assert(eq( s, Tag(op, 42, -1, -1) )); 
    3390     } 
    3391 } 
    3392  
    3393 unittest 
    3394 { 
    3395     // opIndex 
    3396     struct Tag { int i; real j; } 
    3397     struct OpEcho { 
    3398         Tag opIndex(int i, real j) { 
    3399             return Tag(i, j); 
    3400         } 
    3401     } 
    3402     Any!(OpEcho) obj; 
    3403  
    3404     obj = OpEcho(); 
    3405     auto r = obj[4, 9.5]; 
    3406     assert(eq( r, Tag(4, 9.5) )); 
    3407 } 
    3408  
    3409 unittest 
    3410 { 
    3411     // opSlice 
    3412     struct Tag { int i; real j; } 
    3413     struct OpEcho { 
    3414         Tag opSlice(int i, real j) { 
    3415             return Tag(i, j); 
    3416         } 
    3417         Tag opSlice() { 
    3418             return Tag(-1, -1); 
    3419         } 
    3420     } 
    3421     Any!(OpEcho) obj; 
    3422  
    3423     obj = OpEcho(); 
    3424     auto r = obj[4 .. 9.5]; 
    3425     assert(eq( r, Tag(4, 9.5) )); 
    3426  
    3427     auto s = obj[]; 
    3428     assert(eq( s, Tag(-1, -1) )); 
    3429 } 
    3430  
    3431 /+ 
    3432 unittest 
    3433 { 
    3434     // opApply 
    3435     struct OpEcho { 
    3436         int opApply(int delegate(ref size_t, ref real) dg) 
    3437         { 
    3438             foreach (i, ref e; [ 1.L, 2.5L, 5.5L ]) 
    3439                 if (auto r = dg(i, e)) 
    3440                     return r; 
    3441             return 0; 
    3442         } 
    3443     } 
    3444     Any!(OpEcho) obj; 
    3445  
    3446     obj = OpEcho(); 
    3447     foreach (size_t i, ref real e; obj) 
    3448         assert(e == [ 1.L, 2.5L, 5.5L ][i]); 
    3449 } 
    3450 +/ 
    3451  
  • branches/devel/stdio-native-codeset/phobos/std/variant.d

    r1725 r1753  
    5757 * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. 
    5858 * Authors:   $(WEB erdani.org, Andrei Alexandrescu) 
    5959 * 
    6060 *          Copyright Andrei Alexandrescu 2007 - 2009. 
    6161 * Distributed under the Boost Software License, Version 1.0. 
    6262 *    (See accompanying file LICENSE_1_0.txt or copy at 
    6363 *          http://www.boost.org/LICENSE_1_0.txt) 
    6464 */ 
    6565module std.variant; 
    6666 
    67 import std.traits, std.c.string, std.typetuple, std.conv; 
     67import std.algorithm, std.array, std.conv, std.traits, std.typetuple; 
     68import core.stdc.string; 
     69 
    6870version(unittest) 
    6971{ 
    70     import std.exception, std.stdio; 
     72    import std.exception, std.range, std.stdio; 
    7173} 
    7274 
    7375private template maxSize(T...) 
    7476{ 
    7577    static if (T.length == 1) 
    7678    { 
    7779        enum size_t maxSize = T[0].sizeof; 
    7880    } 
    7981    else 
    8082    { 
     
    982984        auto arr = get!(A[]); 
    983985        foreach (ref e; arr) 
    984986        { 
    985987            if (dg(e)) return 1; 
    986988        } 
    987989        return 0; 
    988990    } 
    989991} 
    990992 
    991993/** 
    992  * Algebraic data type restricted to a closed set of possible 
    993  * types. It's an alias for a $(D_PARAM VariantN) with an 
    994  * appropriately-constructed maximum size. $(D_PARAM Algebraic) is 
    995  * useful when it is desirable to restrict what a discriminated type 
    996  * could hold to the end of defining simpler and more efficient 
    997  * manipulation. 
    998  * 
    999  * Future additions to $(D_PARAM Algebraic) will allow compile-time 
    1000  * checking that all possible types are handled by user code, 
    1001  * eliminating a large class of errors. 
    1002  * 
    1003  * Bugs: 
    1004  * 
    1005  * Currently, $(D_PARAM Algebraic) does not allow recursive data 
    1006  * types. They will be allowed in a future iteration of the 
    1007  * implementation. 
    1008  * 
    1009  * Example: 
    1010  * ---- 
    1011  * auto v = Algebraic!(int, double, string)(5); 
    1012  * assert(v.peek!(int)); 
    1013  * v = 3.14; 
    1014  * assert(v.peek!(double)); 
    1015  * // auto x = v.peek!(long); // won't compile, type long not allowed 
    1016  * // v = '1'; // won't compile, type char not allowed 
    1017  * ---- 
    1018  */ 
    1019  
    1020 template Algebraic(T...) 
    1021 { 
    1022     alias VariantN!(maxSize!(T), T) Algebraic; 
    1023 } 
    1024  
    1025 /** 
    1026994$(D_PARAM Variant) is an alias for $(D_PARAM VariantN) instantiated 
    1027995with the largest of $(D_PARAM creal), $(D_PARAM char[]), and $(D_PARAM 
    1028996void delegate()). This ensures that $(D_PARAM Variant) is large enough 
    1029997to hold all of D's predefined types, including all numeric types, 
    1030998pointers, delegates, and class references.  You may want to use 
    1031999$(D_PARAM VariantN) directly with a different maximum size either for 
    10321000storing larger types, or for saving memory. 
    10331001 */ 
    10341002 
    10351003alias VariantN!(maxSize!(creal, char[], void delegate())) Variant; 
     
    11071075        this.source = source; 
    11081076        this.target = target; 
    11091077    } 
    11101078} 
    11111079 
    11121080unittest 
    11131081{ 
    11141082    alias This2Variant!(char, int, This[int]) W1; 
    11151083    alias TypeTuple!(int, char[int]) W2; 
    11161084    static assert(is(W1 == W2)); 
    1117  
    1118     alias Algebraic!(void, string) var_t; 
    1119     var_t foo = "quux"; 
    11201085} 
    11211086 
    11221087unittest 
    11231088{ 
    11241089    // @@@BUG@@@ 
    11251090    // alias Algebraic!(real, This[], This[int], This[This]) A; 
    11261091    // A v1, v2, v3; 
    11271092    // v2 = 5.0L; 
    11281093    // v3 = 42.0L; 
    11291094    // //v1 = [ v2 ][]; 
     
    13891354unittest 
    13901355{ 
    13911356    auto v = Variant([ 1, 2, 3, 4 ][]); 
    13921357    auto j = 0; 
    13931358    foreach (int i; v) 
    13941359    { 
    13951360        assert(i == ++j); 
    13961361    } 
    13971362    assert(j == 4); 
    13981363} 
     1364 
     1365 
     1366//----------------------------------------------------------------------------// 
     1367// Algebraic 
     1368 
     1369/+ 
     1370 + TODO: 
     1371 + 
     1372 +  - Make Algebraic.opBinary() etc. accept Algebraic rhs. 
     1373 + 
     1374 +  - Make Algebraic.empty sensible of infinite ranges. 
     1375 + 
     1376 +  - opApply 
     1377 + 
     1378 +  ? Prefer Algebraic!(T1,T2,...) to Algebraic!(R1,R2,...) for the return 
     1379 +    type of oveloaded operators of Algebraic!(T1,T2,...) if { R1,R2,...} is 
     1380 +    a subset of { T1,T2,... };  this might reduce program size and 
     1381 +    compilation time. 
     1382 +/ 
     1383 
     1384 
     1385// Hook for canonicalizing template instantiation arguments. 
     1386template Algebraic(Types...) 
     1387        if (!isAlgebraicCanonicalized!Types) 
     1388{ 
     1389    alias Algebraic!(AlgebraicCanonicalize!Types) Algebraic; 
     1390} 
     1391 
     1392private template AlgebraicCanonicalize(Types...) 
     1393{ 
     1394    alias NoDuplicates!Types AlgebraicCanonicalize; 
     1395 
     1396    // validate 
     1397    static assert(AlgebraicCanonicalize.length > 0, 
     1398            "Attempted to instantiate Algebraic with empty argument"); 
     1399    static assert(staticIndexOf!(void, AlgebraicCanonicalize) < 0, 
     1400            "void is not allowed for Algebraic"); 
     1401    static assert(isTypeTuple!AlgebraicCanonicalize, 
     1402            "Attempted to isntantiate Algebraic with non-type argument(s)"); 
     1403} 
     1404 
     1405private template isAlgebraicCanonicalized(Types...) 
     1406{ 
     1407    enum bool isAlgebraicCanonicalized = 
     1408        is(Types == AlgebraicCanonicalize!Types); 
     1409} 
     1410 
     1411private template isAlgebraic(A) 
     1412{ 
     1413    enum bool isAlgebraic = 
     1414        (UnpackAlgebraicInstantiationArguments!A.length > 0); 
     1415} 
     1416 
     1417private template UnpackAlgebraicInstantiationArguments(A) 
     1418{ 
     1419    alias UnpackAlgebraicInstantiationArgumentsImpl!A.Result 
     1420                UnpackAlgebraicInstantiationArguments; 
     1421} 
     1422 
     1423private template UnpackAlgebraicInstantiationArgumentsImpl(A) 
     1424{ 
     1425    struct Unpack(UU...) 
     1426    { 
     1427        alias UU Expand; 
     1428    } 
     1429    extern Unpack!UU unpack(UU...)(Algebraic!UU x); 
     1430 
     1431    static if (is(typeof(unpack(A.init)).Expand Types)) 
     1432        alias Types        Result; 
     1433    else 
     1434        alias TypeTuple!() Result; 
     1435} 
     1436 
     1437 
     1438/** 
     1439Algebraic data type restricted to a closed set of possible types. 
     1440$(D Algebraic) is useful when it is desirable to restrict what a 
     1441discriminated type could hold to the end of defining simpler and 
     1442more efficient manipulation. 
     1443 
     1444$(D Algebraic) allows compile-time checking that all possible 
     1445types are handled by user code, eliminating a large class of 
     1446errors. 
     1447-------------------- 
     1448Algebraic!(int, double) x; 
     1449 
     1450// these lines won't compile since long and string are not allowed 
     1451auto n = x.Algebraic.instance!long; 
     1452x = "abc"; 
     1453-------------------- 
     1454 
     1455Bugs: 
     1456 
     1457$(UL 
     1458 $(LI Currently, $(D Algebraic) does not allow recursive data types. 
     1459     They will be allowed in a future iteration of the implementation.) 
     1460 $(LI $(D opCall) overloads are hidden due to $(BUGZILLA 4243). 
     1461 $(LI $(D opApply) overloads are hidden because it conflicts with 
     1462     the $(D range) primitives.) 
     1463) 
     1464 
     1465Examples: 
     1466-------------------- 
     1467Algebraic!(int, double, string) v = 5; 
     1468assert(v.Algebraic.isActive!int); 
     1469 
     1470v = 3.14; 
     1471assert(v.Algebraic.isActive!double); 
     1472 
     1473v *= 2; 
     1474assert(v > 6); 
     1475-------------------- 
     1476 
     1477You can call any method $(D Types) have against $(D Algebraic). 
     1478-------------------- 
     1479Algebraic!(string, wstring, dstring) s; 
     1480 
     1481s = "The quick brown fox jumps over the lazy dog."; 
     1482assert(s.front == 'T'); 
     1483assert(s.back == '.'); 
     1484assert(s.length == 44); 
     1485s.popBack; 
     1486assert(equal(take(retro(s), 3), "god")); 
     1487-------------------- 
     1488 
     1489Dispatch a holded object to handlers with $(D Algebraic.dispatch): 
     1490-------------------- 
     1491Algebraic!(int, string) x = 42; 
     1492 
     1493x.Algebraic.dispatch( 
     1494        (ref int n) 
     1495        { 
     1496            writeln("saw an int: ", n); 
     1497            ++n; 
     1498        }, 
     1499        (string s) 
     1500        { 
     1501            writeln("saw a string: ", s); 
     1502        } 
     1503    ); 
     1504assert(x == 43);    // incremented 
     1505-------------------- 
     1506 */ 
     1507 
     1508struct Algebraic(Types...) 
     1509        if (isAlgebraicCanonicalized!(Types)) 
     1510{ 
     1511//  private alias This2Variant!(typeof(this), Types) _Types;    // @@@BUG4449@@@ 
     1512    private alias Types _Types; 
     1513 
     1514    /** 
     1515     * Constructs an $(D Algebraic) object holding an object $(D init). 
     1516     * 
     1517     * See_Also: 
     1518     *  $(D opAssign) 
     1519     */ 
     1520    this(T)(T init) 
     1521    { 
     1522        static assert(_canAssign!(T), "Attempted to construct an " 
     1523                ~ typeof(this).stringof ~ " with a disallowed initial " 
     1524                "object of type " ~ T.stringof); 
     1525        _grab(init); 
     1526    } 
     1527 
     1528 
     1529    /** 
     1530     * Assigns $(D rhs) to the $(D Algebraic) object. 
     1531     * 
     1532     * If $(D T) is one of the $(D Types...), the active object (if any) 
     1533     * is destroyed and $(D rhs) takes place of it;  otherwise assignment 
     1534     * of $(D rhs) occurs on the active object. 
     1535     * 
     1536     * Throws: 
     1537     *  $(UL 
     1538     *   $(LI $(D VariantException) if $(D rhs) is an empty $(D Algebraic) 
     1539     *      object.) 
     1540     *   $(LI $(D VariantException) if $(D rhs) is an $(D Algebraic) object 
     1541     *      holding an object that is not assignable to the left hand side.) 
     1542     *  ) 
     1543     */ 
     1544    @system void opAssign(T)(T rhs) 
     1545            if (_canAssign!(T) && !_isCompatibleAlgebraic!(T)) 
     1546    { 
     1547        static if (_typeCode!T != size_t.max) 
     1548        { 
     1549            if (_which != size_t.max) 
     1550                _dispose(); 
     1551            _grab(rhs); 
     1552        } 
     1553        else 
     1554        { 
     1555            if (_which == size_t.max) 
     1556                _grab(rhs); 
     1557            else 
     1558                _assign(rhs); 
     1559        } 
     1560    } 
     1561 
     1562    // simple blit 
     1563    @trusted void opAssign(T)(T rhs) 
     1564            if (is(T == typeof(this))) 
     1565    { 
     1566        swap(this, rhs); 
     1567    } 
     1568 
     1569    // intersection 
     1570    @system void opAssign(T)(T rhs) 
     1571            if (_isCompatibleAlgebraic!(T) && !is(T == typeof(this))) 
     1572    { 
     1573        if (rhs._which == size_t.max) 
     1574            throw new VariantException("Attempted to assign an empty " 
     1575                    ~ T.stringof ~ " to " ~ typeof(this).stringof); 
     1576 
     1577        final switch (rhs._which) 
     1578        { 
     1579            foreach (U; rhs._Types) 
     1580            { 
     1581            case rhs._typeCode!U: 
     1582                static if (_canAssign!U) 
     1583                    return opAssign(rhs._storageAs!U); 
     1584                else 
     1585                    throw new VariantException("Attempted to assign an " 
     1586                        ~ T.stringof ~ " holding " ~ U.stringof ~ " which " 
     1587                        "is incompatible with " ~ typeof(this).stringof); 
     1588            } 
     1589        } 
     1590        assert(0); 
     1591    } 
     1592 
     1593    private template _canAssign(T, size_t i = 0) 
     1594    { 
     1595        static if (i < _Types.length && is(_Types[i] Type)) 
     1596            enum bool _canAssign = 
     1597                   is(T : Type) 
     1598                || is(typeof(phony!Type = phony!T)) 
     1599                || _isCompatibleAlgebraic!(T) 
     1600                || _canAssign!(T, i + 1); 
     1601        else 
     1602            enum bool _canAssign = false; 
     1603    } 
     1604 
     1605    // Returns true if this and A have nonempty intersection 
     1606    private template _isCompatibleAlgebraic(A) 
     1607    { 
     1608        static if (isAlgebraic!(A) && is(A._Types UU)) 
     1609            enum bool _isCompatibleAlgebraic = 
     1610                _Types.length + UU.length > NoDuplicates!(_Types, UU).length; 
     1611        else 
     1612            enum bool _isCompatibleAlgebraic = false; 
     1613    } 
     1614 
     1615    // @@@BUG4424@@@ workaround 
     1616    private template _workaround4424() 
     1617        { @disable void opAssign(...) { assert(0); } } 
     1618    mixin _workaround4424 _workaround4424_; 
     1619 
     1620 
     1621    /** 
     1622     * Invokes the copy constructor on the active object if any. 
     1623     */ 
     1624    this(this) 
     1625    { 
     1626        if (_which != size_t.max) 
     1627        { 
     1628            mixin (_onActiveObject!( 
     1629                q{ 
     1630                    static if (__traits(compiles, 
     1631                            _storageAs!Active().__postblit() )) 
     1632                        _storageAs!Active().__postblit(); 
     1633                })); 
     1634        } 
     1635    } 
     1636 
     1637 
     1638    /** 
     1639     * Invokes the destructor on the active object if any. 
     1640     */ 
     1641    ~this() 
     1642    { 
     1643        if (_which != size_t.max) 
     1644            _dispose(); 
     1645    } 
     1646 
     1647 
     1648    //------------------------------------------------------------------------// 
     1649 
     1650    /** 
     1651     * $(D Algebraic) namespace for operating on the $(D Algebraic) object 
     1652     * itself, not a holded object. 
     1653     * 
     1654     * Example: 
     1655-------------------- 
     1656Algebraic!(A, B) ab; 
     1657assert(ab.Algebraic.empty); 
     1658 
     1659ab = A(); 
     1660assert(ab.Algebraic.isActive!A); 
     1661-------------------- 
     1662     */ 
     1663    private template _Algebraic() 
     1664    { 
     1665        /** 
     1666         * The type tuple used to instantiate the $(D Algebraic) with no 
     1667         * duplicates. 
     1668         * 
     1669         * Example: 
     1670-------------------- 
     1671Algebraic!(int, int, real, int) x; 
     1672assert(is( x.Algebraic.Types == TypeTuple!(int, real) )); 
     1673-------------------- 
     1674         */ 
     1675        alias _Types Types; 
     1676 
     1677 
     1678        /** 
     1679         * Returns $(D true) if type $(D T) is contained in $(D Types...). 
     1680         */ 
     1681        template allowed(T) 
     1682        { 
     1683            enum bool allowed = (_typeCode!T != size_t.max); 
     1684        } 
     1685 
     1686 
     1687        /** 
     1688         * Returns $(D true) if an object of type $(D T) can be assigned to 
     1689         * the $(D Algebraic) object. 
     1690         */ 
     1691        template canAssign(T) 
     1692        { 
     1693            enum bool canAssign = _canAssign!T; 
     1694        } 
     1695 
     1696 
     1697        /** 
     1698         * Returns $(D true) if the $(D Algebraic) object holds nothing. 
     1699         */ 
     1700        @safe @property nothrow bool empty() const 
     1701        { 
     1702            return _which == size_t.max; 
     1703        } 
     1704 
     1705 
     1706        /** 
     1707         * Returns $(D true) if the type of the active object is $(D T). 
     1708         */ 
     1709        @safe nothrow bool isActive(T)() const 
     1710        { 
     1711            return _which != size_t.max && _which == _typeCode!T; 
     1712        } 
     1713 
     1714 
     1715        /** 
     1716         * Returns $(D true) if and only if the $(D Algebraic) object holds 
     1717         * an object implicitly convertible to type $(D T). 
     1718         */ 
     1719        @safe nothrow bool convertsTo(T)() const 
     1720        { 
     1721            if (_which == size_t.max) 
     1722                return false; 
     1723            mixin (_onActiveObject!( 
     1724                q{ 
     1725                    return isImplicitlyConvertible!(Active, T); 
     1726                })); 
     1727            assert(0); 
     1728        } 
     1729 
     1730 
     1731        /** 
     1732         * Returns the active object as a reference of type $(D T).  $(D T) 
     1733         * must be the type of the active object, i.e., 
     1734         * $(D isActive!T == true). 
     1735         * 
     1736         * Throws: 
     1737         * $(UL 
     1738         *   $(LI $(D VariantException) if the $(D Algebraic) object is 
     1739         *        empty or $(D T) is not active.) 
     1740         * ) 
     1741         * 
     1742         * Example: 
     1743-------------------- 
     1744// take a pointer to the active object 
     1745Algebraic!(A, B) ab = A(); 
     1746 
     1747assert(ab.Algebraic.isActive!A); 
     1748A* p = &(ab.Algebraic.instance!A()); 
     1749B* q = &(ab.Algebraic.instance!B());    // throws VariantException 
     1750-------------------- 
     1751         */ 
     1752        @safe @property ref T instance(T)() 
     1753                if (allowed!(T)) 
     1754        { 
     1755            if (!isActive!T) 
     1756                throw new VariantException("Attempting to peek a reference " 
     1757                        ~ "to " ~ T.stringof ~ " in " ~ typeof(this).stringof); 
     1758            return _storageAs!T; 
     1759        } 
     1760        /+ // @@@BUG3748@@@ 
     1761        @trusted @property nothrow ref inout(T) instance(T)() inout 
     1762        +/ 
     1763 
     1764 
     1765        /** 
     1766         * Returns the active object as a value of type $(D T) allowing 
     1767         * implicit convertion. 
     1768         * 
     1769         * Throws: 
     1770         *  $(UL 
     1771         *   $(LI Compile fails if none of $(D Types...) supports implicit 
     1772         *      convertion to $(D T).) 
     1773         *   $(LI $(D VariantException) if the $(D Algebraic) object is 
     1774         *      empty or the active object is not implicitly convertible 
     1775         *      to $(D T).) 
     1776         *  ) 
     1777         */ 
     1778        @safe T get(T)() 
     1779                if (canGet!(T)) 
     1780        { 
     1781            if (_which == size_t.max) 
     1782                throw new VariantException("Attempted to get a value of " 
     1783                        "type " ~ T.stringof ~ " out of an empty " 
     1784                        ~ typeof(this).stringof); 
     1785 
     1786            mixin (_onActiveObject!( 
     1787                q{ 
     1788                    static if (isImplicitlyConvertible!(Active, T)) 
     1789                        return _storageAs!Active; 
     1790                    else 
     1791                        throw new VariantException(Active.stringof 
     1792                            ~ "is not implicitly convertible to " 
     1793                            ~ T.stringof); 
     1794                })); 
     1795            assert(0); 
     1796        } 
     1797        /+ // @@@BUG3748@@@ 
     1798        @trusted inout(T) get(T)() inout 
     1799        +/ 
     1800 
     1801        private template canGet(T, size_t i = 0) 
     1802        { 
     1803            // Convertion must be supported by at least one type. 
     1804            static if (i < _Types.length && is(_Types[i] Active)) 
     1805                enum bool canGet = isImplicitlyConvertible!(Active, T) 
     1806                        || canGet!(T, i + 1); 
     1807            else 
     1808                enum bool canGet = false; 
     1809        } 
     1810 
     1811 
     1812        /** 
     1813         * Returns the active object explicitly converted to $(D T) using 
     1814         * $(D std.conv.to!T). 
     1815         * 
     1816         * Throws: 
     1817         *  $(UL 
     1818         *   $(LI Compile fails if none of $(D Types...) supports explicit 
     1819         *      convertion to $(D T).) 
     1820         *   $(LI $(D VariantException) if the $(D Algebraic) object is 
     1821         *      empty.) 
     1822         *   $(LI $(D ConvError) on any convertion error.) 
     1823         *  ) 
     1824         */ 
     1825        @system T coerce(T)() 
     1826                if (canCoerce!(T)) 
     1827        { 
     1828            if (_which == size_t.max) 
     1829                throw new VariantException("Attempted to coerce an empty " 
     1830                        ~ typeof(this).stringof ~ " into " ~ T.stringof); 
     1831 
     1832            mixin (_onActiveObject!( 
     1833                q{ 
     1834                    static if (__traits(compiles, to!T(phony!Active))) 
     1835                        return to!T(_storageAs!Active); 
     1836                    else 
     1837                        throw new ConvError("Can't convert a value of type " 
     1838                            ~ Active.stringof ~ " to type " ~ T.stringof); 
     1839                })); 
     1840            assert(0); 
     1841        } 
     1842 
     1843        private template canCoerce(T, size_t i = 0) 
     1844        { 
     1845            // Convertion must be supported by at least one type. 
     1846            static if (i < _Types.length && is(_Types[i] Active)) 
     1847                enum bool canCoerce = __traits(compiles, to!T(phony!Active)) 
     1848                        || canCoerce!(T, i + 1); 
     1849            else 
     1850                enum bool canCoerce = false; 
     1851        } 
     1852 
     1853 
     1854        /** 
     1855         * Passes a reference to the active object by reference to 
     1856         * appropriate $(D handlers) in turn. 
     1857         * 
     1858         * Returns: 
     1859         *  $(D true) if at least one handler is called. 
     1860         * 
     1861         * Example: 
     1862-------------------- 
     1863Algebraic!(A, B, C) x = A.init; 
     1864 
     1865// will print "saw an A" and "it's an A" 
     1866auto matched = x.Algebraic.dispatch( 
     1867        (A obj) { writeln("saw an A"); }, 
     1868        (B obj) { writeln("saw a B"); }, 
     1869        (ref A obj) { writeln("it's an A"); } 
     1870    ); 
     1871assert(matched == true); 
     1872-------------------- 
     1873         */ 
     1874        bool dispatch(Handlers...)(Handlers handlers) 
     1875        { 
     1876            if (_which == size_t.max) 
     1877                return false; 
     1878 
     1879            uint match = 0; 
     1880            mixin (_onActiveObject!( 
     1881                q{ 
     1882                    foreach (handler; handlers) 
     1883                    { 
     1884                        static if (__traits(compiles, handler(_storageAs!Active))) 
     1885                        { 
     1886                            handler(_storageAs!Active); 
     1887                            ++match; 
     1888                        } 
     1889                    } 
     1890                })); 
     1891            return match != 0; 
     1892        } 
     1893    } 
     1894 
     1895    /// Ditto 
     1896    alias _Algebraic!() Algebraic; 
     1897 
     1898 
     1899    //--------------------------------------------------------------------// 
     1900    // standard operator overloads 
     1901 
     1902    /* 
     1903     * Generates code for returning $(D expr) evaluated on the active 
     1904     * object of type $(D Active).  $(D typeof(return)) must be inferable. 
     1905     */ 
     1906    private template _returnUsingActiveObject(string expr) 
     1907    { 
     1908        enum string _returnUsingActiveObject = _onActiveObject!( 
     1909             "static if (is(typeof(0, (" ~ expr ~ ")) Ri))" 
     1910            ~"{" 
     1911                ~"static if (is(Ri == void))" 
     1912                ~"{" 
     1913                    ~"return (" ~ expr ~ "), byValue!(typeof(return));" 
     1914                ~"}" 
     1915                ~"else" 
     1916                ~"{" 
     1917                    ~"return byValue!(typeof(return))(" ~ expr ~ ");" 
     1918                ~"}" 
     1919            ~"}"); 
     1920    } 
     1921 
     1922    /* 
     1923     * Returns Algebraic!( RTs[0], RTs[1], ... ), or $(D void) if $(D RTs) 
     1924     * is empty or consisting only of $(D void)s. 
     1925     */ 
     1926    private template _ReduceOpGenericRT(RTs...) 
     1927    { 
     1928        static if (is(Erase!(void, staticMap!(Unqual, RTs)) NVRTs) && 
     1929                    NVRTs.length > 0) 
     1930            alias .Algebraic!NVRTs _ReduceOpGenericRT; 
     1931        else 
     1932            alias void             _ReduceOpGenericRT; 
     1933    } 
     1934 
     1935    /* 
     1936     * Maps Types --> { typeof(expr) | Active in Types }, where expr is 
     1937     * an expression in which Active and Args are used. 
     1938     */ 
     1939    private template _MapOpGenericRTs(size_t i, string expr, Args...) 
     1940    { 
     1941        static if (i < _Types.length && is(_Types[i] Active)) 
     1942        { 
     1943            static if (is(typeof(0, mixin(expr)) R)) 
     1944                alias TypeTuple!(R, _MapOpGenericRTs!(i + 1, expr, Args)) 
     1945                            _MapOpGenericRTs; 
     1946            else 
     1947                alias _MapOpGenericRTs!(i + 1, expr, Args) 
     1948                            _MapOpGenericRTs; 
     1949        } 
     1950        else 
     1951        { 
     1952            alias TypeTuple!() _MapOpGenericRTs; 
     1953        } 
     1954    } 
     1955 
     1956 
     1957    /** 
     1958     * Evaluates a method or a property $(D op) on the active object. 
     1959     * 
     1960     * The operation $(D op) must be defined by at least one type in the 
     1961     * allowed $(D Types...). 
     1962     * 
     1963     * Params: 
     1964     *  args = The arguments to be passed to the method. 
     1965     * 
     1966     * Returns: 
     1967     *  The value returned by the active object's method $(D op). 
     1968     * 
     1969     *  The type of the result is the $(D CommonType) of all $(D op)s on 
     1970     *  possible $(D Types...).  It's returned by reference if all the 
     1971     *  return types are identical and returned by reference. 
     1972-------------------- 
     1973Algebraic!(int, real) n = 0; 
     1974assert(is(typeof(n.max) == real)); 
     1975 
     1976Algebraic!(int[], Retro!(int[])) r = [ 1, 2, 3 ]; 
     1977auto p = &(r.front()); 
     1978assert(*p == 1); 
     1979-------------------- 
     1980     * 
     1981     * Throws: 
     1982     *  $(UL 
     1983     *   $(LI $(D VariantException) if the $(D Algebraic) object is 
     1984     *        empty.) 
     1985     *   $(LI $(D VariantException) if the method $(D op) is not 
     1986     *        defined by the active object.) 
     1987     *  ) 
     1988     * 
     1989     * BUGS: 
     1990     *  $(UL 
     1991     *   $(LI Forward reference errors may occur due to $(BUGZILLA 3294). 
     1992     *       For example, $(D hasLength) reports $(D false) even if the 
     1993     *       $(D length) property is really available.) 
     1994     *  ) 
     1995     */ 
     1996    auto ref opDispatch(string op, Args...)(auto ref Args args) 
     1997            if (_canDispatch!(op, Args)) 
     1998    { 
     1999        alias CommonType!(_MapOpDispatchRTs!(op, Args)) RT; 
     2000        enum byRef    = _canDispatchByRef!(op, Args); 
     2001 
     2002        enum attempt  = (Args.length ? op ~ Args.stringof : op); 
     2003        enum dispatch = "_storageAs!Active()." 
     2004                ~ (args.length ? op ~ "(args)" : op); 
     2005 
     2006        if (_which == size_t.max) 
     2007            throw new VariantException(_emptyMsg(attempt)); 
     2008        // 
     2009        mixin (_onActiveObject!( 
     2010            q{ 
     2011                static if (is(typeof(0, mixin(dispatch)) Ri)) 
     2012                { 
     2013                    static if (byRef) 
     2014                    { 
     2015                        // Return the result by reference. 
     2016                        return mixin(dispatch); 
     2017                    } 
     2018                    else static if (!is(RT == void) && !is(Ri == void)) 
     2019                    { 
     2020                        // Return the result by value of type RT. 
     2021                        return byValue!RT(mixin(dispatch)); 
     2022                    } 
     2023                    else 
     2024                    { 
     2025                        // Just dispatch the method and return nothing. 
     2026                        return mixin(dispatch), byValue!RT; 
     2027                    } 
     2028                } 
     2029            })); 
     2030        throw new VariantException(_undefinedOpMsg(attempt)); 
     2031    } 
     2032 
     2033    private template _MapOpDispatchRTs(string op, Args...) 
     2034    { 
     2035        alias _MapOpGenericRTs!(0, 
     2036                "phony!Active." 
     2037                    ~ (Args.length ? op ~ "(phonyList!Args)" : op), 
     2038                Args 
     2039            ) _MapOpDispatchRTs; 
     2040    } 
     2041 
     2042    private template _canDispatch(string op, Args...) 
     2043    { 
     2044        enum bool _canDispatch = 
     2045            _MapOpDispatchRTs!(op, Args).length > 0; 
     2046    } 
     2047 
     2048    private template _canDispatchByRef(string op, Args...) 
     2049    { 
     2050        enum bool _canDispatchByRef = 
     2051            NoDuplicates!(_MapOpDispatchRTs!(op, Args)).length == 1 
     2052            && 
     2053            __traits(compiles, function(Args args) 
     2054                { 
     2055                    enum dispatch = "obj." 
     2056                        ~ (args.length ? op ~ "(args)" : op); 
     2057                    foreach (Type; _Types) 
     2058                    { 
     2059                        Type obj; 
     2060                        expectLvalue(mixin(dispatch)); 
     2061                    } 
     2062                }); 
     2063    } 
     2064 
     2065 
     2066    //--------------------------------------------------------------------// 
     2067 
     2068    /* 
     2069     * <op>storageAs!Active 
     2070     */ 
     2071    _ReduceOpGenericRT!(_MapOpUnaryRTs!(op)) 
     2072        opUnary(string op)() 
     2073    { 
     2074        enum string attempt = "unary " ~ op; 
     2075 
     2076        static assert(_MapOpUnaryRTs!(op).length, _invalidOpMsg(attempt)); 
     2077        if (_which == size_t.max) 
     2078            throw new VariantException(_emptyMsg(attempt)); 
     2079 
     2080        mixin (_returnUsingActiveObject!( 
     2081                op~"_storageAs!Active" 
     2082            )); 
     2083        throw new VariantException(_undefinedOpMsg(attempt)); 
     2084    } 
     2085 
     2086    private template _MapOpUnaryRTs(string op) 
     2087    { 
     2088        alias _MapOpGenericRTs!(0, op~"phony!Active") _MapOpUnaryRTs; 
     2089    } 
     2090 
     2091 
     2092    /* 
     2093     * storageAs!Active <op> rhs 
     2094     */ 
     2095    _ReduceOpGenericRT!(_MapOpBinaryRTs!(op, RHS)) 
     2096        opBinary(string op, RHS)(RHS rhs) 
     2097    { 
     2098        enum string attempt = "binary " ~ op ~ " " ~ RHS.stringof; 
     2099 
     2100        static assert(_MapOpBinaryRTs!(op, RHS).length, 
     2101                _invalidOpMsg(attempt)); 
     2102        if (_which == size_t.max) 
     2103            throw new VariantException(_emptyMsg(attempt)); 
     2104 
     2105        mixin (_returnUsingActiveObject!( 
     2106                "_storageAs!Active() "~op~" rhs" 
     2107            )); 
     2108        throw new VariantException(_undefinedOpMsg(attempt)); 
     2109    } 
     2110 
     2111    private template _MapOpBinaryRTs(string op, RHS) 
     2112    { 
     2113        alias _MapOpGenericRTs!(0, 
     2114                "phony!Active "~op~" phony!(Args[0])", 
     2115                RHS 
     2116            ) _MapOpBinaryRTs; 
     2117    } 
     2118 
     2119 
     2120    /* 
     2121     * lhs <op> storageAs!Active 
     2122     */ 
     2123    _ReduceOpGenericRT!(_MapOpBinaryRightRTs!(op, LHS)) 
     2124        opBinaryRight(string op, LHS)(LHS lhs) 
     2125            if (!_isCompatibleAlgebraic!(LHS)) 
     2126    { 
     2127        enum string attempt = "binary " ~ LHS.stringof ~ " " ~ op; 
     2128 
     2129        static assert(_MapOpBinaryRightRTs!(op, LHS).length, 
     2130                _invalidOpMsg(attempt)); 
     2131        if (_which == size_t.max) 
     2132            throw new VariantException(_emptyMsg(attempt)); 
     2133 
     2134        mixin (_returnUsingActiveObject!( 
     2135                "lhs "~op~" _storageAs!Active" 
     2136            )); 
     2137        throw new VariantException(_undefinedOpMsg(attempt)); 
     2138    } 
     2139 
     2140    private template _MapOpBinaryRightRTs(string op, LHS) 
     2141    { 
     2142        alias _MapOpGenericRTs!(0, 
     2143                "phony!(Args[0]) " ~ op ~ " phony!Active", 
     2144                LHS 
     2145            ) _MapOpBinaryRightRTs; 
     2146    } 
     2147 
     2148 
     2149    /* 
     2150     * storageAs!Active[ indices[0], ... ] 
     2151     */ 
     2152    _ReduceOpGenericRT!(_MapOpIndexRTs!(Indices)) 
     2153        opIndex(Indices...)(Indices indices) 
     2154    { 
     2155        enum size_t K       = Indices.length; 
     2156        enum string attempt = to!string(K) ~ "-indexing"; 
     2157 
     2158        static assert(_MapOpIndexRTs!(Indices).length, 
     2159                _invalidOpMsg(attempt)); 
     2160        if (_which == size_t.max) 
     2161            throw new VariantException(_emptyMsg(attempt)); 
     2162 
     2163        mixin (_returnUsingActiveObject!( 
     2164//              "_storageAs!Active()[indices]" // @@@BUG4444@@@ 
     2165                "_storageAs!Active()[" ~ expandArray("indices", K) ~ "]" 
     2166            )); 
     2167        throw new VariantException(_undefinedOpMsg(attempt)); 
     2168    } 
     2169 
     2170    private template _MapOpIndexRTs(Indices...) 
     2171    { 
     2172        alias _MapOpGenericRTs!(0, 
     2173//              "phony!Active[phonyList!Args]", // @@@BUG4444@@@ 
     2174                "phony!Active[" ~ expandArray("phonyList!Args", Indices.length) ~ "]", 
     2175                Indices 
     2176            ) _MapOpIndexRTs; 
     2177    } 
     2178 
     2179 
     2180    /* 
     2181     * storageAs!Active[i .. j] 
     2182     */ 
     2183    _ReduceOpGenericRT!(_MapOpSliceRTs!(I, J)) 
     2184        opSlice(I, J)(I i, J j) 
     2185    { 
     2186        enum string attempt = "slicing"; 
     2187 
     2188        static assert(_MapOpSliceRTs!(I, J).length, 
     2189                _invalidOpMsg(attempt)); 
     2190        if (_which == size_t.max) 
     2191            throw new VariantException(_emptyMsg(attempt)); 
     2192 
     2193        mixin (_returnUsingActiveObject!( 
     2194                "_storageAs!Active()[i .. j]" 
     2195            )); 
     2196        throw new VariantException(_undefinedOpMsg(attempt)); 
     2197    } 
     2198 
     2199    private template _MapOpSliceRTs(I, J) 
     2200    { 
     2201        alias _MapOpGenericRTs!(0, 
     2202                "phony!Active[phony!(Args[0]) .. phony!(Args[1])]", 
     2203                I, J 
     2204            ) _MapOpSliceRTs; 
     2205    } 
     2206 
     2207 
     2208    /* 
     2209     * storageAs!Active[] 
     2210     */ 
     2211    _ReduceOpGenericRT!(_MapOpSliceRTs!()) 
     2212        opSlice()() 
     2213    { 
     2214        enum string attempt = "whole-slicing"; 
     2215 
     2216        static assert(_MapOpSliceRTs!().length, _invalidOpMsg(attempt)); 
     2217        if (_which == size_t.max) 
     2218            throw new VariantException(_emptyMsg(attempt)); 
     2219 
     2220        mixin (_returnUsingActiveObject!( 
     2221                "_storageAs!Active()[]" 
     2222            )); 
     2223        throw new VariantException(_undefinedOpMsg(attempt)); 
     2224    } 
     2225 
     2226    private template _MapOpSliceRTs() 
     2227    { 
     2228        alias _MapOpGenericRTs!(0, "phony!Active[]") _MapOpSliceRTs; 
     2229    } 
     2230 
     2231 
     2232    /* 
     2233     * <op>storageAs!Active[ indices[0], ... ] 
     2234     */ 
     2235    _ReduceOpGenericRT!(_MapOpIndexUnaryRTs!(op, Indices)) 
     2236        opIndexUnary(string op, Indices...)(Indices indices) 
     2237    { 
     2238        enum size_t K       = Indices.length; 
     2239        enum string attempt = to!string(K) ~ "-indexing unary " ~ op; 
     2240 
     2241        static assert(_MapOpIndexUnaryRTs!(op, Indices).length, 
     2242                _invalidOpMsg(attempt)); 
     2243        if (_which == size_t.max) 
     2244            throw new VariantException(_emptyMsg(attempt)); 
     2245 
     2246        mixin (_returnUsingActiveObject!( 
     2247//              op~"_storageAs!Active()[indices]"   // @@@BUG4444@@@ 
     2248                op~"_storageAs!Active()[" ~ expandArray("indices", K) ~ "]" 
     2249            )); 
     2250        throw new VariantException(_undefinedOpMsg(attempt)); 
     2251    } 
     2252 
     2253    private template _MapOpIndexUnaryRTs(string op, Indices...) 
     2254    { 
     2255        alias _MapOpGenericRTs!(0, 
     2256//              op~"phony!Active[phonyList!Args]",  // @@@BUG4444@@@ 
     2257                op~"phony!Active[" 
     2258                    ~ expandArray("phonyList!Args", Indices.length) ~ "]", 
     2259                Indices 
     2260            ) _MapOpIndexUnaryRTs; 
     2261    } 
     2262 
     2263 
     2264    /* 
     2265     * <op>storageAs!Active[i .. j] 
     2266     */ 
     2267    _ReduceOpGenericRT!(_MapOpSliceUnaryRTs!(op, I, J)) 
     2268        opSliceUnary(string op, I, J)(I i, J j) 
     2269    { 
     2270        enum string attempt = "unary slicing " ~ op; 
     2271 
     2272        static assert(_MapOpSliceUnaryRTs!(op, I, J).length, 
     2273                _invalidOpMsg(attempt)); 
     2274        if (_which == size_t.max) 
     2275            throw new VariantException(_emptyMsg(attempt)); 
     2276 
     2277        mixin (_returnUsingActiveObject!( 
     2278                op~"_storageAs!Active()[i .. j]" 
     2279            )); 
     2280        throw new VariantException(_undefinedOpMsg(attempt)); 
     2281    } 
     2282 
     2283    private template _MapOpSliceUnaryRTs(string op, I, J) 
     2284    { 
     2285        alias _MapOpGenericRTs!(0, 
     2286                op~"phony!Active[phony!(Args[0]) .. phony!(Args[1])]", 
     2287                I, J 
     2288            ) _MapOpSliceUnaryRTs; 
     2289    } 
     2290 
     2291 
     2292    /* 
     2293     * <op>storageAs!Active[] 
     2294     */ 
     2295    _ReduceOpGenericRT!(_MapOpSliceUnaryRTs!(op)) 
     2296        opSliceUnary(string op)() 
     2297    { 
     2298        enum string attempt = "unary whole-slicing " ~ op; 
     2299 
     2300        static assert(_MapOpSliceUnaryRTs!(op).length, 
     2301                _invalidOpMsg(attempt)); 
     2302        if (_which == size_t.max) 
     2303            throw new VariantException(_emptyMsg(attempt)); 
     2304 
     2305        mixin (_returnUsingActiveObject!( 
     2306                op~"_storageAs!Active()[]" 
     2307            )); 
     2308        throw new VariantException(_undefinedOpMsg(attempt)); 
     2309    } 
     2310 
     2311    private template _MapOpSliceUnaryRTs(string op) 
     2312    { 
     2313        alias _MapOpGenericRTs!(0, op ~ "phony!Active[]") _MapOpSliceUnaryRTs; 
     2314    } 
     2315 
     2316 
     2317    /* 
     2318     * storageAs!Active[ indices[0], ... ] = rhs 
     2319     */ 
     2320    _ReduceOpGenericRT!(_MapOpIndexAssignRTs!(RHS, Indices)) 
     2321        opIndexAssign(RHS, Indices...)(RHS rhs, Indices indices) 
     2322            if (!_isCompatibleAlgebraic!(RHS)) 
     2323    { 
     2324        enum size_t K       = Indices.length; 
     2325        enum string attempt = to!string(K) ~ "-indexing assignment of " 
     2326                                ~ RHS.stringof; 
     2327 
     2328        static assert(_MapOpIndexAssignRTs!(RHS, Indices).length, 
     2329                _invalidOpMsg(attempt)); 
     2330        if (_which == size_t.max) 
     2331            throw new VariantException(_emptyMsg(attempt)); 
     2332 
     2333        mixin (_returnUsingActiveObject!( 
     2334//              "_storageAs!Active()[indices] = rhs"    // @@@BUG4444@@@ 
     2335                "_storageAs!Active()[" ~ expandArray("indices", K) ~ "] = rhs" 
     2336            )); 
     2337        throw new VariantException(_undefinedOpMsg(attempt)); 
     2338    } 
     2339 
     2340    private template _MapOpIndexAssignRTs(RHS, Indices...) 
     2341    { 
     2342        alias _MapOpGenericRTs!(0, 
     2343//              "phony!Active[ phonyList!(Args[1 .. $]) ] = phony!(Args[0])", // @@@BUG4444@@@ 
     2344                "phony!Active[" ~ expandArray( 
     2345                    "phonyList!(Args[1 .. $])", Indices.length) 
     2346                        ~ "] = phony!(Args[0])", 
     2347                RHS, Indices 
     2348            ) _MapOpIndexAssignRTs; 
     2349    } 
     2350 
     2351 
     2352    /* 
     2353     * storageAs!Active[i .. j] = rhs 
     2354     */ 
     2355    _ReduceOpGenericRT!(_MapOpSliceAssignRTs!(RHS, I, J)) 
     2356        opSliceAssign(RHS, I, J)(RHS rhs, I i, J j) 
     2357            if (!_isCompatibleAlgebraic!(RHS)) 
     2358    { 
     2359        enum string attempt = "slicing assignment of " ~ RHS.stringof; 
     2360 
     2361        static assert(_MapOpSliceAssignRTs!(RHS, I, J).length, 
     2362                _invalidOpMsg(attempt)); 
     2363        if (_which == size_t.max) 
     2364            throw new VariantException(_emptyMsg(attempt)); 
     2365 
     2366        mixin (_returnUsingActiveObject!( 
     2367                "_storageAs!Active()[i .. j] = rhs" 
     2368            )); 
     2369        throw new VariantException(_undefinedOpMsg(attempt)); 
     2370    } 
     2371 
     2372    private template _MapOpSliceAssignRTs(RHS, I, J) 
     2373    { 
     2374        alias _MapOpGenericRTs!(0, 
     2375                "phony!Active[phony!(Args[1]) .. phony!(Args[2])]" 
     2376                    ~ " = phony!(Args[0])", 
     2377                RHS, I, J 
     2378            ) _MapOpSliceAssignRTs; 
     2379    } 
     2380 
     2381 
     2382    /* 
     2383     * storageAs!Active[] = rhs 
     2384     */ 
     2385    _ReduceOpGenericRT!(_MapOpSliceAssignRTs!(RHS)) 
     2386        opSliceAssign(RHS)(RHS rhs) 
     2387            if (!_isCompatibleAlgebraic!(RHS)) 
     2388    { 
     2389        enum string attempt = "whole-slicing assignment of " ~ RHS.stringof; 
     2390 
     2391        static assert(_MapOpSliceAssignRTs!(RHS).length, 
     2392                _invalidOpMsg(attempt)); 
     2393        if (_which == size_t.max) 
     2394            throw new VariantException(_emptyMsg(attempt)); 
     2395 
     2396        mixin (_returnUsingActiveObject!( 
     2397                "_storageAs!Active()[] = rhs" 
     2398            )); 
     2399        throw new VariantException(_undefinedOpMsg(attempt)); 
     2400    } 
     2401 
     2402    private template _MapOpSliceAssignRTs(RHS) 
     2403    { 
     2404        alias _MapOpGenericRTs!(0, 
     2405                "phony!Active[] = phony!(Args[0])", 
     2406                RHS 
     2407            ) _MapOpSliceAssignRTs; 
     2408    } 
     2409 
     2410 
     2411    /* 
     2412     * storageAs!Active <op>= rhs 
     2413     */ 
     2414    _ReduceOpGenericRT!(_MapOpOpAssignRTs!(op, RHS)) 
     2415        opOpAssign(string op, RHS)(RHS rhs) 
     2416            if (!_isCompatibleAlgebraic!(RHS)) 
     2417    { 
     2418        enum string attempt = "binary assignment "~op~"= " ~ RHS.stringof; 
     2419 
     2420        static assert(_MapOpOpAssignRTs!(op, RHS).length, 
     2421                _invalidOpMsg(attempt)); 
     2422        if (_which == size_t.max) 
     2423            throw new VariantException(_emptyMsg(attempt)); 
     2424 
     2425        mixin (_returnUsingActiveObject!( 
     2426                "_storageAs!Active() "~op~"= rhs" 
     2427            )); 
     2428        throw new VariantException(_undefinedOpMsg(attempt)); 
     2429    } 
     2430 
     2431    private template _MapOpOpAssignRTs(string op, RHS) 
     2432    { 
     2433        alias _MapOpGenericRTs!(0, 
     2434                "phony!Active "~op~"= phony!(Args[0])", 
     2435                RHS 
     2436            ) _MapOpOpAssignRTs; 
     2437    } 
     2438 
     2439 
     2440    /* 
     2441     * storageAs!Active[ indices[0], ... ] <op>= rhs 
     2442     */ 
     2443    _ReduceOpGenericRT!(_MapOpIndexOpAssignRTs!(op, RHS, Indices)) 
     2444        opIndexOpAssign(string op, RHS, Indices...)(RHS rhs, Indices indices) 
     2445            if (!_isCompatibleAlgebraic!(RHS)) 
     2446    { 
     2447        enum string attempt = "binary indexing assignment " 
     2448                                ~op~"= " ~ RHS.stringof; 
     2449 
     2450        static assert(_MapOpIndexOpAssignRTs!(op, RHS, Indices).length, 
     2451                _invalidOpMsg(attempt)); 
     2452        if (_which == size_t.max) 
     2453            throw new VariantException(_emptyMsg(attempt)); 
     2454 
     2455        mixin (_returnUsingActiveObject!( 
     2456//              "_storageAs!Active()[indices] "~op~"= rhs"  // @@@BUG4444@@@ 
     2457                "_storageAs!Active()[" 
     2458                        ~ expandArray("indices", Indices.length) 
     2459                    ~ "] "~op~"= rhs" 
     2460            )); 
     2461        throw new VariantException(_undefinedOpMsg(attempt)); 
     2462    } 
     2463 
     2464    private template _MapOpIndexOpAssignRTs(string op, RHS, Indices...) 
     2465    { 
     2466        alias _MapOpGenericRTs!(0, 
     2467//              "phony!Active[phonyList!(Args[1 .. $])] " 
     2468//                  ~op~"= phony!(Args[0])",    // @@@BUG4444@@@ 
     2469                "phony!Active[" ~ expandArray( 
     2470                    "phonyList!(Args[1 .. $])", Indices.length) ~ "] " 
     2471                    ~op~"= phony!(Args[0])", 
     2472                RHS, Indices 
     2473            ) _MapOpIndexOpAssignRTs; 
     2474    } 
     2475 
     2476 
     2477    /* 
     2478     * storageAs!Active[i .. j] <op>= rhs 
     2479     */ 
     2480    _ReduceOpGenericRT!(_MapOpSliceOpAssignRTs!(op, RHS, I, J)) 
     2481         opSliceOpAssign(string op, RHS, I, J)(RHS rhs, I i, J j) 
     2482            if (!_isCompatibleAlgebraic!(RHS)) 
     2483    { 
     2484        enum string attempt = "binary slicing assignment " 
     2485                                ~op~"= " ~ RHS.stringof; 
     2486 
     2487        static assert(_MapOpSliceOpAssignRTs!(op, RHS, I, J).length, 
     2488                _invalidOpMsg(attempt)); 
     2489        if (_which == size_t.max) 
     2490            throw new VariantException(_emptyMsg(attempt)); 
     2491 
     2492        mixin (_returnUsingActiveObject!( 
     2493                "_storageAs!Active()[i .. j] "~op~"= rhs" 
     2494            )); 
     2495        throw new VariantException(_undefinedOpMsg(attempt)); 
     2496    } 
     2497 
     2498    private template _MapOpSliceOpAssignRTs(string op, RHS, I, J) 
     2499    { 
     2500        alias _MapOpGenericRTs!(0, 
     2501                "phony!Active[phony!(Args[1]) .. phony!(Args[2])] " 
     2502                    ~op~"= phony!(Args[0])", 
     2503                RHS, I, J 
     2504            ) _MapOpSliceOpAssignRTs; 
     2505    } 
     2506 
     2507 
     2508    /* 
     2509     * storageAs!Active[] <op>= rhs 
     2510     */ 
     2511    _ReduceOpGenericRT!(_MapOpSliceOpAssignRTs!(op, RHS)) 
     2512        opSliceOpAssign(string op, RHS)(RHS rhs) 
     2513            if (!_isCompatibleAlgebraic!(RHS)) 
     2514    { 
     2515        enum string attempt = "binary whole-slicing assignment " 
     2516                                ~op~"= " ~ RHS.stringof; 
     2517 
     2518        static assert(_MapOpSliceOpAssignRTs!(op, RHS).length, 
     2519                _invalidOpMsg(attempt)); 
     2520        if (_which == size_t.max) 
     2521            throw new VariantException(_emptyMsg(attempt)); 
     2522 
     2523        mixin (_returnUsingActiveObject!( 
     2524                "_storageAs!Active()[] "~op~"= rhs" 
     2525            )); 
     2526        throw new VariantException(_undefinedOpMsg(attempt)); 
     2527    } 
     2528 
     2529    private template _MapOpSliceOpAssignRTs(string op, RHS) 
     2530    { 
     2531        alias _MapOpGenericRTs!(0, 
     2532                "phony!Active[] "~op~"= phony!(Args[0])", 
     2533                RHS 
     2534            ) _MapOpSliceOpAssignRTs; 
     2535    } 
     2536 
     2537 
     2538    //--------------------------------------------------------------------// 
     2539 
     2540    /* 
     2541     * cast(T) storageAs!Active 
     2542     */ 
     2543    T opCast(T)() 
     2544    { 
     2545        enum attempt = "casting to " ~ T.stringof; 
     2546 
     2547        if (_which == size_t.max) 
     2548            throw new VariantException(_emptyMsg(attempt)); 
     2549        mixin (_onActiveObject!( 
     2550            q{ 
     2551                static if (is(Active : T)) 
     2552                    return         _storageAs!Active; 
     2553//              else static if (__traits(compiles, cast(T) _storageAs!Active))  // @@@ e2ir 
     2554                else static if (is(typeof(Active.opCast!T) R == return) && is(R == T)) 
     2555                    return cast(T) _storageAs!Active; 
     2556            })); 
     2557        throw new VariantException(_undefinedOpMsg(attempt)); 
     2558    } 
     2559 
     2560 
     2561    /* 
     2562     * storageAs!Active == rhs 
     2563     */ 
     2564    bool opEquals(RHS)(auto ref RHS rhs) const 
     2565            if (!_isCompatibleAlgebraic!(RHS)) 
     2566    { 
     2567        enum attempt = "equality comparison with " ~ RHS.stringof; 
     2568 
     2569        if (_which == size_t.max) 
     2570            throw new VariantException(_emptyMsg(attempt)); 
     2571        mixin (_onActiveObject!( 
     2572            q{ 
     2573                static if (__traits(compiles, 
     2574                        _storageAs_const!Active() == rhs)) 
     2575                    return _storageAs_const!Active() == rhs; 
     2576            })); 
     2577        throw new VariantException(_undefinedOpMsg(attempt)); 
     2578    } 
     2579 
     2580    // Algebraic vs. Algebraic 
     2581    bool opEquals(RHS)(ref const RHS rhs) const 
     2582            if (is(RHS == typeof(this))) 
     2583    { 
     2584        if (_which != size_t.max && _which == rhs._which) 
     2585        { 
     2586            mixin (_onActiveObject!( 
     2587                q{ 
     2588                    return _storageAs_const!Active() == 
     2589                            rhs._storageAs_const!Active; 
     2590                })); 
     2591            assert(0); 
     2592        } 
     2593        else 
     2594        { 
     2595            return false; 
     2596        } 
     2597    } 
     2598 
     2599 
     2600    /* 
     2601     * storageAs!Active <>= rhs 
     2602     */ 
     2603    int opCmp(RHS)(auto ref RHS rhs) const 
     2604            if (!_isCompatibleAlgebraic!(RHS)) 
     2605    { 
     2606        enum attempt = "ordering comparison with " ~ RHS.stringof; 
     2607 
     2608        if (_which == size_t.max) 
     2609            throw new VariantException(_emptyMsg(attempt)); 
     2610        mixin (_onActiveObject!( 
     2611            q{ 
     2612                static if (__traits(compiles, _storageAs_const!Active < rhs)) 
     2613                { 
     2614                    return (_storageAs_const!Active < rhs) ? -1 : 
     2615                           (_storageAs_const!Active > rhs) ?  1 : 0; 
     2616                } 
     2617            })); 
     2618        throw new VariantException(_undefinedOpMsg(attempt)); 
     2619    } 
     2620 
     2621    // Algebraic vs. Algebraic 
     2622    int opCmp(RHS)(ref const RHS rhs) const 
     2623            if (is(RHS == typeof(this))) 
     2624    { 
     2625        enum attempt = "ordering comparison"; 
     2626 
     2627        if (_which == size_t.max) 
     2628            throw new VariantException(_emptyMsg(attempt)); 
     2629        mixin (_onActiveObject!( 
     2630            q{ 
     2631                return -rhs.opCmp(_storageAs_const!Active); 
     2632            })); 
     2633        assert(0); 
     2634    } 
     2635 
     2636/+ 
     2637// @@@BUG4253@@@ 
     2638    _ReduceOpGenericRT!(_MapOpCallRTs!(Args)) 
     2639        opCall(Args...)(auto ref Args args) 
     2640    { 
     2641        enum string attempt = "calling operator"; 
     2642 
     2643        static assert(_MapOpCallRTs!(Args).length, 
     2644                _invalidOpMsg(attempt)); 
     2645        if (_which == size_t.max) 
     2646            throw new VariantException(_emptyMsg(attempt)); 
     2647 
     2648        mixin (_returnUsingActiveObject!( 
     2649                "_storageAs!Active(args)" 
     2650            )); 
     2651        throw new VariantException(_undefinedOpMsg(attempt)); 
     2652    } 
     2653 
     2654    private template _MapOpCallRTs(Args...) 
     2655    { 
     2656        alias _MapOpGenericRTs!(0, 
     2657                "phony!Active(phonyList!Args)", 
     2658                Args 
     2659            ) _MapOpCallRTs; 
     2660    } 
     2661+/ 
     2662 
     2663/+ 
     2664// @@@ cannot coexist with input range primitives 
     2665    int opApply(Args...)(int delegate(ref Args) dg) 
     2666    { 
     2667        enum attempt = "foreach"; 
     2668 
     2669        if (_which == size_t.max) 
     2670            throw new VariantException(_emptyMsg(attempt)); 
     2671        mixin (_onActiveObject!( 
     2672            q{ 
     2673                static if (__traits(compiles, 
     2674                        _storageAs!Active().opApply(dg))) 
     2675                    return _storageAs!Active().opApply(dg); 
     2676            })); 
     2677        throw new VariantException(_undefinedOpMsg(attempt)); 
     2678    } 
     2679+/ 
     2680 
     2681 
     2682    //--------------------------------------------------------------------// 
     2683    // special functions 
     2684 
     2685    @system string toString() 
     2686    { 
     2687        if (_which == size_t.max) 
     2688            return typeof(this).stringof ~ "(empty)"; 
     2689 
     2690        mixin (_onActiveObject!( 
     2691            q{ 
     2692                static if (__traits(compiles, 
     2693                        to!string(_storageAs!Active) )) 
     2694                    return to!string(_storageAs!Active); 
     2695                else 
     2696                    return Active.stringof; 
     2697            })); 
     2698        assert(0); 
     2699    } 
     2700//  @system string toString( 
     2701//      void delegate(const(char)[]) sink = null, 
     2702//      string fmt = null) 
     2703 
     2704    @system hash_t toHash() const 
     2705    { 
     2706        if (_which == size_t.max) 
     2707            return 0; 
     2708 
     2709        mixin (_onActiveObject!( 
     2710            q{ 
     2711                return typeid(Active).getHash(_storage.ptr); 
     2712            })); 
     2713        assert(0); 
     2714    } 
     2715 
     2716 
     2717    // input range primitives 
     2718    static if (_canDispatch!"front" && 
     2719               _canDispatch!"empty" && 
     2720               _canDispatch!"popFront") 
     2721    { 
     2722        @property bool empty() 
     2723        { 
     2724            return opDispatch!"empty"(); 
     2725        } 
     2726        @property auto ref front() 
     2727        { 
     2728            return opDispatch!"front"(); 
     2729        } 
     2730        void popFront() 
     2731        { 
     2732            opDispatch!"popFront"(); 
     2733        } 
     2734    } 
     2735 
     2736    // forward range primitive 
     2737    static if (_canDispatch!"save") 
     2738    { 
     2739        @property typeof(this) save() 
     2740        { 
     2741            enum string attempt = "range primitive save()"; 
     2742            if (_which == size_t.max) 
     2743                throw new VariantException(_emptyMsg(attempt)); 
     2744            mixin (_returnUsingActiveObject!( 
     2745                    "_storageAs!Active.save" 
     2746                )); 
     2747            throw new VariantException(_undefinedOpMsg(attempt)); 
     2748        } 
     2749    } 
     2750 
     2751    // bidirectional range primitives 
     2752    static if (_canDispatch!"back" && 
     2753               _canDispatch!"popBack") 
     2754    { 
     2755        @property auto ref back() 
     2756        { 
     2757            return opDispatch!"back"(); 
     2758        } 
     2759        void popBack() 
     2760        { 
     2761            opDispatch!"popBack"(); 
     2762        } 
     2763    } 
     2764 
     2765 
     2766    //------------------------------------------------------------// 
     2767    // internals 
     2768private: 
     2769 
     2770    /* 
     2771     * Returns the internal code number of the type $(D T), or 
     2772     * $(D size_t.max) if $(D T) is not in $(D Types...). 
     2773     */ 
     2774    template _typeCode(T, size_t id = 0) 
     2775    { 
     2776        static if (id < _Types.length) 
     2777        { 
     2778            static if (is(T == _Types[id])) 
     2779                enum size_t _typeCode = id; 
     2780            else 
     2781                enum size_t _typeCode = _typeCode!(T, id + 1); 
     2782        } 
     2783        else 
     2784        { 
     2785            enum size_t _typeCode = size_t.max; 
     2786        } 
     2787    } 
     2788 
     2789 
     2790    /* 
     2791     * Returns a reference to the storage as an object of type $(D T). 
     2792     */ 
     2793    @trusted nothrow ref T _storageAs(T)() 
     2794            if (_typeCode!T != size_t.max) 
     2795    { 
     2796        return *cast(T*) _storage.ptr; 
     2797    } 
     2798    @trusted nothrow ref const(T) _storageAs_const(T)() const 
     2799            if (_typeCode!T != size_t.max) 
     2800    { 
     2801        return *cast(const T*) _storage.ptr; 
     2802    } 
     2803    /+ // @@@BUG3748@@@ 
     2804    @trusted nothrow ref inout(T) storageAs(T)() inout 
     2805    +/ 
     2806 
     2807 
     2808    /* 
     2809     * Generates code for doing $(D stmt) on the active object. 
     2810     */ 
     2811    template _onActiveObject(string stmt) 
     2812    { 
     2813        enum string _onActiveObject = 
     2814                 "assert(_which != size_t.max);" 
     2815            ~"L_chooseActive:" 
     2816                ~"final switch (_which)" 
     2817                ~"{" 
     2818                    ~"foreach (Active; _Types)" 
     2819                    ~"{" 
     2820                    ~"case _typeCode!Active:" 
     2821                        ~stmt 
     2822                        ~"break L_chooseActive;" 
     2823                    ~"}" 
     2824                ~"}"; 
     2825    } 
     2826 
     2827 
     2828    /* 
     2829     * Error message for an attempting against any operation on an 
     2830     * empty Algebraic object. 
     2831     */ 
     2832    static @safe pure nothrow string _emptyMsg(string attempt) 
     2833    { 
     2834        return "Attempted to evaluate " ~ attempt ~ " on an empty " 
     2835            ~ typeof(this).stringof; 
     2836    } 
     2837 
     2838    /* 
     2839     * Error message for an attempting to evaluate any operation that 
     2840     * is not defined by any of $(D Types...). 
     2841     */ 
     2842    static @safe pure nothrow string _invalidOpMsg(string op) 
     2843    { 
     2844        return "No type in " ~ typeof(this).stringof ~ " defines " ~ op; 
     2845    } 
     2846 
     2847    /* 
     2848     * Error message for an attempting to evaluate any operation that 
     2849     * is not defined by the active object. 
     2850     */ 
     2851    @safe nothrow string _undefinedOpMsg(string op) const 
     2852    in 
     2853    { 
     2854        assert(_which != size_t.max); 
     2855    } 
     2856    body 
     2857    { 
     2858        string typeName; 
     2859 
     2860        mixin (_onActiveObject!( 
     2861            q{ 
     2862                typeName = Active.stringof; 
     2863            })); 
     2864        return "An active object of type " ~ typeName ~ " does not " 
     2865            ~ "define " ~ op; 
     2866    } 
     2867 
     2868 
     2869    /* 
     2870     * Store $(D rhs) in the internal storage. 
     2871     */ 
     2872    @system void _grab(T)(ref T rhs) 
     2873    in 
     2874    { 
     2875        assert(_which == size_t.max); 
     2876    } 
     2877    out 
     2878    { 
     2879        assert(_which != size_t.max); 
     2880    } 
     2881    body 
     2882    { 
     2883        static if (_typeCode!T != size_t.max) 
     2884        { 
     2885            // Simple blit. 
     2886            initialize(_storageAs!T); 
     2887            swap(_storageAs!T, rhs); 
     2888            _which = _typeCode!T; 
     2889        } 
     2890        else 
     2891        { 
     2892            // Use opAssign matched first. 
     2893            foreach (Active; _Types) 
     2894            { 
     2895                static if (__traits(compiles, _storageAs!Active() = rhs)) 
     2896                { 
     2897                    initialize(_storageAs!Active); 
     2898                    _storageAs!Active() = rhs;  // may be @system 
     2899                    _which = _typeCode!Active; 
     2900                    break; 
     2901                } 
     2902            } 
     2903        } 
     2904    } 
     2905 
     2906 
     2907    /* 
     2908     * Assigns $(D rhs) to the non-empty active storage. 
     2909     */ 
     2910    @system void _assign(T)(ref T rhs) 
     2911    in 
     2912    { 
     2913        assert(_which != size_t.max); 
     2914    } 
     2915    body 
     2916    { 
     2917        mixin (_onActiveObject!( 
     2918            q{ 
     2919                static if (__traits(compiles, _storageAs!Active() = rhs)) 
     2920                    return _storageAs!Active() = rhs;   // may be @system 
     2921            })); 
     2922 
     2923        // Or, replace the content with rhs. 
     2924        _dispose(); 
     2925        _grab(rhs); 
     2926    } 
     2927 
     2928 
     2929    /* 
     2930     * Destroys the active object (if it's a struct) and marks this 
     2931     * $(D Algebraic) object empty. 
     2932     */ 
     2933    @trusted void _dispose() 
     2934    in 
     2935    { 
     2936        assert(_which != size_t.max); 
     2937    } 
     2938    out 
     2939    { 
     2940        assert(_which == size_t.max); 
     2941    } 
     2942    body 
     2943    { 
     2944        mixin (_onActiveObject!( 
     2945            q{ 
     2946                static if (__traits(compiles, _storageAs!Active.__dtor())) 
     2947                    _storageAs!Active.__dtor(); 
     2948                _which = size_t.max; 
     2949                return; 
     2950            })); 
     2951        assert(0); 
     2952    } 
     2953 
     2954 
     2955    //------------------------------------------------------------------------// 
     2956private: 
     2957    void*[(maxSize!_Types + (void*).sizeof - 1) / (void*).sizeof] 
     2958            _storage; 
     2959    size_t  _which = size_t.max;    // typeCode of the active object 
     2960} 
     2961 
     2962 
     2963version (unittest) private 
     2964{ 
     2965    bool eq(S)(S a, S b) 
     2966    { 
     2967        foreach (i, _; a.tupleof) 
     2968        { 
     2969            if (a.tupleof[i] != b.tupleof[i]) 
     2970                return false; 
     2971        } 
     2972        return true; 
     2973    } 
     2974 
     2975    bool fails(lazy void expr) 
     2976    { 
     2977        try { expr; } catch (VariantException e) { return true; } 
     2978        return false; 
     2979    } 
     2980} 
     2981 
     2982//-------------- doc examples 
     2983 
     2984unittest 
     2985{ 
     2986    // doc example 0 
     2987    Algebraic!(int, double) x; 
     2988 
     2989    // these lines won't compile since long and string are not allowed 
     2990//  auto n = x.Algebraic.instance!long; 
     2991//  x = "abc"; 
     2992    assert(!__traits(compiles, x.Algebraic.instance!long)); 
     2993    assert(!__traits(compiles, x = "abc")); 
     2994} 
     2995 
     2996unittest 
     2997{ 
     2998    // doc example 1 
     2999    Algebraic!(int, double, string) v = 5; 
     3000    assert(v.Algebraic.isActive!int); 
     3001 
     3002    v = 3.14; 
     3003    assert(v.Algebraic.isActive!double); 
     3004 
     3005    v *= 2; 
     3006    assert(v > 6); 
     3007} 
     3008 
     3009unittest 
     3010{ 
     3011    // doc example 2 
     3012    Algebraic!(string, wstring, dstring) s; 
     3013 
     3014    s = "The quick brown fox jumps over the lazy dog."; 
     3015    assert(s.front == 'T'); 
     3016    assert(s.back == '.'); 
     3017    assert(s.length == 44); 
     3018    s.popBack; 
     3019    assert(equal(take(retro(s), 3), "god")); 
     3020} 
     3021 
     3022unittest 
     3023{ 
     3024    // doc exmaple 3 
     3025    Algebraic!(int, double, string) x = 42; 
     3026 
     3027    x.Algebraic.dispatch( 
     3028            (ref int n) 
     3029            { 
     3030                //writeln("saw an int: ", n); 
     3031                assert(n == 42); 
     3032                ++n; 
     3033            }, 
     3034            (string s) 
     3035            { 
     3036                //writeln("saw a string: ", s); 
     3037                assert(0); 
     3038            } 
     3039        ); 
     3040    assert(x == 43);    // incremented 
     3041} 
     3042 
     3043unittest 
     3044{ 
     3045    // doc example 4 
     3046    Algebraic!(int, int, real, int) x; 
     3047    assert(is( x.Algebraic.Types == TypeTuple!(int, real) )); 
     3048} 
     3049 
     3050unittest 
     3051{ 
     3052    // doc example 5 - take a pointer to the active object 
     3053    struct A {} 
     3054    struct B {} 
     3055    Algebraic!(A, B) ab; 
     3056    /+ 
     3057    Algebraic!(A, B) ab = A(); 
     3058 
     3059    assert(ab.Algebraic.isActive!A); 
     3060    A* p = &(ab.Algebraic.instance!A()); 
     3061//  B* q = &(ab.Algebraic.instance!B());    // throws VariantException 
     3062    B* q; 
     3063    assert(fails( q = &(ab.Algebraic.instance!B()) )); 
     3064    +/ 
     3065} 
     3066 
     3067//-------------- 
     3068 
     3069unittest 
     3070{ 
     3071    // funny types 
     3072    assert(!__traits(compiles, Algebraic!())); 
     3073    assert(!__traits(compiles, Algebraic!(void))); 
     3074    assert(!__traits(compiles, Algebraic!(int, void, dchar))); 
     3075    assert(!__traits(compiles, Algebraic!(int, 42, short))); 
     3076    assert(is( Algebraic!(int, real, int) == Algebraic!(int, real) )); 
     3077} 
     3078 
     3079unittest 
     3080{ 
     3081    // copy constructor & destructor 
     3082    struct Counter 
     3083    { 
     3084        int* copies; 
     3085        this(this) { copies && ++*copies; } 
     3086        ~this()    { copies && --*copies; } 
     3087    } 
     3088    Algebraic!(Counter) a; 
     3089    a = Counter(new int); 
     3090    assert(*a.copies == 0); 
     3091    { 
     3092        auto b = a; 
     3093        assert(*a.copies == 1); 
     3094        { 
     3095            auto c = a; 
     3096            assert(*a.copies == 2); 
     3097        } 
     3098        assert(*a.copies == 1); 
     3099    } 
     3100    assert(*a.copies == 0); 
     3101} 
     3102 
     3103unittest 
     3104{ 
     3105    // basic use 
     3106    int afoo, bfoo; 
     3107    struct A { 
     3108        int inc() { return ++afoo; } 
     3109        int dec() { return --afoo; } 
     3110    } 
     3111    struct B { 
     3112        int inc() { return --bfoo; } 
     3113        int dec() { return ++bfoo; } 
     3114    } 
     3115    Algebraic!(A, B) ab; 
     3116    ab = A(); 
     3117    assert(ab.inc() == 1 && afoo == 1); 
     3118    assert(ab.dec() == 0 && afoo == 0); 
     3119    ab = B(); 
     3120    assert(ab.inc() == -1 && bfoo == -1); 
     3121    assert(ab.dec() ==  0 && bfoo ==  0); 
     3122} 
     3123 
     3124unittest 
     3125{ 
     3126    // constructor 
     3127    auto x = Algebraic!(int, real)(4.5); 
     3128    assert(x == 4.5); 
     3129} 
     3130 
     3131unittest 
     3132{ 
     3133    // meta interface 
     3134    Algebraic!(int, real) a; 
     3135 
     3136    assert(is(a.Algebraic.Types == TypeTuple!(int, real))); 
     3137    assert(a.Algebraic.allowed!int); 
     3138    assert(a.Algebraic.allowed!real); 
     3139    assert(!a.Algebraic.allowed!string); 
     3140 
     3141    assert(a.Algebraic.canAssign!int); 
     3142    assert(a.Algebraic.canAssign!real); 
     3143    assert(a.Algebraic.canAssign!byte); 
     3144    assert(a.Algebraic.canAssign!short); 
     3145    assert(a.Algebraic.canAssign!ushort); 
     3146    assert(a.Algebraic.canAssign!double); 
     3147    assert(a.Algebraic.canAssign!(const int)); 
     3148    assert(a.Algebraic.canAssign!(immutable int)); 
     3149    assert(!a.Algebraic.canAssign!string); 
     3150    assert(!a.Algebraic.canAssign!void); 
     3151    assert(!a.Algebraic.canAssign!(int*)); 
     3152    assert(!a.Algebraic.canAssign!(int[])); 
     3153 
     3154    assert(!__traits(compiles, a.Algebraic.get!(int[]))); 
     3155    assert(!__traits(compiles, a.Algebraic.coerce!(int[]))); 
     3156    assert(!__traits(compiles, a.Algebraic.instance!(int[]))); 
     3157 
     3158    assert(a.Algebraic.empty); 
     3159 
     3160    a = 42; 
     3161    assert(!a.Algebraic.empty); 
     3162    assert( a.Algebraic.isActive!int); 
     3163    assert(!a.Algebraic.isActive!real); 
     3164    assert(!a.Algebraic.isActive!string); 
     3165    assert(fails( a.Algebraic.instance!real )); 
     3166    int* i = &(a.Algebraic.instance!int()); 
     3167    assert(*i == 42); 
     3168    assert(a.Algebraic.convertsTo!(long)); 
     3169    assert(a.Algebraic.convertsTo!(const uint)); 
     3170    assert(a.Algebraic.get!real == 42); 
     3171    assert(a.Algebraic.coerce!string == "42"); 
     3172 
     3173    a = -21.0L; 
     3174    assert(!a.Algebraic.empty); 
     3175    assert(!a.Algebraic.isActive!int); 
     3176    assert( a.Algebraic.isActive!real); 
     3177    assert(!a.Algebraic.isActive!string); 
     3178    assert(fails( a.Algebraic.instance!int )); 
     3179    real* r = &(a.Algebraic.instance!real()); 
     3180    assert(*r == -21.0L); 
     3181    assert(a.Algebraic.get!(const real) == -21.0L); 
     3182    assert(a.Algebraic.coerce!string == "-21"); 
     3183    assert(fails( a.Algebraic.get!int )); 
     3184 
     3185    a = 100; 
     3186    assert(a.Algebraic.dispatch( 
     3187            (int a) { assert(a == 100); }, 
     3188            (ref real b) { assert(0); }, 
     3189            (ref int a) { assert(a == 100); ++a; } 
     3190        )); 
     3191    assert(a == 101); 
     3192 
     3193    a = a.init; 
     3194    assert(a.Algebraic.empty); 
     3195    assert(fails( a.Algebraic.instance!int )); 
     3196    assert(fails( a.Algebraic.instance!real )); 
     3197    assert(fails( a.Algebraic.get!real )); 
     3198    assert(fails( a.Algebraic.coerce!string )); 
     3199} 
     3200 
     3201unittest 
     3202{ 
     3203    // implicit convertion 
     3204    Algebraic!(real, const(char)[]) a; 
     3205 
     3206    a = 42; 
     3207    assert(a.Algebraic.isActive!real); 
     3208    a = "abc"; 
     3209    assert(a.Algebraic.isActive!(const(char)[])); 
     3210} 
     3211 
     3212unittest 
     3213{ 
     3214    // foreach over input range 
     3215    Algebraic!(string, wstring) str; 
     3216 
     3217    assert(isInputRange!(typeof(str))); 
     3218    assert(isForwardRange!(typeof(str))); 
     3219    assert(isBidirectionalRange!(typeof(str))); 
     3220//  assert(isRandomAccessRange!(typeof(str)));  // @@@ forward reference 
     3221//  assert(hasLength!(typeof(str)));            // @@@ forward reference 
     3222 
     3223    str = cast(string) "a"; 
     3224    assert(str.length == 1); 
     3225    assert(str.front == 'a'); 
     3226    str.popFront; 
     3227    assert(str.empty); 
     3228 
     3229    str = cast(wstring) "bc"; 
     3230    assert(str.length == 2); 
     3231    str.popFront; 
     3232    assert(str.front == 'c'); 
     3233    assert(!str.empty); 
     3234 
     3235    size_t i; 
     3236    str = "\u3067\u3043\u30fc"; 
     3237    foreach (e; str) 
     3238        assert(e == "\u3067\u3043\u30fc"d[i++]); 
     3239    foreach_reverse (e; str) 
     3240        assert(e == "\u3067\u3043\u30fc"d[--i]); 
     3241} 
     3242 
     3243//-------------- operator overloads 
     3244 
     3245unittest 
     3246{ 
     3247    // opDispatch 
     3248    struct Tag { string op; int n; } 
     3249    struct OpEcho { 
     3250        Tag opDispatch(string op)(int n) { 
     3251            return Tag(op, n); 
     3252        } 
     3253    } 
     3254    Algebraic!(OpEcho) obj; 
     3255 
     3256    obj = OpEcho(); 
     3257    auto r = obj.foo(42); 
     3258    assert(eq( r, Tag("foo", 42) )); 
     3259} 
     3260 
     3261unittest 
     3262{ 
     3263    // opDispatch (common type) 
     3264    struct K { 
     3265        @property  int value() { return 441; } 
     3266    } 
     3267    struct L { 
     3268        @property real value() { return 4.5; } 
     3269    } 
     3270    Algebraic!(K, L) obj; 
     3271 
     3272    obj = K(); assert(obj.value == 441); 
     3273    obj = L(); assert(obj.value == 4.5); 
     3274 
     3275    assert(!__traits(compiles, &(obj.value()) )); 
     3276//  assert(is( typeof(obj.value()) == real ));  // @@@ forward reference 
     3277    auto r = obj.value; 
     3278    assert(is( typeof(r) == real )); 
     3279} 
     3280 
     3281unittest 
     3282{ 
     3283    // opDispatch (ref argument & ref return) 
     3284    struct K { 
     3285        ref int foo(ref int a, ref int b) { ++b; return a; } 
     3286    } 
     3287    struct L { 
     3288        ref int foo(   long a, ref int b) {      return b; } 
     3289    } 
     3290    Algebraic!(K, L) q; 
     3291    int v, w; 
     3292 
     3293    q = K(); 
     3294    assert(&(q.foo(v, w)) == &v); 
     3295    assert(w == 1); 
     3296 
     3297    q = L(); 
     3298    assert(&(q.foo(v, w)) == &w); 
     3299} 
     3300 
     3301unittest 
     3302{ 
     3303    // opDispatch (empty / undefined) 
     3304    Algebraic!(int, real) obj; 
     3305 
     3306    assert(fails( obj.max )); 
     3307    obj = 42; 
     3308    assert(fails( obj.nan )); 
     3309} 
     3310 
     3311unittest 
     3312{ 
     3313    // opAssign 
     3314    struct Tag { string op; int n; } 
     3315    struct OpEcho { 
     3316        int n; 
     3317        void opAssign(int n) { 
     3318            this.n = n; 
     3319        } 
     3320    } 
     3321    Algebraic!(OpEcho) obj; 
     3322 
     3323    obj = OpEcho(); 
     3324    obj = 42; 
     3325    assert(obj.n == 42); 
     3326} 
     3327 
     3328unittest 
     3329{ 
     3330    // opAssign (intersection) 
     3331    Algebraic!(   int, real) a; 
     3332    Algebraic!(string, real) b; 
     3333 
     3334    a = 4; 
     3335    assert(a.Algebraic.isActive!int); 
     3336    b = a; 
     3337    assert(b.Algebraic.isActive!real); 
     3338    a = b; 
     3339    assert(a.Algebraic.isActive!real); 
     3340    b = "0"; 
     3341    assert(b.Algebraic.isActive!string); 
     3342 
     3343    // incompatible: string 
     3344    assert(fails( a = b )); 
     3345} 
     3346 
     3347unittest 
     3348{ 
     3349    // opUnary 
     3350    struct Tag { string op; } 
     3351    struct OpEcho { 
     3352        Tag opUnary(string op)() { 
     3353            return Tag(op); 
     3354        } 
     3355    } 
     3356    Algebraic!(OpEcho) obj; 
     3357 
     3358    obj = OpEcho(); 
     3359    foreach (op; TypeTuple!("+", "-", "~", "*", "++", "--")) 
     3360    { 
     3361        auto r = mixin(op ~ "obj"); 
     3362        assert(r.Algebraic.isActive!Tag); 
     3363        assert(eq( r.Algebraic.instance!Tag, Tag(op) )); 
     3364    } 
     3365} 
     3366 
     3367unittest 
     3368{ 
     3369    // opUnary (empty, undefined) 
     3370    Algebraic!(int, string) p; 
     3371 
     3372    assert(fails( ~p )); 
     3373    p = "D"; 
     3374    assert(fails( +p )); 
     3375} 
     3376 
     3377unittest 
     3378{ 
     3379    // opIndexUnary 
     3380    struct Tag { string op; int x; real y; } 
     3381    struct OpEcho { 
     3382        Tag opIndexUnary(string op)(int x, real y) { 
     3383            return Tag(op, x, y); 
     3384        } 
     3385    } 
     3386    Algebraic!(OpEcho) obj; 
     3387 
     3388    obj = OpEcho(); 
     3389    foreach (op; TypeTuple!("+", "-", "~", "*", "++", "--")) 
     3390    { 
     3391        auto r = mixin(op ~ "obj[4, 2.5]"); 
     3392        assert(r.Algebraic.isActive!Tag); 
     3393        assert(eq( r.Algebraic.instance!Tag, Tag(op, 4, 2.5) )); 
     3394    } 
     3395} 
     3396 
     3397unittest 
     3398{ 
     3399    // opIndexUnary (empty, undefined) 
     3400    Algebraic!(int[], int) obj; 
     3401 
     3402    assert(fails( ++obj[0] )); 
     3403    obj = 42; 
     3404    assert(fails( --obj[4] )); 
     3405} 
     3406 
     3407unittest 
     3408{ 
     3409    // opSliceUnary 
     3410    struct Tag { string op; int x; real y; } 
     3411    struct OpEcho { 
     3412        Tag opSliceUnary(string op, int k = 2)(int x, real y) { 
     3413            return Tag(op, x, y); 
     3414        } 
     3415        Tag opSliceUnary(string op, int k = 0)() { 
     3416            return Tag(op, -1, -1); 
     3417        } 
     3418    } 
     3419    Algebraic!(OpEcho) obj; 
     3420 
     3421    obj = OpEcho(); 
     3422    foreach (op; TypeTuple!("+", "-", "~", "*", "++", "--")) 
     3423    { 
     3424        auto r = mixin(op ~ "obj[4 .. 5.5]"); 
     3425        assert(r.Algebraic.isActive!Tag); 
     3426        assert(eq( r.Algebraic.instance!Tag, Tag(op, 4, 5.5) )); 
     3427 
     3428        auto s = mixin(op ~ "obj[]"); 
     3429        assert(r.Algebraic.isActive!Tag); 
     3430        assert(eq( s.Algebraic.instance!Tag, Tag(op, -1, -1) )); 
     3431    } 
     3432} 
     3433 
     3434unittest 
     3435{ 
     3436    // opSliceUnary (empty, undefined) 
     3437    Algebraic!(int[], int) obj; 
     3438 
     3439    assert(fails( ++obj[0 .. 1] )); 
     3440    assert(fails( --obj[] )); 
     3441    obj = 42; 
     3442    assert(fails( ++obj[0 .. 1] )); 
     3443    assert(fails( --obj[] )); 
     3444} 
     3445 
     3446unittest 
     3447{ 
     3448    // opCast 
     3449    struct OpEcho { 
     3450        T opCast(T)() { return T.init; } 
     3451    } 
     3452    Algebraic!(OpEcho) obj; 
     3453 
     3454    obj = OpEcho(); 
     3455    foreach (T; TypeTuple!(int, string, OpEcho, Object, real)) 
     3456    { 
     3457        T r = cast(T) obj; 
     3458    } 
     3459} 
     3460 
     3461unittest 
     3462{ 
     3463    // opCast (empty, undefined) 
     3464    Algebraic!(int, string) obj; 
     3465 
     3466    assert(fails( cast(int) obj )); 
     3467    assert(fails( cast(string) obj )); 
     3468    obj = 42; 
     3469    assert(fails( cast(string) obj )); 
     3470    obj = "abc"; 
     3471    assert(fails( cast(int) obj )); 
     3472} 
     3473 
     3474unittest 
     3475{ 
     3476    // opBinary, opBinaryRight 
     3477    struct LTag { string op; int v; } 
     3478    struct RTag { string op; int v; } 
     3479    struct OpEcho { 
     3480        LTag opBinary(string op)(int v) { 
     3481            return LTag(op, v); 
     3482        } 
     3483        RTag opBinaryRight(string op)(int v) { 
     3484            return RTag(op, v); 
     3485        } 
     3486    } 
     3487    Algebraic!(OpEcho) obj; 
     3488 
     3489    obj = OpEcho(); 
     3490    foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
     3491                "|", "^", "<<", ">>", ">>>", "~", "in")) 
     3492    { 
     3493        auto r = mixin("obj " ~ op ~ " 42"); 
     3494        assert(r.Algebraic.isActive!LTag); 
     3495        assert(eq( r.Algebraic.instance!LTag, LTag(op, 42) )); 
     3496 
     3497        auto s = mixin("76 " ~ op ~ " obj"); 
     3498        assert(s.Algebraic.isActive!RTag); 
     3499        assert(eq( s.Algebraic.instance!RTag, RTag(op, 76) )); 
     3500    } 
     3501} 
     3502 
     3503unittest 
     3504{ 
     3505    // opBinary, opBinaryRight (empty, undefined) 
     3506    Algebraic!(int, real) obj; 
     3507 
     3508    assert(fails( obj + 4 )); 
     3509    assert(fails( 4 + obj )); 
     3510    obj = 4.5; 
     3511    assert(fails( obj >> 4 )); 
     3512    assert(fails( 4 >> obj )); 
     3513} 
     3514 
     3515unittest 
     3516{ 
     3517    // opEquals (forward) 
     3518    struct Dummy { 
     3519        bool opEquals(int v) const { 
     3520            return v > 0; 
     3521        } 
     3522        bool opEquals(ref const Dummy) const { assert(0); } 
     3523    } 
     3524    Algebraic!(Dummy) obj; 
     3525 
     3526    obj = Dummy(); 
     3527    assert(obj ==  1); 
     3528    assert(obj !=  0); 
     3529    assert(obj != -1); 
     3530} 
     3531 
     3532unittest 
     3533{ 
     3534    // opEquals (meta) 
     3535    struct Dummy(int k) { 
     3536        bool opEquals(int kk)(ref const Dummy!kk rhs) const { 
     3537            return k == kk; 
     3538        } 
     3539    } 
     3540    Algebraic!(Dummy!0, Dummy!1) a, b; 
     3541 
     3542    a = Dummy!0(); 
     3543    b = Dummy!1(); 
     3544    assert(a == a); 
     3545    assert(a != b); 
     3546    assert(b == b); 
     3547} 
     3548 
     3549unittest 
     3550{ 
     3551    // opCmp (forward) 
     3552    struct Dummy { 
     3553        int opCmp(int v) const { 
     3554            return 0 - v; 
     3555        } 
     3556        int opCmp(ref const Dummy) const { assert(0); } 
     3557    } 
     3558    Algebraic!(Dummy) a; 
     3559 
     3560    a = Dummy(); 
     3561    assert(a >= 0); 
     3562    assert(a > -1); 
     3563    assert(a < 1); 
     3564} 
     3565 
     3566unittest 
     3567{ 
     3568    // opCmp (meta) 
     3569    struct Dummy(int k) { 
     3570        int opCmp(int kk)(ref const Dummy!kk r) const { 
     3571            return k - kk; 
     3572        } 
     3573    } 
     3574    Algebraic!(Dummy!0, Dummy!1) a, b; 
     3575 
     3576    a = Dummy!0(); 
     3577    b = Dummy!1(); 
     3578    assert(a >= a); 
     3579    assert(a <= b); 
     3580    assert(a < b); 
     3581    assert(b >= a); 
     3582    assert(b <= b); 
     3583    assert(b > a); 
     3584} 
     3585 
     3586unittest 
     3587{ 
     3588    // opCmp (empty, undefined) 
     3589    Algebraic!(int, string) obj; 
     3590 
     3591    assert(fails( /+obj < 0+/ obj.opCmp(0) )); 
     3592    obj = "abc"; 
     3593    assert(fails( /+obj > 0+/ obj.opCmp(1) )); 
     3594} 
     3595 
     3596/+ 
     3597// @@@BUG4253@@@ 
     3598unittest 
     3599{ 
     3600    // opCall 
     3601    struct Tag { int x; real y; } 
     3602    struct OpEcho { 
     3603        Tag opCall(int x, real y) { 
     3604            return Tag(x, y); 
     3605        } 
     3606    } 
     3607    Algebraic!(OpEcho) obj; 
     3608 
     3609//  obj = OpEcho(); // @@@BUG@@@ 
     3610    obj = OpEcho.init; 
     3611    auto r = obj(4, 8.5); 
     3612    assert(r.Algebraic.isActive!Tag); 
     3613    assert(r.Algebraic.instance!Tag == Tag(4, 8.5)); 
     3614} 
     3615+/ 
     3616 
     3617unittest 
     3618{ 
     3619    // opIndexAssign 
     3620    struct Tag { string v; int i; real j; } 
     3621    struct OpEcho { 
     3622        Tag opIndexAssign(string v, int i, real j) { 
     3623            return Tag(v, i, j); 
     3624        } 
     3625    } 
     3626    Algebraic!(OpEcho) obj; 
     3627 
     3628    obj = OpEcho(); 
     3629    auto r = (obj[1, 2.5] = "abc"); 
     3630    assert(r.Algebraic.isActive!Tag); 
     3631    assert(eq( r.Algebraic.instance!Tag, Tag("abc", 1, 2.5) )); 
     3632} 
     3633 
     3634unittest 
     3635{ 
     3636    // opIndexAssign (empty, undefined) 
     3637    Algebraic!(int, int[]) obj; 
     3638 
     3639    assert(fails( obj[0] = 4 )); 
     3640    obj = 42; 
     3641    assert(fails( obj[4] = 0 )); 
     3642} 
     3643 
     3644unittest 
     3645{ 
     3646    // opSliceAssign 
     3647    struct Tag { string v; int i; real j; } 
     3648    struct OpEcho { 
     3649        Tag opSliceAssign(string v, int i, real j) { 
     3650            return Tag(v, i, j); 
     3651        } 
     3652    } 
     3653    Algebraic!(OpEcho) obj; 
     3654 
     3655    obj = OpEcho(); 
     3656    auto r = (obj[1 .. 2.5] = "abc"); 
     3657    assert(r.Algebraic.isActive!Tag); 
     3658    assert(eq( r.Algebraic.instance!Tag, Tag("abc", 1, 2.5) )); 
     3659} 
     3660 
     3661unittest 
     3662{ 
     3663    // opSliceAssign (empty, undefined) 
     3664    Algebraic!(int, int[]) obj; 
     3665 
     3666    assert(fails( obj[0 .. 1] = 2 )); 
     3667    obj = 42; 
     3668    assert(fails( obj[1 .. 2] = 3 )); 
     3669} 
     3670 
     3671unittest 
     3672{ 
     3673    // opOpAssign 
     3674    struct Tag { string op; int v; } 
     3675    struct OpEcho { 
     3676        Tag opOpAssign(string op)(int v) { 
     3677            return Tag(op, v); 
     3678        } 
     3679    } 
     3680    Algebraic!(OpEcho) obj; 
     3681 
     3682    obj = OpEcho(); 
     3683    foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
     3684                "|", "^", "<<", ">>", ">>>", "~")) 
     3685    { 
     3686        auto r = mixin("obj " ~ op ~ "= 97"); 
     3687        assert(r.Algebraic.isActive!Tag); 
     3688        assert(eq( r.Algebraic.instance!Tag, Tag(op, 97) )); 
     3689    } 
     3690} 
     3691 
     3692unittest 
     3693{ 
     3694    // opOpAssign (empty, undefined) 
     3695    Algebraic!(int, string) obj; 
     3696 
     3697//  assert(fails( obj *= 4 ));  // exception uncaught. why? 
     3698    obj = "abc"; 
     3699    assert(fails( obj /= 4 )); 
     3700} 
     3701 
     3702unittest 
     3703{ 
     3704    // opIndexOpAssign 
     3705    struct Tag { string op; int v; int x; real y; } 
     3706    struct OpEcho { 
     3707        Tag opIndexOpAssign(string op)(int v, int x, real y) { 
     3708            return Tag(op, v, x, y); 
     3709        } 
     3710    } 
     3711    Algebraic!(OpEcho) obj; 
     3712 
     3713    obj = OpEcho(); 
     3714    foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
     3715                "|", "^", "<<", ">>", ">>>", "~")) 
     3716    { 
     3717        auto r = mixin("obj[4, 7.5] " ~ op ~ "= 42"); 
     3718        assert(r.Algebraic.isActive!Tag); 
     3719        assert(eq( r.Algebraic.instance!Tag, Tag(op, 42, 4, 7.5) )); 
     3720    } 
     3721} 
     3722 
     3723unittest 
     3724{ 
     3725    // opIndexOpAssign (empty, undefined) 
     3726    Algebraic!(int, int[]) obj; 
     3727 
     3728    assert(fails( obj[0] += 4 )); 
     3729    obj = 42; 
     3730    assert(fails( obj[1] *= 4 )); 
     3731} 
     3732 
     3733unittest 
     3734{ 
     3735    // opSliceOpAssign 
     3736    struct Tag { string op; int v; int i; real j; } 
     3737    struct OpEcho { 
     3738        Tag opSliceOpAssign(string op, int k = 2)(int v, int i, real j) { 
     3739            return Tag(op, v, i, j); 
     3740        } 
     3741        Tag opSliceOpAssign(string op, int k = 0)(int v) { 
     3742            return Tag(op, v, -1, -1); 
     3743        } 
     3744    } 
     3745    Algebraic!(OpEcho) obj; 
     3746 
     3747    obj = OpEcho(); 
     3748    foreach (op; TypeTuple!("+", "-", "*", "/", "%", "^^", "&", 
     3749                "|", "^", "<<", ">>", ">>>", "~")) 
     3750    { 
     3751        auto r = mixin("obj[4 .. 7.5] " ~ op ~ "= 42"); 
     3752        assert(r.Algebraic.isActive!Tag); 
     3753        assert(eq( r.Algebraic.instance!Tag, Tag(op, 42, 4, 7.5) )); 
     3754 
     3755        auto s = mixin("obj[] " ~ op ~ "= 42"); 
     3756        assert(s.Algebraic.isActive!Tag); 
     3757        assert(eq( s.Algebraic.instance!Tag, Tag(op, 42, -1, -1) )); 
     3758    } 
     3759} 
     3760 
     3761unittest 
     3762{ 
     3763    // opSliceOpAssign (empty, undefined) 
     3764    Algebraic!(int, int[]) obj; 
     3765 
     3766    assert(fails( obj[0 .. 1] += 1 )); 
     3767    assert(fails( obj[]       -= 2 )); 
     3768    obj = 42; 
     3769    assert(fails( obj[2 .. 3] *= 3 )); 
     3770    assert(fails( obj[]       /= 4 )); 
     3771} 
     3772 
     3773unittest 
     3774{ 
     3775    // opIndex 
     3776    struct Tag { int i; real j; } 
     3777    struct OpEcho { 
     3778        Tag opIndex(int i, real j) { 
     3779            return Tag(i, j); 
     3780        } 
     3781    } 
     3782    Algebraic!(OpEcho) obj; 
     3783 
     3784    obj = OpEcho(); 
     3785    auto r = obj[4, 9.5]; 
     3786    assert(r.Algebraic.isActive!Tag); 
     3787    assert(eq( r.Algebraic.instance!Tag, Tag(4, 9.5) )); 
     3788} 
     3789 
     3790unittest 
     3791{ 
     3792    // opIndex (empty, undefined) 
     3793    Algebraic!(int, int[]) obj; 
     3794 
     3795    assert(fails( obj[0] )); 
     3796    obj = 42; 
     3797    assert(fails( obj[2] )); 
     3798} 
     3799 
     3800unittest 
     3801{ 
     3802    // opSlice 
     3803    struct Tag { int i; real j; } 
     3804    struct OpEcho { 
     3805        Tag opSlice(int i, real j) { 
     3806            return Tag(i, j); 
     3807        } 
     3808        Tag opSlice() { 
     3809            return Tag(-1, -1); 
     3810        } 
     3811    } 
     3812    Algebraic!(OpEcho) obj; 
     3813 
     3814    obj = OpEcho(); 
     3815    auto r = obj[4 .. 9.5]; 
     3816    assert(r.Algebraic.isActive!Tag); 
     3817    assert(eq( r.Algebraic.instance!Tag, Tag(4, 9.5) )); 
     3818 
     3819    auto s = obj[]; 
     3820    assert(s.Algebraic.isActive!Tag); 
     3821    assert(eq( s.Algebraic.instance!Tag, Tag(-1, -1) )); 
     3822} 
     3823 
     3824unittest 
     3825{ 
     3826    // opSlice (empty, undefined) 
     3827    Algebraic!(int, int[]) obj; 
     3828 
     3829    assert(fails( obj[0 .. 1] )); 
     3830    assert(fails( obj[] )); 
     3831    obj = 42; 
     3832    assert(fails( obj[2 .. 3] )); 
     3833    assert(fails( obj[] )); 
     3834} 
     3835 
     3836/+ 
     3837unittest 
     3838{ 
     3839    // opApply 
     3840    struct OpEcho { 
     3841        int opApply(int delegate(ref size_t, ref real) dg) 
     3842        { 
     3843            foreach (i, ref e; [ 1.L, 2.5L, 5.5L ]) 
     3844                if (auto r = dg(i, e)) 
     3845                    return r; 
     3846            return 0; 
     3847        } 
     3848    } 
     3849    Algebraic!(OpEcho) obj; 
     3850 
     3851    obj = OpEcho(); 
     3852    foreach (size_t i, ref real e; obj) 
     3853        assert(e == [ 1.L, 2.5L, 5.5L ][i]); 
     3854} 
     3855+/ 
     3856 
     3857//-------------- special functions 
     3858 
     3859unittest 
     3860{ 
     3861    // toString 
     3862    Algebraic!(int, string, Object) obj; 
     3863    obj.toString(); 
     3864 
     3865    obj = 42; 
     3866    assert(obj.toString() == "42"); 
     3867 
     3868    obj = "The quick brown..."; 
     3869    assert(obj.toString() == "The quick brown..."); 
     3870 
     3871    obj = new class { string toString() { return "mew"; } }; 
     3872    assert(obj.toString() == "mew"); 
     3873 
     3874    assert(to!string(obj) == "mew"); 
     3875} 
     3876 
     3877unittest 
     3878{ 
     3879    // toHash 
     3880    Algebraic!(string, Object) obj; 
     3881    obj.toHash(); 
     3882 
     3883    obj = "I'm in a box."; 
     3884    obj.toHash(); 
     3885 
     3886    obj = new class { hash_t toHash() { return 42; } }; 
     3887    assert(obj.toHash() == 42); 
     3888} 
     3889 
     3890//-------------- misc 
     3891 
     3892unittest 
     3893{ 
     3894    // class object 
     3895    class A { 
     3896        int foo(int a, int b) { return a + b; } 
     3897    } 
     3898    struct B { 
     3899        int foo(int a, int b) { return a * b; } 
     3900    } 
     3901    Algebraic!(A, B) ab; 
     3902 
     3903    ab = new A; 
     3904    { 
     3905        auto c = ab; 
     3906        assert(c.foo(2, 3) == 5); 
     3907    } 
     3908    assert(ab.foo(4, 5) == 9); 
     3909 
     3910    ab = B(); 
     3911    assert(ab.foo(6, 7) == 42); 
     3912} 
     3913 
     3914unittest 
     3915{ 
     3916    // associative array 
     3917    Algebraic!(int[string], real[string]) map; 
     3918 
     3919    map = (int[string]).init; 
     3920    map["abc"] = 42; 
     3921    assert(("abc" in map) != null); 
     3922    assert(map["abc"] == 42); 
     3923    map.rehash; 
     3924    assert(map.length == 1); 
     3925 
     3926    map = (real[string]).init; 
     3927    map["xyz"] = 3.5; 
     3928    assert(("xyz" in map) != null); 
     3929    assert(map["xyz"] == 3.5); 
     3930    map.rehash; 
     3931    assert(map.length == 1); 
     3932} 
     3933 
     3934/+ 
     3935// @@@BUG4449@@@ ICE 
     3936unittest 
     3937{ 
     3938    // recursive data type 
     3939    alias Algebraic!(dchar, This[]) Tree; 
     3940 
     3941    static uint depth(ref Tree tree) 
     3942    { 
     3943        uint r; 
     3944 
     3945        // pattern match against the tree node 
     3946        tree.Algebraic.dispatch( 
     3947                (dchar leaf) 
     3948                { 
     3949                    r = 1; 
     3950                }, 
     3951                (Tree[] subtrees) 
     3952                { 
     3953                    uint mx = 0; 
     3954                    foreach (sub; subtrees) 
     3955                        mx = max(mx, depth(sub)); 
     3956                    r = 1 + mx; 
     3957                } 
     3958            ) || assert(0); 
     3959        return r; 
     3960    } 
     3961 
     3962    /* 
     3963     *  1:      <root> 
     3964     *         /      \ 
     3965     *  2:   <ab>    <cde> 
     3966     *       /  \    /   \ 
     3967     *  3:  a    b  c    <de> 
     3968     *                   /  \ 
     3969     *  4:              d    e 
     3970     */ 
     3971    Tree tree = 
     3972        [ Tree([ Tree('a'), 
     3973                 Tree('b') ]), 
     3974          Tree([ Tree('c'), 
     3975                 Tree([ Tree('d'), 
     3976                        Tree('e') ]) ]) ]; 
     3977    assert(depth(tree) == 4); 
     3978} 
     3979+/ 
     3980 
     3981 
     3982//----------------------------------------------------------------------------// 
     3983 
     3984/* 
     3985 * A dummy lvalue of type T. 
     3986 */ 
     3987private template phony(T) 
     3988{ 
     3989    static extern T phony; 
     3990} 
     3991 
     3992unittest 
     3993{ 
     3994    real foo(ref string s) { return 0; } 
     3995    assert(is(typeof(++phony!int) == int)); 
     3996    assert(is(typeof(foo(phony!string)) == real)); 
     3997} 
     3998 
     3999 
     4000/* 
     4001 * A tuple of dummy lvalues of types TT. 
     4002 */ 
     4003private template phonyList(TT...) 
     4004{ 
     4005    static if (TT.length > 0) 
     4006        alias TypeTuple!(phony!(TT[0]), phonyList!(TT[1 .. $])) 
     4007                            phonyList; 
     4008    else 
     4009        alias TypeTuple!()  phonyList; 
     4010} 
     4011 
     4012unittest 
     4013{ 
     4014    int foo(Args...)(ref Args args) { return 0; } 
     4015    assert(is(typeof(foo(phonyList!(int, dchar))) == int)); 
     4016} 
     4017 
     4018 
     4019/* 
     4020 * Returns x by a value of type R, or nothing if R is void. 
     4021 * Used by Algebraic.opDispatch(). 
     4022 */ 
     4023private @system R byValue(R, T)(auto ref T x) 
     4024{ 
     4025    static if (is(R == T)) 
     4026    { 
     4027        return x; 
     4028    } 
     4029    else static if (!is(R == void)) 
     4030    { 
     4031        R r = x; 
     4032        return r; 
     4033    } 
     4034} 
     4035 
     4036private @safe R byValue(R, T = void)() 
     4037{ 
     4038    static if (!is(R == void)) 
     4039        return R.init; 
     4040} 
     4041 
     4042unittest 
     4043{ 
     4044    static R foo(R)() 
     4045    { 
     4046        return byValue!R(42); 
     4047    } 
     4048    assert(foo!int() == 42); 
     4049    assert(foo!real() == 42.L); 
     4050    assert(is(typeof(foo!void()) == void)); 
     4051 
     4052    static R bar(R)() 
     4053    { 
     4054        return byValue!R; 
     4055    } 
     4056    assert(bar!int() == int.init); 
     4057    assert(is(typeof(bar!void()) == void)); 
     4058} 
     4059 
     4060 
     4061/* 
     4062 * Compile fails if var is an rvalue. 
     4063 */ 
     4064private @safe nothrow void expectLvalue(T)(ref T var); 
     4065 
     4066unittest 
     4067{ 
     4068    int x; 
     4069    assert(__traits(compiles, expectLvalue(x))); 
     4070    assert(!__traits(compiles, expectLvalue(42))); 
     4071} 
     4072 
     4073 
     4074/* 
     4075 * Initializes a variable $(D obj) with its default initializer without 
     4076 * invoking copy constructor nor destructor. 
     4077 */ 
     4078private @trusted void initialize(T)(ref T obj) 
     4079{ 
     4080    static T init; 
     4081    memcpy(&obj, &init, T.sizeof); 
     4082} 
     4083 
     4084unittest 
     4085{ 
     4086    struct S 
     4087    { 
     4088        int n; 
     4089        this(this) { assert(0); } 
     4090    } 
     4091    S s; 
     4092    s.n = 42; 
     4093    assert(s != s.init); 
     4094    initialize(s); 
     4095    assert(s == s.init); 
     4096} 
     4097 
     4098 
     4099/* 
     4100 * Workaround for the issue 4444. 
     4101 */ 
     4102private @trusted string expandArray(string array, size_t n) 
     4103{ 
     4104    string expr = ""; 
     4105 
     4106    foreach (i; 0 .. n) 
     4107    { 
     4108        if (i > 0) 
     4109            expr ~= ", "; 
     4110        expr ~= array ~ "[" ~ to!string(i) ~ "]"; 
     4111    } 
     4112    return expr; 
     4113} 
     4114 
     4115unittest 
     4116{ 
     4117    enum s = expandArray("arr", 3); 
     4118    assert(s == "arr[0], arr[1], arr[2]"); 
     4119} 
     4120