Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 44 additions & 74 deletions std/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}

/**
Expand All @@ -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
Expand All @@ -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;
}

/**
Expand All @@ -2181,62 +2184,62 @@ 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
private void ensureAddable(size_t nelems) @safe pure nothrow
{
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
if (__ctfe)
{
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
}
}
Expand Down Expand Up @@ -2279,31 +2282,15 @@ struct Appender(A : T[], T)
else
{
ensureAddable(1);
immutable len = _data.arr.length;
immutable len = _data.length;

auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. len + 1];}
auto bigData = bigDataFun();

static if (is(Unqual!T == T))
alias uitem = item;
static if (is(U : Unqual!T))
emplace(&_data.arr[len], 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);
}
else
{
//pragma(msg, T.stringof); pragma(msg, U.stringof);
bigData[len] = uitem;
}
emplace(&_data.arr[len], cast(Unqual!T)item);

//We do this at the end, in case of exceptions
_data.arr = bigData;
++_data.length;
}
}

Expand All @@ -2323,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
Expand All @@ -2338,47 +2325,30 @@ 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;

auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. newlen];}
auto bigData = bigDataFun();
immutable itemslen = items.length;
ensureAddable(itemslen);

enum mustEmplace = is(typeof(bigData[0].opAssign(cast(Unqual!T)items.front))) ||
!is(typeof(bigData[0] = cast(Unqual!T)items.front));
immutable len = _data.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();
}
_data.arr[len .. newlen] = items[];
}
else
{
static auto ref getUItem(U)(U item) @trusted {return cast(Unqual!T)item;}
foreach (ref it ; bigData[len .. newlen])
foreach (size_t i ; len .. newlen)
{
static if (mustEmplace)
emplace(&it, getUItem(items.front));
static if (is(U : Unqual!T))
emplace(&_data.arr[i], items.front);
else
it = getUItem(items.front);
emplace(&_data.arr[i], cast(Unqual!T)items.front);
items.popFront();
}
}

//We do this at the end, in case of exceptions
_data.arr = bigData;
_data.length = newlen;
}
else
{
Expand Down Expand Up @@ -2427,7 +2397,7 @@ struct Appender(A : T[], T)
{
if (_data)
{
_data.arr = ()@trusted{ return _data.arr.ptr[0 .. 0]; }();
_data.length = 0;
}
}

Expand All @@ -2440,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);
Expand Down