Skip to content

Compile-Time Allocation

Quxlang's compile-time allocator intrinsics reserve storage while a function is being evaluated as CONSTEXPR. They expose storage, not a live object: use PLACE AT to begin an object lifetime and DESTROY AT before deallocation.

One storage element

CONSTEXPR_ALLOC and CONSTEXPR_DEALLOC take the stored type as their template argument:

::allocated_integer STATIC_TEST
{
  VAR storage ->TYPED_STORAGE(I32) := CONSTEXPR_ALLOC#I32();
  VAR value ->I32 := PLACE AT(storage->) I32 := 123;

  ASSERT(value-> == 123);

  DESTROY AT(storage->) I32;
  CONSTEXPR_DEALLOC#I32(% [storage]);
}

Explicit size and alignment are available when the eventual stored type is not part of the allocation interface:

VAR storage ->ALIGNED_STORAGE(8, 8) :=
  CONSTEXPR_ALLOC#(@SIZE 8, @ALIGN 8)();

CONSTEXPR_DEALLOC#(@SIZE 8, @ALIGN 8)(% [storage]);

Multiple storage elements

The multiple-element forms use an array pointer and require the allocation count at both ends of the lifetime:

::allocated_bytes STATIC_TEST
{
  VAR count SZ := 3;
  VAR storage =>>TYPED_STORAGE(BYTE) :=
    CONSTEXPR_ALLOC_MULTIPLE#BYTE(% [count]);

  PLACE AT(storage->) BYTE := 7;
  PLACE AT(storage[1]) BYTE := 9;
  PLACE AT((storage + 2)->) BYTE := 11;

  ASSERT((PUN storage[1] AS BYTE) == 9);

  DESTROY AT((storage + 2)->) BYTE;
  DESTROY AT(storage[1]) BYTE;
  DESTROY AT(storage->) BYTE;
  CONSTEXPR_DEALLOC_MULTIPLE#BYTE(% [storage, count]);
}

The corresponding explicit-layout form is:

VAR storage =>>ALIGNED_STORAGE(size, align) :=
  CONSTEXPR_ALLOC_MULTIPLE#(@SIZE size, @ALIGN align)(% [count]);

CONSTEXPR_DEALLOC_MULTIPLE#(@SIZE size, @ALIGN align)(% [storage, count]);

Checked lifetime rules

Compile-time evaluation rejects invalid allocation use, including:

  • freeing the same allocation twice;
  • freeing an interior pointer rather than the allocation start;
  • supplying the wrong count to CONSTEXPR_DEALLOC_MULTIPLE;
  • deallocating storage that still contains a live object; and
  • using storage or a pointer after its allocation was released.

A zero-count multiple allocation is valid, but it must still be paired with the matching deallocation call.

These intrinsics are the compile-time allocation interface. See Object Storage and Lifetime for PLACE AT, PUN, and DESTROY AT.