UInt32ArrayAllocator (struct)

The UInt32ArrayAllocator is used to efficiently allocate of many UInt32 arrays within the same memory buffer. This allocator is used internally by various performance oriented objects, like the Octree or the PolygonMesh.

The UInt32ArrayAllocator was written for optimal performance and not simplicity. One example is that it is not storing the stored array sizes, as the owner can use a more compact encoding for the size. A simple way is to use the 1st array data to store the array size.

Using a single buffer has multiple performance benefits, such as avoiding multiple heap allocation calls (slow), avoiding memory fragmentation (reduces global memory usage) and making the data access CPU cache friendly. This allocator is not threadsafe, but supporting a single thread avoids locking checks overhead.

For performance reason, this allocator will only grow, unless UInt32ArrayAllocator.clear or UInt32ArrayAllocator.recompact is called. A proper usage of this allocator should call UInt32ArrayAllocator.recompact when a large enough portion of the memory is unused (eg: 25% or 50%).

Although the UInt32ArrayAllocator is able to reused free storage by using simplified heap-like structure, the user that cares about memory usage should monitor the portion of unused data (internal fragmentation) and recompact it when this portion is large enough (eg: 50%). This can be done through a call to UInt32ArrayAllocator.recompact, however the caller needs to remap all its indices accordingly.

For optimal performance, the array indices (keys) are not safeguarded. The user should do the safeguarding if required.

注釈

This allocator is not threadsafe, unless all threads are having a read-only access.

注釈

Technical detail: UInt32ArrayAllocator.data[0] is a reserved entry, so 0 can always be used as a ‘null’ index for convenience

UInt32ArrayAllocator UInt32ArrayAllocator UInt32ArrayAllocator

Members

UInt32[] data The UInt32 buffer containing all data. Users need to use this data member directly to read or write their UInt32 data.
/*
** Example: UInt32ArrayAllocator
*/

require Containers;
  
operator entry() {

  UInt32ArrayAllocator allocator;
  
  //Allocate array1 with size 2
  UInt32 array1Key = allocator.allocate(2, 0);
  allocator.data[array1Key] = 10;
  allocator.data[array1Key+1] = 11;
  
  //Allocate array2 with size 1 + 1 reserved entry for future growth
  UInt32 array2Key = allocator.allocate(1, 1);
  allocator.data[array2Key] = 20;
  
  //Reallocate array1 to size 3, and update its key with the new one
  array1Key = allocator.reallocate(array1Key, 2, 3, 0);
  allocator.data[array1Key+2] = 12;
  
  //Reallocate array2 to size 2, but we don't expect the key to change since there was 1 reserved entry
  if( allocator.reallocate(array2Key, 1, 2, 0) != array2Key )
    report("UNEXPECTED");
  allocator.data[array2Key+1] = 21;
  
  //Recompact the array
  report( "Unused data after reallocates: " + allocator.unusedSize() );
  UInt32 oldIndexToNewIndex[];
  allocator.recompact( oldIndexToNewIndex );
  //Remap our array keys
  array1Key = oldIndexToNewIndex[array1Key];
  array2Key = oldIndexToNewIndex[array2Key];
  report( "Unused data after recompact: " + allocator.unusedSize() );
  
  report( "Array1 content: " 
          + allocator.data[array1Key] 
          + " " + allocator.data[array1Key+1] 
          + " " + allocator.data[array1Key+2] );
  
  report( "Array2 content: " 
          + allocator.data[array2Key] 
          + " " + allocator.data[array2Key+1] );
  
}

/*
** Output:

Unused data after reallocates: 2
Unused data after recompact: 0
Array1 content: 10 11 12
Array2 content: 20 21

*/

Methods

  UInt32ArrayAllocator ( in UInt32ArrayAllocator other )
  UInt32ArrayAllocator ()
UInt32 allocate ! ( in UInt32 allocateCount, in UInt32 reserveCount )
  append ! ( in UInt32ArrayAllocator other, io Size dataOffset )
  clear ! ()
UInt32ArrayAllocator clone ? ()
  copy ! ( in UInt32ArrayAllocator src )
  free ! ( in UInt32 head, in UInt32 count )
Boolean isUsed ? ( in UInt32 i )
Size memUsage ? ()
UInt32 reallocate ! ( in UInt32 head, in UInt32 prevCount, in UInt32 newCount, in UInt32 reserveCountIfShrinkOrMove )
  recompact ! ( io UInt32 oldIndexToNewIndex[] )
UInt32 size ? ()
UInt32 unusedSize ? ()

Methods in detail

UInt32ArrayAllocator ( in UInt32ArrayAllocator other )

copy constructor



UInt32 UInt32ArrayAllocator.allocate! ( in UInt32 allocateCount, in UInt32 reserveCount )

allocate an array of a certain allocated size, but can reserve a additional entries.

注釈

Reserved additional entries will allow the array to grow in that space without reallocating. However, UInt32ArrayAllocator.recompact will remove all reserved space.


UInt32ArrayAllocator.append! ( in UInt32ArrayAllocator other, io Size dataOffset )

appends one UInt32ArrayAllocator to this one while using a data offset


UInt32ArrayAllocator.clear! ()

clears the managed array


UInt32ArrayAllocator UInt32ArrayAllocator.clone? ()

clone method


UInt32ArrayAllocator.copy! ( in UInt32ArrayAllocator src )

copies another UInt32ArrayAllocator into this one


UInt32ArrayAllocator.free! ( in UInt32 head, in UInt32 count )

free the managed array given a head and a count


Boolean UInt32ArrayAllocator.isUsed? ( in UInt32 i )

returns true if a given index is used


Size UInt32ArrayAllocator.memUsage? ()


UInt32 UInt32ArrayAllocator.reallocate! ( in UInt32 head, in UInt32 prevCount, in UInt32 newCount, in UInt32 reserveCountIfShrinkOrMove )

reallocate the managed array, based on a previous head and count, as well as a new count and a minimum reserved count


UInt32ArrayAllocator.recompact! ( io UInt32 oldIndexToNewIndex[] )

recompact: will remove all unused data entries by compacting all data arrays, while maintaining their relative order. The caller needs to remap its data based on the returned index mapping (oldIndexToNewIndex).

注釈

Only call if there is a significant portion to be recompacted (compare return unusedSize() to size() )


UInt32 UInt32ArrayAllocator.size? ()

returns the size of the array


UInt32 UInt32ArrayAllocator.unusedSize? ()

returns the size of the array which is currently not in use