From 67a319902a6293c24f923c84139ff2e9e55e4059 Mon Sep 17 00:00:00 2001 From: monarchdodra Date: Fri, 8 Nov 2013 20:26:54 +0100 Subject: [PATCH 1/2] cleanup emplace code in Appender --- std/array.d | 69 ++++++++++++++++------------------------------------- 1 file changed, 20 insertions(+), 49 deletions(-) diff --git a/std/array.d b/std/array.d index f97ad078bef..ed03bfb7650 100644 --- a/std/array.d +++ b/std/array.d @@ -2281,29 +2281,15 @@ struct Appender(A : T[], T) ensureAddable(1); immutable len = _data.arr.length; - auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. len + 1];} - auto bigData = bigDataFun(); - - static if (is(Unqual!T == T)) - alias uitem = item; - else - auto ref uitem() @trusted nothrow @property { return cast(Unqual!T)item;} - - //The idea is to only call emplace if we must. - static if ( is(typeof(bigData[0].opAssign(uitem))) || - !is(typeof(bigData[0] = uitem))) - { - //pragma(msg, T.stringof); pragma(msg, U.stringof); - emplace(&bigData[len], uitem); - } + auto ptr() @trusted @property nothrow { return _data.arr.ptr + len; } + static if (is(U : Unqual!T)) + emplace(ptr, item); else - { - //pragma(msg, T.stringof); pragma(msg, U.stringof); - bigData[len] = uitem; - } + emplace(ptr, cast(Unqual!T)item); //We do this at the end, in case of exceptions - _data.arr = bigData; + auto trustedGrow() @trusted nothrow { _data.arr = _data.arr.ptr[0 .. len + 1];} + trustedGrow(); } } @@ -2338,47 +2324,32 @@ struct Appender(A : T[], T) } // make sure we have enough space, then add the items - ensureAddable(items.length); - immutable len = _data.arr.length; - immutable newlen = len + items.length; + immutable itemslen = items.length; + ensureAddable(itemslen); - auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. newlen];} - auto bigData = bigDataFun(); - - enum mustEmplace = is(typeof(bigData[0].opAssign(cast(Unqual!T)items.front))) || - !is(typeof(bigData[0] = cast(Unqual!T)items.front)); + immutable len = _data.arr.length; + immutable newlen = len + itemslen; - static if (is(typeof(_data.arr[] = items[])) && !mustEmplace) - { - //pragma(msg, T.stringof); pragma(msg, Range.stringof); - bigData[len .. newlen] = items[]; - } - else static if (is(Unqual!T == ElementType!Range)) + static if (is(typeof(_data.arr[] = items[])) && !hasElaborateAssign!(Unqual!T) ) { - foreach (ref it ; bigData[len .. newlen]) - { - static if (mustEmplace) - emplace(&it, items.front); - else - it = items.front; - items.popFront(); - } + auto slice() @trusted @property nothrow { return _data.arr.ptr[len .. newlen];} + slice[] = items[]; } else { - static auto ref getUItem(U)(U item) @trusted {return cast(Unqual!T)item;} - foreach (ref it ; bigData[len .. newlen]) + auto ptr(size_t i) @trusted nothrow { return _data.arr.ptr + i; } + for (size_t i = len ; i < newlen ; items.popFront(), ++i) { - static if (mustEmplace) - emplace(&it, getUItem(items.front)); + static if (is(ElementType!Range : Unqual!T)) + emplace(ptr(i), items.front); else - it = getUItem(items.front); - items.popFront(); + emplace(ptr(i), cast(Unqual!T)items.front); } } //We do this at the end, in case of exceptions - _data.arr = bigData; + auto trustedGrow() @trusted nothrow { _data.arr = _data.arr.ptr[0 .. newlen];} + trustedGrow(); } else { From 50f49a53ff34d9cef1ac4509a91e86fd4d0d571e Mon Sep 17 00:00:00 2001 From: monarchdodra Date: Sun, 10 Nov 2013 21:39:26 +0100 Subject: [PATCH 2/2] Chnage capacity/length in Appender --- std/array.d | 81 ++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/std/array.d b/std/array.d index ed03bfb7650..8ee74e18f70 100644 --- a/std/array.d +++ b/std/array.d @@ -2113,8 +2113,9 @@ struct Appender(A : T[], T) { private struct Data { - size_t capacity; + // arr is as long as its capacity. Unqual!T[] arr; + size_t length; } private Data* _data; @@ -2127,9 +2128,12 @@ struct Appender(A : T[], T) */ this(Unqual!T[] arr) @safe pure nothrow { - // initialize to a given array. + // intialize Data _data = new Data; + + // initialize to a given array. _data.arr = arr; + _data.length = arr.length; if (__ctfe) return; @@ -2142,7 +2146,6 @@ struct Appender(A : T[], T) arr = ()@trusted{ return arr.ptr[0 .. cap]; }(); // we assume no reallocation occurred assert(arr.ptr is _data.arr.ptr); - _data.capacity = arr.length; } /** @@ -2154,7 +2157,7 @@ struct Appender(A : T[], T) { if (_data) { - if (newCapacity > _data.capacity) + if (newCapacity > _data.arr.length) ensureAddable(newCapacity - _data.arr.length); } else @@ -2170,7 +2173,7 @@ struct Appender(A : T[], T) */ @property size_t capacity() const @safe pure nothrow { - return _data ? _data.capacity : 0; + return _data ? _data.arr.length : 0; } /** @@ -2181,7 +2184,7 @@ struct Appender(A : T[], T) /* @trusted operation: * casting Unqual!T[] to inout(T)[] */ - return cast(typeof(return))(_data ? _data.arr : null); + return cast(typeof(return))(_data ? _data.arr[0 .. _data.length] : null); } // ensure we can add nelems elements, resizing as necessary @@ -2189,10 +2192,12 @@ struct Appender(A : T[], T) { if (!_data) _data = new Data; - immutable len = _data.arr.length; - immutable reqlen = len + nelems; - if (()@trusted{ return _data.capacity; }() >= reqlen) + immutable len = _data.length; + immutable cap = _data.arr.length; + immutable reqcap = len + nelems; + + if (cap >= reqcap) return; // need to increase capacity @@ -2200,43 +2205,41 @@ struct Appender(A : T[], T) { static if (__traits(compiles, new Unqual!T[1])) { - _data.arr.length = reqlen; + _data.arr.length = reqcap; } else { // avoid restriction of @disable this() - ()@trusted{ _data.arr = _data.arr[0 .. _data.capacity]; }(); - foreach (i; _data.capacity .. reqlen) + foreach (i; cap .. reqcap) _data.arr ~= Unqual!T.init; } - _data.arr = _data.arr[0 .. len]; - _data.capacity = reqlen; } else { // Time to reallocate. // We need to almost duplicate what's in druntime, except we // have better access to the capacity field. - auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen); + auto newcap = appenderNewCapacity!(T.sizeof)(cap, reqcap); // first, try extending the current block auto u = ()@trusted{ return - GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof); + GC.extend(_data.arr.ptr, (reqcap - cap) * T.sizeof, (newcap - cap) * T.sizeof); }(); if (u) { - // extend worked, update the capacity - _data.capacity = u / T.sizeof; + // extend worked, update the array + ()@trusted{ _data.arr = _data.arr.ptr[0 .. u / T.sizeof]; }(); } else { // didn't work, must reallocate auto bi = ()@trusted{ return - GC.qalloc(newlen * T.sizeof, (typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN); + GC.qalloc(newcap * T.sizeof, (typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN); }(); - _data.capacity = bi.size / T.sizeof; if (len) ()@trusted{ memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }(); - _data.arr = ()@trusted{ return (cast(Unqual!T*)bi.base)[0 .. len]; }(); + ()@trusted{ + _data.arr = (cast(Unqual!T*)bi.base)[0 .. bi.size / T.sizeof]; + }(); // leave the old data, for safety reasons } } @@ -2279,17 +2282,15 @@ struct Appender(A : T[], T) else { ensureAddable(1); - immutable len = _data.arr.length; + immutable len = _data.length; - auto ptr() @trusted @property nothrow { return _data.arr.ptr + len; } static if (is(U : Unqual!T)) - emplace(ptr, item); + emplace(&_data.arr[len], item); else - emplace(ptr, cast(Unqual!T)item); + emplace(&_data.arr[len], cast(Unqual!T)item); //We do this at the end, in case of exceptions - auto trustedGrow() @trusted nothrow { _data.arr = _data.arr.ptr[0 .. len + 1];} - trustedGrow(); + ++_data.length; } } @@ -2309,7 +2310,7 @@ struct Appender(A : T[], T) // another because we can't trust the length portion. static if (!(isSomeChar!T && isSomeChar!(ElementType!Range) && !is(immutable Range == immutable T[])) && - is(typeof(items.length) == size_t)) + (hasLength!Range || isSomeString!Range)) { // optimization -- if this type is something other than a string, // and we are adding exactly one element, call the version for one @@ -2327,29 +2328,27 @@ struct Appender(A : T[], T) immutable itemslen = items.length; ensureAddable(itemslen); - immutable len = _data.arr.length; + immutable len = _data.length; immutable newlen = len + itemslen; static if (is(typeof(_data.arr[] = items[])) && !hasElaborateAssign!(Unqual!T) ) { - auto slice() @trusted @property nothrow { return _data.arr.ptr[len .. newlen];} - slice[] = items[]; + _data.arr[len .. newlen] = items[]; } else { - auto ptr(size_t i) @trusted nothrow { return _data.arr.ptr + i; } - for (size_t i = len ; i < newlen ; items.popFront(), ++i) + foreach (size_t i ; len .. newlen) { - static if (is(ElementType!Range : Unqual!T)) - emplace(ptr(i), items.front); + static if (is(U : Unqual!T)) + emplace(&_data.arr[i], items.front); else - emplace(ptr(i), cast(Unqual!T)items.front); + emplace(&_data.arr[i], cast(Unqual!T)items.front); + items.popFront(); } } //We do this at the end, in case of exceptions - auto trustedGrow() @trusted nothrow { _data.arr = _data.arr.ptr[0 .. newlen];} - trustedGrow(); + _data.length = newlen; } else { @@ -2398,7 +2397,7 @@ struct Appender(A : T[], T) { if (_data) { - _data.arr = ()@trusted{ return _data.arr.ptr[0 .. 0]; }(); + _data.length = 0; } } @@ -2411,8 +2410,8 @@ struct Appender(A : T[], T) { if (_data) { - enforce(newlength <= _data.arr.length); - _data.arr = ()@trusted{ return _data.arr.ptr[0 .. newlength]; }(); + enforce(newlength <= _data.length); + _data.length = newlength; } else enforce(newlength == 0);