From e3fe89ca0fe88e7cd45beb9f22385873eb9a0ddc Mon Sep 17 00:00:00 2001 From: monarchdodra Date: Mon, 11 Nov 2013 15:34:59 +0100 Subject: [PATCH] Use "autoEmplace" for performance --- std/algorithm.d | 6 +++--- std/array.d | 16 ++++++---------- std/conv.d | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ std/functional.d | 2 +- std/typecons.d | 2 +- 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/std/algorithm.d b/std/algorithm.d index bb1417af569..4ed9d520fac 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -794,7 +794,7 @@ template reduce(fun...) if (fun.length >= 1) result = void; foreach (i, T; result.Types) { - emplace(&result[i], seed); + autoEmplace(result[i], seed); } r.popFront(); return reduce(result, r); @@ -856,7 +856,7 @@ template reduce(fun...) if (fun.length >= 1) foreach (i, T; result.Types) { - emplace(&result[i], elem); + autoEmplace(result[i], elem); } } } @@ -1186,7 +1186,7 @@ void uninitializedFill(Range, Value)(Range range, Value filler) { // Must construct stuff by the book for (; !range.empty; range.popFront()) - emplace(addressOf(range.front), filler); + autoEmplace(range.front, filler); } else // Doesn't matter whether fill is initialized or not diff --git a/std/array.d b/std/array.d index f97ad078bef..ea8d5a56d80 100644 --- a/std/array.d +++ b/std/array.d @@ -30,22 +30,19 @@ if (isIterable!Range && !isNarrowString!Range && !isInfinite!Range) alias ForeachType!Range E; static if (hasLength!Range) { - if(r.length == 0) return null; + immutable len = r.length; + if(len == 0) return null; static auto trustedAllocateArray(size_t n) @trusted nothrow { return uninitializedArray!(Unqual!E[])(n); } - auto result = trustedAllocateArray(r.length); + auto result = trustedAllocateArray(len); size_t i; - static auto trustedGetAddr(T)(ref T t) @trusted nothrow pure - { - return &t; - } foreach (e; r) { - emplace(trustedGetAddr(result[i]), e); + autoEmplace(result[i], e); ++i; } return cast(E[])result; @@ -913,17 +910,16 @@ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff) } array.length += to_insert; copyBackwards(array[pos..oldLen], array[pos+to_insert..$]); - auto ptr = array.ptr + pos; foreach (i, E; U) { static if (is(E : T)) //ditto { - emplace(ptr++, stuff[i]); + autoEmplace(array[pos++], stuff[i]); } else { foreach (v; stuff[i]) - emplace(ptr++, v); + autoEmplace(array[pos++], v); } } } diff --git a/std/conv.d b/std/conv.d index 8bf39952a7f..7b355d5bed7 100644 --- a/std/conv.d +++ b/std/conv.d @@ -4833,6 +4833,55 @@ unittest assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345])); } +/+ +package helper: This function is functionally equivalent to the normal +emplace. However, it only calls the actual emplace if really necessary. +It's dedicated to improving both code readability and performance. +This function is mostly a workaround for DMD's bad inliner. + +Doing it as a dedicated function helps reduce error-prone boilerplate +code in caller function. Indeed: While the normal emplace will still +correctly call '=' when needed, it takes an argument by pointer. DMD +seems to have a lot of trouble making the inline assignment when there +is an un-necessary indirection. + +eg: +---- +int i; +emplace(&i, 5); +vs +autoEmplace(i, 5); +---- + +Using $(D emplace) over raw assignement or $(D autoEmplace) for trivial +types in a tight loop $(I can) result in a $(I catastrophic) performance +penalty. ++/ +package void autoEmplace(T, Args...)(ref T chunk, auto ref Args args) +{ + static if (Args.length == 0 && isAssignable!(T) && !hasElaborateAssign!T) + chunk = T.init; + else static if (Args.length == 1 && isAssignable!(T, Args[0]) && !hasElaborateAssign!T) + chunk = args[0]; + else + emplace(&chunk, args); +} + +unittest +{ + int i; + autoEmplace(i); + autoEmplace(i, 5); + + static struct S + { + void opAssign(S); + } + S s; + autoEmplace(s); + autoEmplace(s, S.init); +} + // Undocumented for the time being void toTextRange(T, W)(T value, W writer) if (isIntegral!T && isOutputRange!(W, char)) diff --git a/std/functional.d b/std/functional.d index d336b8c0908..6f9c3b656d7 100644 --- a/std/functional.d +++ b/std/functional.d @@ -368,7 +368,7 @@ template adjoin(F...) if (F.length) Tuple!(Head, typeof(.adjoin!(F[1..$])(a)).Types) result = void; foreach (i, Unused; result.Types) { - emplace(&result[i], F[i](a)); + autoEmplace(result[i], F[i](a)); } return result; } diff --git a/std/typecons.d b/std/typecons.d index 962b4ebb2d9..ce0782ff59d 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3522,7 +3522,7 @@ if (!is(T == class)) _store = cast(Impl*) enforce(malloc(Impl.sizeof)); static if (hasIndirections!T) GC.addRange(&_store._payload, T.sizeof); - emplace(&_store._payload, args); + autoEmplace(_store._payload, args); _store._count = 1; }