Skip to content

Commit

Permalink
Merge pull request #1410 from monarchdodra/AppenderCapacity
Browse files Browse the repository at this point in the history
Appender.reserve: Overzealous and wrong
  • Loading branch information
AndrejMitrovic committed Oct 24, 2013
2 parents 779eedc + cc669ef commit 693ccb1
Showing 1 changed file with 25 additions and 14 deletions.
39 changes: 25 additions & 14 deletions std/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -2132,9 +2132,15 @@ struct Appender(A : T[], T)
*/
void reserve(size_t newCapacity) @safe pure nothrow
{
immutable cap = _data ? _data.capacity : 0;
if (newCapacity > cap)
ensureAddable(newCapacity - cap);
if (_data)
{
if (newCapacity > _data.capacity)
ensureAddable(newCapacity - _data.arr.length);
}
else
{
ensureAddable(newCapacity);
}
}

/**
Expand All @@ -2161,16 +2167,6 @@ struct Appender(A : T[], T)
// ensure we can add nelems elements, resizing as necessary
private void ensureAddable(size_t nelems) @safe pure nothrow
{
static size_t newCapacity(size_t newlength) @safe pure nothrow
{
long mult = 100 + (1000L) / (bsr(newlength * T.sizeof) + 1);
// limit to doubling the length, we don't want to grow too much
if(mult > 200)
mult = 200;
auto newext = cast(size_t)((newlength * mult + 99) / 100);
return newext > newlength ? newext : newlength;
}

if (!_data)
_data = new Data;
immutable len = _data.arr.length;
Expand Down Expand Up @@ -2201,7 +2197,7 @@ struct Appender(A : T[], T)
// Time to reallocate.
// We need to almost duplicate what's in druntime, except we
// have better access to the capacity field.
auto newlen = newCapacity(reqlen);
auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen);
// first, try extending the current block
auto u = ()@trusted{ return
GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof);
Expand Down Expand Up @@ -2396,6 +2392,21 @@ struct Appender(A : T[], T)
}
}

//Calculates an efficient growth scheme based on the old capacity
//of data, and the minimum requested capacity.
//arg curLen: The current length
//arg reqLen: The length as requested by the user
//ret sugLen: A suggested growth.
private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen) @safe pure nothrow
{
ulong mult = 100 + (1000UL) / (bsr(curLen * TSizeOf) + 1);
// limit to doubling the length, we don't want to grow too much
if(mult > 200)
mult = 200;
auto sugLen = cast(size_t)((curLen * mult + 99) / 100);
return max(reqLen, sugLen);
}

/**
* An appender that can update an array in-place. It forwards all calls to an
* underlying appender implementation. Any calls made to the appender also update
Expand Down

0 comments on commit 693ccb1

Please sign in to comment.