Skip to content

Commit 9dedff3

Browse files
authored
Merge pull request #3445 from ntrel/capacity
[spec/arrays] Improve capacity docs Signed-off-by: Dennis <dkorpel@users.noreply.github.com> Merged-on-behalf-of: Dennis <dkorpel@users.noreply.github.com>
2 parents 518d6b1 + e2b834e commit 9dedff3

File tree

1 file changed

+70
-11
lines changed

1 file changed

+70
-11
lines changed

spec/arrays.dd

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -576,8 +576,6 @@ Returns an array literal with each element of the literal being the $(D .init) p
576576
the number of bytes per array element.)
577577
$(TROW $(D .length), Returns the number of elements in the array.
578578
This is a fixed quantity for static arrays. It is of type $(D size_t).)
579-
$(TROW $(D .capacity), Returns the number of elements that can be appended to the array without reallocating.
580-
$(D .capacity) is always $(D 0) for static arrays because their size cannot be modified.)
581579
$(TROW $(D .ptr), Returns a pointer to the first element of the array.)
582580
$(TROW $(D .dup), Create a dynamic array of the same size and copy the contents of the array into it. The copy will have any immutability or const stripped. If this conversion is invalid the call will not compile.)
583581
$(TROW $(D .idup), Create a dynamic array of the same size and copy the contents of the array into it. The copy is typed as being immutable. If this conversion is invalid the call will not compile.)
@@ -607,7 +605,8 @@ Returns an array literal with each element of the literal being the $(D .init) p
607605
which is 8 in 32-bit builds and 16 on 64-bit builds.))
608606
$(TROW $(D .length), Get/set number of elements in the
609607
array. It is of type $(D size_t).)
610-
$(TROW $(D .capacity), Returns the number of elements that can be appended to the array without reallocating.)
608+
$(TROW $(D .capacity), Returns the number of elements that can be appended to the array without reallocating.
609+
See $(RELATIVE_LINK2 capacity-reserve, here) for details.)
611610
$(TROW $(D .ptr), Returns a pointer to the first element of the array.)
612611
$(TROW $(D .dup), Create a dynamic array of the same size and copy the contents of the array into it. The copy will have any immutability or const stripped. If this conversion is invalid the call will not compile.)
613612
$(TROW $(D .idup), Create a dynamic array of the same size and copy the contents of the array into it. The copy is typed as being immutable. If this conversion is invalid the call will not compile.)
@@ -664,7 +663,7 @@ $(H4 $(LNAME2 growing, Growing an Array))
664663
is larger and either:)
665664

666665
* The array was not $(DDSUBLINK spec/garbage, op_involving_gc, allocated by the GC).
667-
* There is no spare $(RELATIVE_LINK2 capacity-reserve, capacity) in the array.
666+
* There is no spare $(RELATIVE_LINK2 capacity-reserve, capacity) for the array.
668667
* Resizing in place would overwrite valid data still accessible in another slice.
669668

670669
$(SPEC_RUNNABLE_EXAMPLE_RUN
@@ -759,24 +758,84 @@ array.length = i;
759758

760759
$(H3 $(LNAME2 capacity-reserve, `capacity` and `reserve`))
761760

762-
$(P The $(D capacity) property gives the maximum length the array
763-
can grow to without reallocating. The spare capacity for array *a*
764-
is `a.capacity - a.length`.)
761+
$(P The $(D capacity) property gives the maximum length a dynamic array
762+
can grow to without reallocating. If the array does not point to
763+
GC-allocated memory, the capacity will be zero.
764+
The spare capacity for an array *a* is `a.capacity - a.length`.)
765+
766+
$(P By default, `capacity` will be zero if an element has been stored after the slice.)
767+
768+
$(SPEC_RUNNABLE_EXAMPLE_RUN
769+
---
770+
int[] a;
771+
assert(a.capacity == 0);
772+
a.length = 3; // may allocate spare capacity too
773+
assert(a.capacity >= 3);
774+
auto b = a[1..3];
775+
assert(b.capacity >= 2); // either a or b can append into any spare capacity
776+
b = a[0..2];
777+
assert(b.capacity == 0);
778+
---
779+
)
780+
781+
$(RATIONALE This behaviour helps prevent accidental overwriting of
782+
elements in another slice. It is also necessary to protect immutable
783+
elements from being overwritten.)
784+
765785
$(P The $(D reserve)
766-
function expands an array's capacity for use by the append operator.)
786+
function expands an array's capacity for use by the
787+
$(RELATIVE_LINK2 array-appending, append operator) or `.length` assignment.)
767788

768-
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
789+
$(SPEC_RUNNABLE_EXAMPLE_RUN
769790
---------
770791
int[] array;
771-
size_t cap = array.reserve(10); // request
792+
const size_t cap = array.reserve(10); // request
772793
assert(cap >= 10); // allocated may be more than request
794+
assert(array.ptr != null);
773795

774796
int[] copy = array;
797+
assert(copy.capacity == cap); // array and copy have same capacity
775798
array ~= [1, 2, 3, 4, 5]; // grow in place
776-
assert(cap == array.capacity);
799+
assert(cap == array.capacity); // array memory was not reallocated
777800
assert(copy.ptr == array.ptr);
801+
assert(copy.capacity == 0);
802+
copy ~= 0; // new allocation
803+
assert(copy.ptr != array.ptr);
778804
---------
779805
)
806+
$(P Above, `copy`'s length remains zero but it points to the same
807+
memory allocated by the `reserve` call. Because `array` is then appended
808+
to, `copy.ptr + 0` no longer points to unused memory - instead that
809+
is the address of `array[0]`. So `copy.capacity` will be zero to
810+
prevent any appending to `copy` from overwriting elements in `array`.)
811+
812+
$(NOTE The runtime uses the number of appended elements to track the
813+
start of the spare capacity for the memory allocation.)
814+
815+
$(P When an array with spare capacity has its length reduced, or is
816+
assigned a slice of itself that ends before the previous last element,
817+
the capacity will be zero.)
818+
819+
$(P The `@system` function $(REF1 assumeSafeAppend, object) allows the
820+
capacity to be regained, but care must be taken not to overwrite
821+
immutable elements that may exist in a longer slice.)
822+
823+
$(SPEC_RUNNABLE_EXAMPLE_RUN
824+
---
825+
int[] a = [1, 2, 3];
826+
a.length--;
827+
assert(a.capacity == 0);
828+
a.assumeSafeAppend();
829+
assert(a.capacity >= 3);
830+
---
831+
)
832+
833+
$(NOTE Accessing `.capacity` may require the runtime to
834+
acquire a global lock and perform a cache lookup.)
835+
836+
$(BEST_PRACTICE Avoid intensive use of `.capacity` in performance-sensitive code.
837+
Instead, track the capacity locally when building an array via a unique reference.)
838+
780839

781840
$(H3 $(LNAME2 func-as-property, Functions as Array Properties))
782841

0 commit comments

Comments
 (0)