Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions mak/COPY
Original file line number Diff line number Diff line change
Expand Up @@ -406,5 +406,6 @@ COPY=\
$(IMPDIR)\rt\array\comparison.d \
$(IMPDIR)\rt\array\equality.d \
$(IMPDIR)\rt\array\casting.d \
$(IMPDIR)\rt\array\capacity.d \
\
$(IMPDIR)\etc\linux\memoryerror.d
3 changes: 3 additions & 0 deletions mak/DOCS
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ DOCS=\
$(DOCDIR)\rt_aApplyR.html \
$(DOCDIR)\rt_adi.html \
$(DOCDIR)\rt_alloca.html \
\
$(DOCDIR)\rt_array_capacity.html \
\
$(DOCDIR)\rt_arrayassign.html \
$(DOCDIR)\rt_arraycat.html \
\
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ SRCS=\
src\rt\array\comparison.d \
src\rt\array\equality.d \
src\rt\array\casting.d \
src\rt\array\capacity.d \
\
src\rt\backtrace\dwarf.d \
src\rt\backtrace\elf.d \
Expand Down
3 changes: 3 additions & 0 deletions mak/WINDOWS
Original file line number Diff line number Diff line change
Expand Up @@ -1196,3 +1196,6 @@ $(IMPDIR)\rt\array\equality.d : src\rt\array\equality.d

$(IMPDIR)\rt\array\casting.d : src\rt\array\casting.d
copy $** $@

$(IMPDIR)\rt\array\capacity.d : src\rt\array\capacity.d
copy $** $@
3 changes: 3 additions & 0 deletions posix.mak
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ $(DOCDIR)/core_sys_darwin_netinet_%.html : src/core/sys/darwin/netinet/%.d $(DMD
$(DOCDIR)/rt_%.html : src/rt/%.d $(DMD)
$(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $<

$(DOCDIR)/rt_array_capacity.html : src/rt/array/capacity.d $(DMD)
$(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $<

$(DOCDIR)/rt_backtrace_%.html : src/rt/backtrace/%.d $(DMD)
$(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $<

Expand Down
192 changes: 7 additions & 185 deletions src/object.d
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ public import rt.array.comparison : __cmp;
public import rt.array.equality : __ArrayEq, __equals;
public import rt.array.casting: __ArrayCast;

/// See $(REF capacity, rt,array,capacity)
public import rt.array.capacity: capacity;
/// See $(REF reserve, rt,array,capacity)
public import rt.array.capacity: reserve;
/// See $(REF assumeSafeAppend, rt,array,capacity)
public import rt.array.capacity: assumeSafeAppend;

// Compare class and interface objects for ordering.
private int __cmp(Obj)(Obj lhs, Obj rhs)
if (is(Obj : Object))
Expand Down Expand Up @@ -3543,191 +3550,6 @@ nothrow @safe @nogc unittest
assert(postblitRecurseOrder == order);
}

private
{
extern (C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow;
extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow;
}

/**
* (Property) Gets the current _capacity of a slice. The _capacity is the size
* that the slice can grow to before the underlying array must be
* reallocated or extended.
*
* If an append must reallocate a slice with no possibility of extension, then
* `0` is returned. This happens when the slice references a static array, or
* if another slice references elements past the end of the current slice.
*
* Note: The _capacity of a slice may be impacted by operations on other slices.
*/
@property size_t capacity(T)(T[] arr) pure nothrow @trusted
{
return _d_arraysetcapacity(typeid(T[]), 0, cast(void[]*)&arr);
}

///
@safe unittest
{
//Static array slice: no capacity
int[4] sarray = [1, 2, 3, 4];
int[] slice = sarray[];
assert(sarray.capacity == 0);
//Appending to slice will reallocate to a new array
slice ~= 5;
assert(slice.capacity >= 5);

//Dynamic array slices
int[] a = [1, 2, 3, 4];
int[] b = a[1 .. $];
int[] c = a[1 .. $ - 1];
debug(SENTINEL) {} else // non-zero capacity very much depends on the array and GC implementation
{
assert(a.capacity != 0);
assert(a.capacity == b.capacity + 1); //both a and b share the same tail
}
assert(c.capacity == 0); //an append to c must relocate c.
}

/**
* Reserves capacity for a slice. The capacity is the size
* that the slice can grow to before the underlying array must be
* reallocated or extended.
*
* Returns: The new capacity of the array (which may be larger than
* the requested capacity).
*/
size_t reserve(T)(ref T[] arr, size_t newcapacity) pure nothrow @trusted
{
if (__ctfe)
return newcapacity;
else
return _d_arraysetcapacity(typeid(T[]), newcapacity, cast(void[]*)&arr);
}

///
@safe unittest
{
//Static array slice: no capacity. Reserve relocates.
int[4] sarray = [1, 2, 3, 4];
int[] slice = sarray[];
auto u = slice.reserve(8);
assert(u >= 8);
assert(&sarray[0] !is &slice[0]);
assert(slice.capacity == u);

//Dynamic array slices
int[] a = [1, 2, 3, 4];
a.reserve(8); //prepare a for appending 4 more items
auto p = &a[0];
u = a.capacity;
a ~= [5, 6, 7, 8];
assert(p == &a[0]); //a should not have been reallocated
assert(u == a.capacity); //a should not have been extended
}

// https://issues.dlang.org/show_bug.cgi?id=12330, reserve() at CTFE time
@safe unittest
{
int[] foo() {
int[] result;
auto a = result.reserve = 5;
assert(a == 5);
return result;
}
enum r = foo();
}

// Issue 6646: should be possible to use array.reserve from SafeD.
@safe unittest
{
int[] a;
a.reserve(10);
}

/**
* Assume that it is safe to append to this array. Appends made to this array
* after calling this function may append in place, even if the array was a
* slice of a larger array to begin with.
*
* Use this only when it is certain there are no elements in use beyond the
* array in the memory block. If there are, those elements will be
* overwritten by appending to this array.
*
* Warning: Calling this function, and then using references to data located after the
* given array results in undefined behavior.
*
* Returns:
* The input is returned.
*/
auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow @system
{
_d_arrayshrinkfit(typeid(T[]), *(cast(void[]*)&arr));
return arr;
}

///
@system unittest
{
int[] a = [1, 2, 3, 4];

// Without assumeSafeAppend. Appending relocates.
int[] b = a [0 .. 3];
b ~= 5;
assert(a.ptr != b.ptr);

debug(SENTINEL) {} else
{
// With assumeSafeAppend. Appending overwrites.
int[] c = a [0 .. 3];
c.assumeSafeAppend() ~= 5;
assert(a.ptr == c.ptr);
}
}

@system unittest
{
int[] arr;
auto newcap = arr.reserve(2000);
assert(newcap >= 2000);
assert(newcap == arr.capacity);
auto ptr = arr.ptr;
foreach (i; 0..2000)
arr ~= i;
assert(ptr == arr.ptr);
arr = arr[0..1];
arr.assumeSafeAppend();
arr ~= 5;
assert(ptr == arr.ptr);
}

@system unittest
{
int[] arr = [1, 2, 3];
void foo(ref int[] i)
{
i ~= 5;
}
arr = arr[0 .. 2];
foo(assumeSafeAppend(arr)); //pass by ref
assert(arr[]==[1, 2, 5]);
arr = arr[0 .. 1].assumeSafeAppend(); //pass by value
}

// https://issues.dlang.org/show_bug.cgi?id=10574
@system unittest
{
int[] a;
immutable(int[]) b;
auto a2 = &assumeSafeAppend(a);
auto b2 = &assumeSafeAppend(b);
auto a3 = assumeSafeAppend(a[]);
auto b3 = assumeSafeAppend(b[]);
assert(is(typeof(*a2) == int[]));
assert(is(typeof(*b2) == immutable(int[])));
assert(is(typeof(a3) == int[]));
assert(is(typeof(b3) == immutable(int[])));
}

version (none)
{
// enforce() copied from Phobos std.contracts for destroy(), left out until
Expand Down
Loading