Make Array postblit safe if possible
This commit is contained in:
parent
c511b97b1b
commit
9efbc9d5e0
@ -123,7 +123,7 @@ struct Range(A)
|
|||||||
--this.end;
|
--this.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref inout(E) opIndex(const size_t i) inout @trusted
|
ref inout(E) opIndex(size_t i) inout @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i < length);
|
assert(i < length);
|
||||||
@ -143,7 +143,7 @@ struct Range(A)
|
|||||||
return typeof(return)(*this.container, this.begin, this.end);
|
return typeof(return)(*this.container, this.begin, this.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
Range opSlice(const size_t i, const size_t j) @trusted
|
Range opSlice(size_t i, size_t j) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -154,7 +154,7 @@ struct Range(A)
|
|||||||
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
return typeof(return)(*this.container, this.begin + i, this.begin + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
A.ConstRange opSlice(const size_t i, const size_t j) const @trusted
|
A.ConstRange opSlice(size_t i, size_t j) const @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -218,9 +218,9 @@ struct Array(T)
|
|||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(R)(R init, shared Allocator allocator = defaultAllocator)
|
this(R)(R init, shared Allocator allocator = defaultAllocator)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
insertBack(init);
|
insertBack(init);
|
||||||
@ -244,7 +244,7 @@ struct Array(T)
|
|||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(R)(ref R init, shared Allocator allocator = defaultAllocator)
|
this(R)(ref R init, shared Allocator allocator = defaultAllocator)
|
||||||
if (is(Unqual!R == Array))
|
if (is(Unqual!R == Array))
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
insertBack(init[]);
|
insertBack(init[]);
|
||||||
@ -252,7 +252,7 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
|
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
if (is(R == Array))
|
if (is(R == Array))
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
if (allocator is init.allocator)
|
if (allocator is init.allocator)
|
||||||
@ -300,16 +300,16 @@ struct Array(T)
|
|||||||
* init = Initial value to fill the array with.
|
* init = Initial value to fill the array with.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(const size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
|
this(size_t len, T init, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
reserve(len);
|
reserve(len);
|
||||||
uninitializedFill(this.data[0 .. len], init);
|
uninitializedFill(slice(len), init);
|
||||||
length_ = len;
|
length_ = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(const size_t len, shared Allocator allocator = defaultAllocator)
|
this(size_t len, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
length = len;
|
length = len;
|
||||||
@ -349,10 +349,10 @@ struct Array(T)
|
|||||||
/**
|
/**
|
||||||
* Destroys this $(D_PSYMBOL Array).
|
* Destroys this $(D_PSYMBOL Array).
|
||||||
*/
|
*/
|
||||||
~this() @trusted
|
~this()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
allocator.deallocate(this.data[0 .. capacity]);
|
(() @trusted => allocator.deallocate(slice(capacity)))();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,7 +360,7 @@ struct Array(T)
|
|||||||
*/
|
*/
|
||||||
this(this)
|
this(this)
|
||||||
{
|
{
|
||||||
auto buf = this.data[0 .. this.length_];
|
auto buf = slice(this.length);
|
||||||
this.length_ = capacity_ = 0;
|
this.length_ = capacity_ = 0;
|
||||||
this.data = null;
|
this.data = null;
|
||||||
insertBack(buf);
|
insertBack(buf);
|
||||||
@ -418,7 +418,7 @@ struct Array(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* len = New length.
|
* len = New length.
|
||||||
*/
|
*/
|
||||||
@property void length(const size_t len) @trusted
|
@property void length(size_t len) @trusted
|
||||||
{
|
{
|
||||||
if (len == length)
|
if (len == length)
|
||||||
{
|
{
|
||||||
@ -475,7 +475,7 @@ struct Array(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* size = Desired size.
|
* size = Desired size.
|
||||||
*/
|
*/
|
||||||
void reserve(const size_t size) @trusted
|
void reserve(size_t size) @trusted
|
||||||
{
|
{
|
||||||
if (capacity_ >= size)
|
if (capacity_ >= size)
|
||||||
{
|
{
|
||||||
@ -532,14 +532,14 @@ struct Array(T)
|
|||||||
* Params:
|
* Params:
|
||||||
* size = Desired size.
|
* size = Desired size.
|
||||||
*/
|
*/
|
||||||
void shrink(const size_t size) @trusted
|
void shrink(size_t size) @trusted
|
||||||
{
|
{
|
||||||
if (capacity <= size)
|
if (capacity <= size)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const n = max(length, size);
|
const n = max(length, size);
|
||||||
void[] buf = this.data[0 .. this.capacity_];
|
void[] buf = slice(this.capacity_);
|
||||||
if (allocator.reallocateInPlace(buf, n * T.sizeof))
|
if (allocator.reallocateInPlace(buf, n * T.sizeof))
|
||||||
{
|
{
|
||||||
this.capacity_ = n;
|
this.capacity_ = n;
|
||||||
@ -597,7 +597,7 @@ struct Array(T)
|
|||||||
*
|
*
|
||||||
* Returns: The number of elements removed
|
* Returns: The number of elements removed
|
||||||
*/
|
*/
|
||||||
size_t removeBack(const size_t howMany)
|
size_t removeBack(size_t howMany)
|
||||||
out (removed)
|
out (removed)
|
||||||
{
|
{
|
||||||
assert(removed <= howMany);
|
assert(removed <= howMany);
|
||||||
@ -622,7 +622,17 @@ struct Array(T)
|
|||||||
assert(v.removeBack(3) == 0);
|
assert(v.removeBack(3) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @property inout(T)* end() inout
|
private inout(T)[] slice(size_t length) inout @trusted
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(length <= capacity);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return this.data[0 .. length];
|
||||||
|
}
|
||||||
|
|
||||||
|
private @property inout(T)* end() inout @trusted
|
||||||
{
|
{
|
||||||
return this.data + this.length_;
|
return this.data + this.length_;
|
||||||
}
|
}
|
||||||
@ -638,22 +648,24 @@ struct Array(T)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
Range remove(Range r) @trusted
|
Range remove(Range r)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(r.container is &this);
|
assert(r.container is &this);
|
||||||
assert(r.begin >= this.data);
|
assert(r.begin >= this.data);
|
||||||
assert(r.end <= this.data + length);
|
assert(r.end <= end);
|
||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
auto target = r.begin;
|
auto target = r.begin;
|
||||||
for (auto source = r.end; source != end; ++source, ++target)
|
auto source = r.end;
|
||||||
|
while (source !is end)
|
||||||
{
|
{
|
||||||
move(*source, *target);
|
move(*source, *target);
|
||||||
|
((ref s, ref t) @trusted {++s; ++t;})(source, target);
|
||||||
}
|
}
|
||||||
length = length - r.length;
|
length = length - r.length;
|
||||||
return Range(this, r.begin, this.data + length);
|
return Range(this, r.begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -678,7 +690,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void moveBack(R)(ref R el) @trusted
|
private void moveBack(R)(ref R el) @trusted
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
{
|
{
|
||||||
reserve(this.length + 1);
|
reserve(this.length + 1);
|
||||||
moveEmplace(el, *end);
|
moveEmplace(el, *end);
|
||||||
@ -695,20 +707,20 @@ struct Array(T)
|
|||||||
* Returns: The number of elements inserted.
|
* Returns: The number of elements inserted.
|
||||||
*/
|
*/
|
||||||
size_t insertBack(R)(R el)
|
size_t insertBack(R)(R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
{
|
{
|
||||||
moveBack(el);
|
moveBack(el);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBack(R)(ref R el) @trusted
|
size_t insertBack(R)(ref R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
{
|
{
|
||||||
this.length = this.length + 1;
|
length = length + 1;
|
||||||
scope (failure)
|
scope (failure)
|
||||||
{
|
{
|
||||||
this.length = this.length - 1;
|
length = length - 1;
|
||||||
}
|
}
|
||||||
opIndex(this.length - 1) = el;
|
opIndex(this.length - 1) = el;
|
||||||
return 1;
|
return 1;
|
||||||
@ -716,9 +728,9 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBack(R)(R el)
|
size_t insertBack(R)(R el)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
{
|
{
|
||||||
static if (hasLength!R)
|
static if (hasLength!R)
|
||||||
{
|
{
|
||||||
@ -795,9 +807,9 @@ struct Array(T)
|
|||||||
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
size_t insertAfter(R)(Range r, R el)
|
size_t insertAfter(R)(Range r, R el)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(r.container is &this);
|
assert(r.container is &this);
|
||||||
@ -828,7 +840,7 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertAfter(R)(Range r, auto ref R el)
|
size_t insertAfter(R)(Range r, auto ref R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(r.container is &this);
|
assert(r.container is &this);
|
||||||
@ -855,9 +867,9 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore(R)(Range r, R el)
|
size_t insertBefore(R)(Range r, R el)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(r.container is &this);
|
assert(r.container is &this);
|
||||||
@ -884,7 +896,7 @@ struct Array(T)
|
|||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
size_t insertBefore(R)(Range r, auto ref R el)
|
size_t insertBefore(R)(Range r, auto ref R el)
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(r.container is &this);
|
assert(r.container is &this);
|
||||||
@ -993,7 +1005,7 @@ struct Array(T)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE length > pos).
|
* Precondition: $(D_INLINECODE length > pos).
|
||||||
*/
|
*/
|
||||||
ref T opIndexAssign(E : T)(auto ref E value, const size_t pos)
|
ref T opIndexAssign(E : T)(auto ref E value, size_t pos)
|
||||||
{
|
{
|
||||||
return opIndex(pos) = value;
|
return opIndex(pos) = value;
|
||||||
}
|
}
|
||||||
@ -1058,7 +1070,7 @@ struct Array(T)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE length > pos).
|
* Precondition: $(D_INLINECODE length > pos).
|
||||||
*/
|
*/
|
||||||
ref inout(T) opIndex(const size_t pos) inout @trusted
|
ref inout(T) opIndex(size_t pos) inout @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(length > pos);
|
assert(length > pos);
|
||||||
@ -1133,7 +1145,7 @@ struct Array(T)
|
|||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
*/
|
*/
|
||||||
bool opEquals(R)(R that) const
|
bool opEquals(R)(R that) const
|
||||||
if (is(R == Range) || is(R == ConstRange))
|
if (is(R == Range) || is(R == ConstRange))
|
||||||
{
|
{
|
||||||
return equal(opIndex(), that);
|
return equal(opIndex(), that);
|
||||||
}
|
}
|
||||||
@ -1222,7 +1234,7 @@ struct Array(T)
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE i <= j && j <= length).
|
* Precondition: $(D_INLINECODE i <= j && j <= length).
|
||||||
*/
|
*/
|
||||||
Range opSlice(const size_t i, const size_t j) @trusted
|
Range opSlice(size_t i, size_t j) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -1234,7 +1246,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ConstRange opSlice(const size_t i, const size_t j) const @trusted
|
ConstRange opSlice(size_t i, size_t j) const @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -1295,7 +1307,7 @@ struct Array(T)
|
|||||||
* Precondition: $(D_INLINECODE i <= j && j <= length
|
* Precondition: $(D_INLINECODE i <= j && j <= length
|
||||||
* && value.length == j - i)
|
* && value.length == j - i)
|
||||||
*/
|
*/
|
||||||
Range opSliceAssign(size_t R)(T[R] value, const size_t i, const size_t j)
|
Range opSliceAssign(size_t R)(T[R] value, size_t i, size_t j)
|
||||||
@trusted
|
@trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -1309,7 +1321,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range opSliceAssign(R : T)(auto ref R value, const size_t i, const size_t j)
|
Range opSliceAssign(R : T)(auto ref R value, size_t i, size_t j)
|
||||||
@trusted
|
@trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@ -1323,7 +1335,7 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
Range opSliceAssign(Range value, const size_t i, const size_t j) @trusted
|
Range opSliceAssign(Range value, size_t i, size_t j) @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(i <= j);
|
assert(i <= j);
|
||||||
@ -1402,14 +1414,14 @@ struct Array(T)
|
|||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref typeof(this) opAssign(R)(ref R that)
|
ref typeof(this) opAssign(R)(ref R that)
|
||||||
if (is(Unqual!R == Array))
|
if (is(Unqual!R == Array))
|
||||||
{
|
{
|
||||||
return this = that[];
|
return this = that[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ref typeof(this) opAssign(R)(R that) @trusted
|
ref typeof(this) opAssign(R)(R that)
|
||||||
if (is(R == Array))
|
if (is(R == Array))
|
||||||
{
|
{
|
||||||
swap(this.data, that.data);
|
swap(this.data, that.data);
|
||||||
swap(this.length_, that.length_);
|
swap(this.length_, that.length_);
|
||||||
@ -1428,9 +1440,9 @@ struct Array(T)
|
|||||||
* Returns: $(D_KEYWORD this).
|
* Returns: $(D_KEYWORD this).
|
||||||
*/
|
*/
|
||||||
ref typeof(this) opAssign(R)(R that)
|
ref typeof(this) opAssign(R)(R that)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
&& isInputRange!R
|
&& isInputRange!R
|
||||||
&& isImplicitlyConvertible!(ElementType!R, T))
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
{
|
{
|
||||||
length = 0;
|
length = 0;
|
||||||
insertBack(that);
|
insertBack(that);
|
||||||
@ -1670,3 +1682,14 @@ struct Array(T)
|
|||||||
Array!int v1;
|
Array!int v1;
|
||||||
v1 = Array!int([5, 15, 8]);
|
v1 = Array!int([5, 15, 8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Postblit is safe
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto array = Array!int(3);
|
||||||
|
void func(Array!int arg)
|
||||||
|
{
|
||||||
|
assert(arg.capacity == 3);
|
||||||
|
}
|
||||||
|
func(array);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user