@@ -2285,14 +2285,30 @@ struct Appender(A : T[], T)
22852285 {
22862286 ensureAddable(1 );
22872287 immutable len = _data.arr.length;
2288- // _data.arr.ptr[len] = cast(Unqual!T)item; // assign? emplace?
2289- // _data.arr = _data.arr.ptr[0 .. len + 1];
2290-
2291- // Cannot return ref because it doesn't work in CTFE
2292- ()@trusted { return _data.arr.ptr[len .. len + 1 ]; }()[0 ]
2293- = // assign? emplace?
2294- ()@trusted { return cast (Unqual! T)item; } ();
2295- ()@trusted { _data.arr = _data.arr.ptr[0 .. len + 1 ]; }();
2288+
2289+ auto bigDataFun () @trusted nothrow { return _data.arr.ptr[0 .. len + 1 ];}
2290+ auto bigData = bigDataFun();
2291+
2292+ static if (is (Unqual! T == T))
2293+ alias uitem = item;
2294+ else
2295+ auto ref uitem () @trusted nothrow @property { return cast (Unqual! T)item;}
2296+
2297+ // The idea is to only call emplace if we must.
2298+ static if ( is (typeof (bigData[0 ].opAssign(uitem))) ||
2299+ ! is (typeof (bigData[0 ] = uitem)))
2300+ {
2301+ // pragma(msg, T.stringof); pragma(msg, U.stringof);
2302+ emplace(&bigData[len], uitem);
2303+ }
2304+ else
2305+ {
2306+ // pragma(msg, T.stringof); pragma(msg, U.stringof);
2307+ bigData[len] = uitem;
2308+ }
2309+
2310+ // We do this at the end, in case of exceptions
2311+ _data.arr = bigData;
22962312 }
22972313 }
22982314
@@ -2330,23 +2346,42 @@ struct Appender(A : T[], T)
23302346 ensureAddable(items.length);
23312347 immutable len = _data.arr.length;
23322348 immutable newlen = len + items.length;
2333- _data.arr = ()@trusted { return _data.arr.ptr[0 .. newlen]; }();
2334- static if (is (typeof (_data.arr[] = items[])))
2349+
2350+ auto bigDataFun () @trusted nothrow { return _data.arr.ptr[0 .. newlen];}
2351+ auto bigData = bigDataFun();
2352+
2353+ enum mustEmplace = is (typeof (bigData[0 ].opAssign(cast (Unqual! T)items.front))) ||
2354+ ! is (typeof (bigData[0 ] = cast (Unqual! T)items.front));
2355+
2356+ static if (is (typeof (_data.arr[] = items[])) && ! mustEmplace)
2357+ {
2358+ // pragma(msg, T.stringof); pragma(msg, Range.stringof);
2359+ bigData[len .. newlen] = items[];
2360+ }
2361+ else static if (is (Unqual! T == ElementType! Range ))
23352362 {
2336- ()@trusted { return _data.arr.ptr[len .. newlen]; }()[] = items[];
2363+ foreach (ref it ; bigData[len .. newlen])
2364+ {
2365+ static if (mustEmplace)
2366+ emplace(&it, items.front);
2367+ else
2368+ it = items.front;
2369+ }
23372370 }
23382371 else
23392372 {
2340- for (size_t i = len; ! items.empty; items.popFront(), ++ i)
2373+ static auto ref getUItem (U)(U item) @trusted {return cast (Unqual! T)item;}
2374+ foreach (ref it ; bigData[len .. newlen])
23412375 {
2342- // _data.arr.ptr[i] = cast(Unqual!T)items.front;
2343-
2344- // Cannot return ref because it doesn't work in CTFE
2345- ()@trusted { return _data.arr.ptr[i .. i + 1 ]; }()[0 ]
2346- = // assign? emplace?
2347- ()@trusted { return cast (Unqual! T)items.front; }();
2376+ static if (mustEmplace)
2377+ emplace(&it, getUItem (items.front));
2378+ else
2379+ it = getUItem(items.front);
23482380 }
23492381 }
2382+
2383+ // We do this at the end, in case of exceptions
2384+ _data.arr = bigData;
23502385 }
23512386 else
23522387 {
@@ -2690,6 +2725,96 @@ Appender!(E[]) appender(A : E[], E)(A array)
26902725 }
26912726}
26922727
2728+ unittest
2729+ {
2730+ // 10690
2731+ [tuple(1 )].filter! (t => true ).array; // No error
2732+ [tuple(" A" )].filter! (t => true ).array; // error
2733+ }
2734+
2735+ unittest
2736+ {
2737+ // Coverage for put(Range)
2738+ struct S1
2739+ {
2740+ }
2741+ struct S2
2742+ {
2743+ void opAssign (S2 ){}
2744+ }
2745+ auto a1 = Appender! (S1 [])();
2746+ auto a2 = Appender! (S2 [])();
2747+ auto au1 = Appender! (const (S1 )[])();
2748+ auto au2 = Appender! (const (S2 )[])();
2749+ a1.put(S1 ().repeat().take(10 ));
2750+ a2.put(S2 ().repeat().take(10 ));
2751+ auto sc1 = const (S1 )();
2752+ auto sc2 = const (S2 )();
2753+ au1.put(sc1.repeat().take(10 ));
2754+ au2.put(sc2.repeat().take(10 ));
2755+ }
2756+
2757+ unittest
2758+ {
2759+ struct S
2760+ {
2761+ int * p;
2762+ }
2763+
2764+ auto a0 = Appender! (S[])();
2765+ auto a1 = Appender! (const (S)[])();
2766+ auto a2 = Appender! (immutable (S)[])();
2767+ auto s0 = S(null );
2768+ auto s1 = const (S)(null );
2769+ auto s2 = immutable (S)(null );
2770+ a1.put(s0);
2771+ a1.put(s1);
2772+ a1.put(s2);
2773+ a1.put([s0]);
2774+ a1.put([s1]);
2775+ a1.put([s2]);
2776+ a0.put(s0);
2777+ static assert (! is (typeof (a0.put(a1))));
2778+ static assert (! is (typeof (a0.put(a2))));
2779+ a0.put([s0]);
2780+ static assert (! is (typeof (a0.put([a1]))));
2781+ static assert (! is (typeof (a0.put([a2]))));
2782+ static assert (! is (typeof (a2.put(a0))));
2783+ static assert (! is (typeof (a2.put(a1))));
2784+ a2.put(s2);
2785+ static assert (! is (typeof (a2.put([a0]))));
2786+ static assert (! is (typeof (a2.put([a1]))));
2787+ a2.put([s2]);
2788+ }
2789+
2790+ unittest
2791+ { // 9528
2792+ const (E)[] fastCopy (E)(E[] src) {
2793+ auto app = appender! (const (E)[])();
2794+ foreach (i, e; src)
2795+ app.put(e);
2796+ return app.data;
2797+ }
2798+
2799+ class C {}
2800+ struct S { const (C) c; }
2801+ S[] s = [ S(new C) ];
2802+
2803+ auto t = fastCopy(s); // Does not compile
2804+ }
2805+
2806+ unittest
2807+ { // 10753
2808+ struct Foo {
2809+ immutable dchar d;
2810+ }
2811+ struct Bar {
2812+ immutable int x;
2813+ }
2814+ " 12" .map! Foo .array;
2815+ [1 , 2 ].map! Bar .array;
2816+ }
2817+
26932818/+ +
26942819 Convenience function that returns a $(D RefAppender!A) object initialized
26952820 with $(D array). Don't use null for the $(D array) pointer, use the other
0 commit comments