The OpenD Programming Language

RegionAllocator

This struct provides an interface to the RegionAllocator functionality and enforces scoped deletion. A new instance using the thread-local RegionAllocatorStack instance is created using the global newRegionAllocator function. A new instance using an explicitly created RegionAllocatorStack is created using RegionAllocatorStack.newRegionAllocator.

Each instance has reference semantics in that any copy will allocate from the same memory. When the last copy of an instance goes out of scope, all memory allocated via that instance is freed. Only the most recently created still-existing RegionAllocator using a given RegionAllocatorStack may be used to allocate and free memory at any given time. Deviations from this model result in a RegionAllocatorException being thrown.

An uninitialized RegionAllocator (for example RegionAllocator.init) has semantics similar to a null pointer. It may be assigned to or passed to a function. However, any attempt to call a method will result in a RegionAllocatorException being thrown.

Destructor

A destructor is present on this object, but not explicitly documented in the source.

Postblit

A postblit is present on this object, but not explicitly documented in the source.

Members

Functions

allocate
void* allocate(size_t nBytes)

Allocates nBytes bytes on the RegionAllocatorStack used by this RegionAllocator instance. The last block allocated from this RegionAllocator instance can be freed by calling RegionAllocator.free or RegionAllocator.freeLast or will be automatically freed when the last copy of this RegionAllocator instance goes out of scope.

array
Unqual!(ElementType!(R))[] array(R range)

Copies range to an array. The array will be located on the RegionAllocator stack if any of the following conditions apply:

free
void free(void* ptr)

Checks that ptr is a pointer to the block that would be freed by freeLast then calls freeLast. Throws a RegionAllocatorException if the pointer does not point to the block that would be freed by freeLast.

freeLast
void freeLast()

Frees the last block of memory allocated by the current RegionAllocator. Throws a RegionAllocatorException if this RegionAllocator is not the most recently created still-existing RegionAllocator using its RegionAllocatorStack instance.

gcScanned
bool gcScanned()

Returns whether the RegionAllocatorStack used by this RegionAllocator instance is scanned by the garbage collector.

newArray
auto newArray(I sizes)

Allocates an array of type T. T may be a multidimensional array. In this case sizes may be specified for any number of dimensions from 1 to the number in T.

resize
bool resize(const(void)* ptr, size_t newSize)

Attempts to resize a previously allocated block of memory in place. This is possible only if ptr points to the beginning of the last block allocated by this RegionAllocator instance and, in the case where newSize is greater than the old size, there is additional space in the segment that ptr was allocated from. Additionally, blocks larger than this RegionAllocator's segment size cannot be grown or shrunk.

segmentSize
size_t segmentSize()

Returns the segment size of the RegionAllocatorStack used by this RegionAllocator.

segmentSlack
size_t segmentSlack()

Returns the maximum number of bytes that may be allocated in the current segment.

uninitializedArray
auto uninitializedArray(I sizes)

Same as newArray, except skips initialization of elements for performance reasons.

Manifest constants

freeIsChecked
enum freeIsChecked;

True because if memory is freed via free() instead of freeLast() then the pointer is checked for validity.

isAutomatic
enum isAutomatic;

False because memory allocated by this allocator is not automatically reclaimed by the garbage collector.

isScoped
enum isScoped;

True because, when the last last copy of a $(RegionAllocator) instance goes out of scope, the memory it references is automatically freed.

Static functions

alignBytes
size_t alignBytes(size_t nBytes)

Returns the number of bytes to which an allocation of size nBytes is guaranteed to be aligned.

allocSize
size_t allocSize(size_t nBytes)

Returns the number of bytes used to satisfy an allocation request of nBytes. Will return a value greater than or equal to nBytes to account for alignment overhead.

Examples

1 void foo() {
2     auto alloc = newRegionAllocator();
3     auto ptr1 = bar(alloc);
4     auto ptr2 = alloc.allocate(42);
5 
6     // The last copy of the RegionAllocator object used to allocate ptr1
7     // and ptr2 is going out of scope here.  The memory pointed to by
8     // both ptr1 and ptr2 will be freed.
9 }
10 
11 void* bar(RegionAllocator alloc) {
12     auto ret = alloc.allocate(42);
13 
14     auto alloc2 = newRegionAllocator();
15     auto ptr3 = alloc2.allocate(42);
16 
17     // ptr3 was allocated using alloc2, which is going out of scope.
18     // Its memory will therefore be freed.  ret was allocated using alloc.
19     // A copy of this RegionAllocator is still alive in foo() after
20     // bar() executes.  Therefore, ret will not be freed on returning and
21     // is still valid after bar() returns.
22 
23     return ret;
24 }
25 
26 void* thisIsSafe() {
27     // This is safe because the two RegionAllocator objects being used
28     // are using two different RegionAllocatorStack objects.
29     auto alloc = newRegionAllocator();
30     auto ptr1 = alloc.allocate(42);
31 
32     auto stack = RegionAllocatorStack(1_048_576, GCScan.no);
33     auto alloc2 = stack.newRegionAllocator();
34 
35     auto ptr2 = alloc2.allocate(42);
36     auto ptr3 = alloc.allocate(42);
37 }
38 
39 void* dontDoThis() {
40     auto alloc = newRegionAllocator();
41     auto ptr1 = alloc.allocate(42);
42     auto alloc2 = newRegionAllocator();
43 
44     // Error:  Allocating from a RegionAllocator instance other than the
45     // most recently created one that's still alive from a given stack.
46     auto ptr = alloc.allocate(42);
47 }
48 
49 void uninitialized() {
50     RegionAllocator alloc;
51     auto ptr = alloc.allocate(42);  // Error:  alloc is not initialized.
52     auto alloc2 = alloc;  // Ok.  Both alloc, alloc2 are uninitialized.
53 
54     alloc2 = newRegionAllocator();
55     auto ptr2 = alloc2.allocate(42);  // Ok.
56     auto ptr3 = alloc.allocate(42);  // Error:  alloc is still uninitialized.
57 
58     alloc = alloc2;
59     auto ptr4 = alloc.allocate(42);  // Ok.
60 }

Note: Allocations larger than this.segmentSize are handled as a special case and fall back to allocating directly from the C heap. These large allocations are freed as if they were allocated on a RegionAllocatorStack when free or freeLast is called or the last copy of a RegionAllocator instance goes out of scope. However, due to the extra bookkeeping required, destroying a region (as happens when the last copy of a RegionAllocator instance goes out of scope) will require time linear instead of constant in the number of allocations for regions where these large allocations are present.

Meta