In-place extension of arrays only for certain alignment?

Ali Çehreli acehreli at yahoo.com
Tue Aug 16 18:11:54 UTC 2022


Related to my DConf 2022 lightning talk, I am noticing that D runtime's 
in-place array extension optimization is available only for array data 
that are at certain memory alignments.

I used the following program to test it. In addition to repeatedly 
adding an element to an array,

- 'version = neither' does not drop any element (this is "good" as well)

- 'version = bad' case drops the front element (a moving window of 1)

- 'version = good' case drops elements only when element data will hit a 
certain alignment value.

Is this expected?

import std.stdio;
import std.range;

// PLEASE UNCOMMENT ONLY ONE:
// version = bad;        // No in-place extension
// version = good;       // In-place extension happens
// version = neither;    // In-place extension happens

mixin assertSingleVersionOf!("bad", "good", "neither");

void main() {
   struct S {
     ubyte[4] data;  // Try different reasonable sizes.
                     // For example, 5 will not work even
                     // for the "good" case.
   }

   S[] arr;

   foreach (i; 0 .. 100_000) {
     const oldCap = arr.capacity;
     const oldPtr = arr.ptr;

     arr ~= S.init;

     if (arr.capacity != oldCap) {
       // The array needed to be extended...
       if (arr.ptr == oldPtr) {
         // ... but the pointer did not change
         writefln!"In-place extension -- element: %,s  capacity: %,s -> 
%,s  ptr: %s"(
           i, oldCap, arr.capacity, arr.ptr);
       }
     }

     version (neither) {
       // Do not remove any element; just extend
     }

     version (bad) {
       // Dropping 1 element inhibits in-place extension
       // (Many values other than 1 will inhibit as well.)
       arr = arr[1..$];

       // Even this does not help
       arr.assumeSafeAppend();
     }

     version (good) {
       // Dropping front elements equaling 2048 bytes works.
       // (Likely a GC magic constant.)

       enum magic = 2048;
       enum elementsPerPage = magic / S.sizeof;

       if (arr.length == elementsPerPage) {
         arr = arr[elementsPerPage..$];
       }
     }
   }
}

// A useful template that has nothing to do with this problem.
mixin template assertSingleVersionOf(args...) {
   import std.format : format;

   static assert (1 >= {
     size_t count = 0;
     static foreach (arg; args) {
       static assert (is (typeof(arg) == string));
       mixin (format!q{
         version (%s) {
           ++count;
         }
       }(arg));
     }
     return count;
   }(), format!"Please pick only one or none of %(%s, %)"([args]));
}

Ali


More information about the Digitalmars-d-learn mailing list