mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +03:00
Removed some GC allocations from std.container.array
This commit is contained in:
parent
fd014e84d7
commit
ccff296d70
1 changed files with 61 additions and 39 deletions
|
@ -115,24 +115,24 @@ private struct RangeT(A)
|
||||||
|
|
||||||
@property ref inout(E) front() inout
|
@property ref inout(E) front() inout
|
||||||
{
|
{
|
||||||
version (assert) if (empty) throw new RangeError();
|
assert(!empty, "Attempting to access the front of an empty Array");
|
||||||
return _outer[_a];
|
return _outer[_a];
|
||||||
}
|
}
|
||||||
@property ref inout(E) back() inout
|
@property ref inout(E) back() inout
|
||||||
{
|
{
|
||||||
version (assert) if (empty) throw new RangeError();
|
assert(!empty, "Attempting to access the back of an empty Array");
|
||||||
return _outer[_b - 1];
|
return _outer[_b - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront() @safe pure nothrow
|
void popFront() @safe @nogc pure nothrow
|
||||||
{
|
{
|
||||||
version (assert) if (empty) throw new RangeError();
|
assert(!empty, "Attempting to popFront an empty Array");
|
||||||
++_a;
|
++_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack() @safe pure nothrow
|
void popBack() @safe @nogc pure nothrow
|
||||||
{
|
{
|
||||||
version (assert) if (empty) throw new RangeError();
|
assert(!empty, "Attempting to popBack an empty Array");
|
||||||
--_b;
|
--_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,26 +142,26 @@ private struct RangeT(A)
|
||||||
|
|
||||||
E moveFront()
|
E moveFront()
|
||||||
{
|
{
|
||||||
version (assert) if (empty || _a >= _outer.length) throw new RangeError();
|
assert(!empty && _a < _outer.length);
|
||||||
return move(_outer._data._payload[_a]);
|
return move(_outer._data._payload[_a]);
|
||||||
}
|
}
|
||||||
|
|
||||||
E moveBack()
|
E moveBack()
|
||||||
{
|
{
|
||||||
version (assert) if (empty || _b > _outer.length) throw new RangeError();
|
assert(!empty && _b <= _outer.length);
|
||||||
return move(_outer._data._payload[_b - 1]);
|
return move(_outer._data._payload[_b - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
E moveAt(size_t i)
|
E moveAt(size_t i)
|
||||||
{
|
{
|
||||||
version (assert) if (_a + i >= _b || _a + i >= _outer.length) throw new RangeError();
|
assert(_a + i < _b && _a + i < _outer.length);
|
||||||
return move(_outer._data._payload[_a + i]);
|
return move(_outer._data._payload[_a + i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ref inout(E) opIndex(size_t i) inout
|
ref inout(E) opIndex(size_t i) inout
|
||||||
{
|
{
|
||||||
version (assert) if (_a + i >= _b) throw new RangeError();
|
assert(_a + i < _b);
|
||||||
return _outer[_a + i];
|
return _outer[_a + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ private struct RangeT(A)
|
||||||
|
|
||||||
RangeT opSlice(size_t i, size_t j)
|
RangeT opSlice(size_t i, size_t j)
|
||||||
{
|
{
|
||||||
version (assert) if (i > j || _a + j > _b) throw new RangeError();
|
assert(i <= j && _a + j <= _b);
|
||||||
return typeof(return)(_outer, _a + i, _a + j);
|
return typeof(return)(_outer, _a + i, _a + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ private struct RangeT(A)
|
||||||
|
|
||||||
RangeT!(const(A)) opSlice(size_t i, size_t j) const
|
RangeT!(const(A)) opSlice(size_t i, size_t j) const
|
||||||
{
|
{
|
||||||
version (assert) if (i > j || _a + j > _b) throw new RangeError();
|
assert(i <= j && _a + j <= _b);
|
||||||
return typeof(return)(_outer, _a + i, _a + j);
|
return typeof(return)(_outer, _a + i, _a + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,39 +191,39 @@ private struct RangeT(A)
|
||||||
{
|
{
|
||||||
void opSliceAssign(E value)
|
void opSliceAssign(E value)
|
||||||
{
|
{
|
||||||
version (assert) if (_b > _outer.length) throw new RangeError();
|
assert(_b <= _outer.length);
|
||||||
_outer[_a .. _b] = value;
|
_outer[_a .. _b] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSliceAssign(E value, size_t i, size_t j)
|
void opSliceAssign(E value, size_t i, size_t j)
|
||||||
{
|
{
|
||||||
version (assert) if (_a + j > _b) throw new RangeError();
|
assert(_a + j <= _b);
|
||||||
_outer[_a + i .. _a + j] = value;
|
_outer[_a + i .. _a + j] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSliceUnary(string op)()
|
void opSliceUnary(string op)()
|
||||||
if (op == "++" || op == "--")
|
if (op == "++" || op == "--")
|
||||||
{
|
{
|
||||||
version (assert) if (_b > _outer.length) throw new RangeError();
|
assert(_b <= _outer.length);
|
||||||
mixin(op~"_outer[_a .. _b];");
|
mixin(op~"_outer[_a .. _b];");
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSliceUnary(string op)(size_t i, size_t j)
|
void opSliceUnary(string op)(size_t i, size_t j)
|
||||||
if (op == "++" || op == "--")
|
if (op == "++" || op == "--")
|
||||||
{
|
{
|
||||||
version (assert) if (_a + j > _b) throw new RangeError();
|
assert(_a + j <= _b);
|
||||||
mixin(op~"_outer[_a + i .. _a + j];");
|
mixin(op~"_outer[_a + i .. _a + j];");
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSliceOpAssign(string op)(E value)
|
void opSliceOpAssign(string op)(E value)
|
||||||
{
|
{
|
||||||
version (assert) if (_b > _outer.length) throw new RangeError();
|
assert(_b <= _outer.length);
|
||||||
mixin("_outer[_a .. _b] "~op~"= value;");
|
mixin("_outer[_a .. _b] "~op~"= value;");
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSliceOpAssign(string op)(E value, size_t i, size_t j)
|
void opSliceOpAssign(string op)(E value, size_t i, size_t j)
|
||||||
{
|
{
|
||||||
version (assert) if (_a + j > _b) throw new RangeError();
|
assert(_a + j <= _b);
|
||||||
mixin("_outer[_a + i .. _a + j] "~op~"= value;");
|
mixin("_outer[_a + i .. _a + j] "~op~"= value;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,8 +355,11 @@ if (!is(Unqual!T == bool))
|
||||||
* than realloc.
|
* than realloc.
|
||||||
*/
|
*/
|
||||||
immutable oldLength = length;
|
immutable oldLength = length;
|
||||||
auto newPayload =
|
|
||||||
enforce(cast(T*) malloc(sz))[0 .. oldLength];
|
auto newPayloadPtr = cast(T*) malloc(sz);
|
||||||
|
newPayloadPtr || assert(false, "std.container.Array.reserve failed to allocate memory");
|
||||||
|
auto newPayload = newPayloadPtr[0 .. oldLength];
|
||||||
|
|
||||||
// copy old data over to new array
|
// copy old data over to new array
|
||||||
memcpy(newPayload.ptr, _payload.ptr, T.sizeof * oldLength);
|
memcpy(newPayload.ptr, _payload.ptr, T.sizeof * oldLength);
|
||||||
// Zero out unused capacity to prevent gc from seeing
|
// Zero out unused capacity to prevent gc from seeing
|
||||||
|
@ -374,8 +377,9 @@ if (!is(Unqual!T == bool))
|
||||||
/* These can't have pointers, so no need to zero
|
/* These can't have pointers, so no need to zero
|
||||||
* unused region
|
* unused region
|
||||||
*/
|
*/
|
||||||
auto newPayload =
|
auto newPayloadPtr = cast(T*) realloc(_payload.ptr, sz);
|
||||||
enforce(cast(T*) realloc(_payload.ptr, sz))[0 .. length];
|
newPayloadPtr || assert(false, "std.container.Array.reserve failed to allocate memory");
|
||||||
|
auto newPayload = newPayloadPtr[0 .. length];
|
||||||
_payload = newPayload;
|
_payload = newPayload;
|
||||||
}
|
}
|
||||||
_capacity = elements;
|
_capacity = elements;
|
||||||
|
@ -547,7 +551,8 @@ Complexity: $(BIGOH 1)
|
||||||
bool overflow;
|
bool overflow;
|
||||||
const sz = mulu(elements, T.sizeof, overflow);
|
const sz = mulu(elements, T.sizeof, overflow);
|
||||||
if (overflow) assert(0);
|
if (overflow) assert(0);
|
||||||
auto p = enforce(malloc(sz));
|
auto p = malloc(sz);
|
||||||
|
p || assert(false, "std.container.Array.reserve failed to allocate memory");
|
||||||
static if (hasIndirections!T)
|
static if (hasIndirections!T)
|
||||||
{
|
{
|
||||||
GC.addRange(p, sz);
|
GC.addRange(p, sz);
|
||||||
|
@ -590,17 +595,17 @@ Complexity: $(BIGOH 1)
|
||||||
*/
|
*/
|
||||||
Range opSlice(size_t i, size_t j)
|
Range opSlice(size_t i, size_t j)
|
||||||
{
|
{
|
||||||
version (assert) if (i > j || j > length) throw new RangeError();
|
assert(i <= j && j <= length);
|
||||||
return typeof(return)(this, i, j);
|
return typeof(return)(this, i, j);
|
||||||
}
|
}
|
||||||
ConstRange opSlice(size_t i, size_t j) const
|
ConstRange opSlice(size_t i, size_t j) const
|
||||||
{
|
{
|
||||||
version (assert) if (i > j || j > length) throw new RangeError();
|
assert(i <= j && j <= length);
|
||||||
return typeof(return)(this, i, j);
|
return typeof(return)(this, i, j);
|
||||||
}
|
}
|
||||||
ImmutableRange opSlice(size_t i, size_t j) immutable
|
ImmutableRange opSlice(size_t i, size_t j) immutable
|
||||||
{
|
{
|
||||||
version (assert) if (i > j || j > length) throw new RangeError();
|
assert(i <= j && j <= length);
|
||||||
return typeof(return)(this, i, j);
|
return typeof(return)(this, i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,14 +618,14 @@ Complexity: $(BIGOH 1)
|
||||||
*/
|
*/
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(T) front() inout
|
||||||
{
|
{
|
||||||
version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError();
|
assert(_data.refCountedStore.isInitialized);
|
||||||
return _data._payload[0];
|
return _data._payload[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
@property ref inout(T) back() inout
|
@property ref inout(T) back() inout
|
||||||
{
|
{
|
||||||
version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError();
|
assert(_data.refCountedStore.isInitialized);
|
||||||
return _data._payload[$ - 1];
|
return _data._payload[$ - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +638,7 @@ Complexity: $(BIGOH 1)
|
||||||
*/
|
*/
|
||||||
ref inout(T) opIndex(size_t i) inout
|
ref inout(T) opIndex(size_t i) inout
|
||||||
{
|
{
|
||||||
version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError();
|
assert(_data.refCountedStore.isInitialized);
|
||||||
return _data._payload[i];
|
return _data._payload[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1220,7 +1225,8 @@ unittest
|
||||||
// make sure that Array instances refuse ranges that don't belong to them
|
// make sure that Array instances refuse ranges that don't belong to them
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
import std.exception;
|
import std.exception : assertThrown;
|
||||||
|
|
||||||
Array!int a = [1, 2, 3];
|
Array!int a = [1, 2, 3];
|
||||||
auto r = a.dup[];
|
auto r = a.dup[];
|
||||||
assertThrown(a.insertBefore(r, 42));
|
assertThrown(a.insertBefore(r, 42));
|
||||||
|
@ -1414,6 +1420,19 @@ unittest // const/immutable Array and Ranges
|
||||||
A.ImmutableRange);
|
A.ImmutableRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure @nogc
|
||||||
|
@nogc unittest
|
||||||
|
{
|
||||||
|
Array!int ai;
|
||||||
|
ai ~= 1;
|
||||||
|
assert(ai.front == 1);
|
||||||
|
|
||||||
|
ai.reserve(10);
|
||||||
|
assert(ai.capacity == 10);
|
||||||
|
|
||||||
|
static immutable arr = [1, 2, 3];
|
||||||
|
ai.insertBack(arr);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Array!bool
|
// Array!bool
|
||||||
|
@ -1471,49 +1490,49 @@ if (is(Unqual!T == bool))
|
||||||
/// Ditto
|
/// Ditto
|
||||||
@property T front()
|
@property T front()
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to access the front of an empty Array");
|
||||||
return _outer[_a];
|
return _outer[_a];
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
@property void front(bool value)
|
@property void front(bool value)
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to set the front of an empty Array");
|
||||||
_outer[_a] = value;
|
_outer[_a] = value;
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
T moveFront()
|
T moveFront()
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to move the front of an empty Array");
|
||||||
return _outer.moveAt(_a);
|
return _outer.moveAt(_a);
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
void popFront()
|
void popFront()
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to popFront an empty Array");
|
||||||
++_a;
|
++_a;
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
@property T back()
|
@property T back()
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to access the back of an empty Array");
|
||||||
return _outer[_b - 1];
|
return _outer[_b - 1];
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
@property void back(bool value)
|
@property void back(bool value)
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to set the back of an empty Array");
|
||||||
_outer[_b - 1] = value;
|
_outer[_b - 1] = value;
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
T moveBack()
|
T moveBack()
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to move the back of an empty Array");
|
||||||
return _outer.moveAt(_b - 1);
|
return _outer.moveAt(_b - 1);
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
void popBack()
|
void popBack()
|
||||||
{
|
{
|
||||||
enforce(!empty);
|
enforce(!empty, "Attempting to popBack an empty Array");
|
||||||
--_b;
|
--_b;
|
||||||
}
|
}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
|
@ -1541,7 +1560,10 @@ if (is(Unqual!T == bool))
|
||||||
/// ditto
|
/// ditto
|
||||||
Range opSlice(size_t low, size_t high)
|
Range opSlice(size_t low, size_t high)
|
||||||
{
|
{
|
||||||
assert(_a <= low && low <= high && high <= _b);
|
assert(
|
||||||
|
_a <= low && low <= high && high <= _b,
|
||||||
|
"Using out of bounds indexes on an Array"
|
||||||
|
);
|
||||||
return Range(_outer, _a + low, _a + high);
|
return Range(_outer, _a + low, _a + high);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue