Can assumeSafeAppend() grab more and more capacity?

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Jun 5 14:08:21 PDT 2017


Imagine an array that wants to reuse its buffer after removing elements 
from it. For example, a PID waiting list can remove completed elements 
and add new ones at the end.

The code would call assumeSafeAppend like this:

     arr = arr.remove!(e => e % 2);
     arr.assumeSafeAppend();

1) Assuming that the array is not relocated, is it possible that the 
capacity will grow and grow? (Imagine that a new memory page from the GC 
beyond the current capacity becomes available? Would assumeSafeAppend() 
grab that as capacity as well?)

For example, if capacity was non-zero before the two lines above, would 
that assumeSafeAppend() call find more capacity than before?

2) If so, is the capacity "allocated" for this buffer or can the GC use 
those pages for other purposes, effectively reducing the array's capacity?

In other words, is having capacity a guarantee like having called reserve()?

3) Bonus: Shouldn't the array specialization of std.algorithm.remove 
call assumeSafeAppend if the array has capacity to begin with? (The 
equivalent of following code?)

     const oldCap = arr.capacity;
     // ... do std.algorithm.remove magic on arr ...
     if (oldCap) {
         arr.assumeSafeAppend();
     }

I'm aware that there can be multiple slices with non-zero capacity until 
one of them grabs the capacity for itself but it's ok for remove() to 
give the capacity to just one of them.

Here is a test program that plays with this idea, starting with two 
identical slices with same capacity:

import std.stdio;
import std.array;
import std.algorithm;

void myRemove(ref int[] arr) {
     const cap = arr.capacity;

     arr = arr.remove!(e => e % 2);

     if (cap) {
         arr.assumeSafeAppend();
     }
}

void info(arrays...)(string title) {
     writefln("\n%s", title);
     foreach (i, arr; arrays) {
         writefln("  %s - ptr: %s, len: %s, cap: %s",
                  (arrays[i]).stringof, arr.ptr, arr.length, arr.capacity);
     }
}

void main() {
     auto a = [ 1, 2, 3, 4 ];
     auto b = a;

     info!(a, b)("before myRemove(a)");

     myRemove(a);
     info!(a, b)("after  myRemove(a)");

     myRemove(b);
     info!(a, b)("after myRemove(b)");
}

before myRemove(a)
   a - ptr: 7F15F40D4060, len: 4, cap: 7
   b - ptr: 7F15F40D4060, len: 4, cap: 7

after  myRemove(a)
   a - ptr: 7F15F40D4060, len: 2, cap: 7  <== 'a' grabbed capacity
   b - ptr: 7F15F40D4060, len: 4, cap: 0  <==

after myRemove(b)
   a - ptr: 7F15F40D4060, len: 2, cap: 7
   b - ptr: 7F15F40D4060, len: 3, cap: 0

Ali


More information about the Digitalmars-d-learn mailing list