Skip to content

Commit f9712aa

Browse files
committed
Merge pull request #1529 from monarchdodra/appenderEmplace
Fix appender form elaborate assign types
2 parents 3fd3cee + 8a50b18 commit f9712aa

1 file changed

Lines changed: 143 additions & 18 deletions

File tree

std/array.d

Lines changed: 143 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)