Myrddin: Allocation

Summary: Memory Allocation

pkg std =
        generic mk  : (val : @a -> @a#)
        generic alloc   : (     -> @a#)
        generic zalloc  : (     -> @a#)
        generic free    : (v:@a#    -> void)
        generic slalloc : (len : size   -> @a[:])
        generic slzalloc    : (len : size   -> @a[:])
        generic slgrow  : (sl : @a[:]#, len : size  -> @a[:])
        generic slzgrow : (sl : @a[:]#, len : size  -> @a[:])
        generic slfree  : (sl : @a[:]   -> void)
        const bytealloc : (sz:size  -> byte#)
        const zbytealloc    : (sz:size  -> byte#)
        const bytefree  : (m:byte#, sz:size -> void)
;;

generic mk  : (val : @a -> @a#)

mk creates a shallow copy of variable passed to it on the heap, returning a pointer to the value that it allocated. It is conventionally used for creating new copies of larger complex data structures, although it can be used to heapify any value.

Returns: Pointer to fully initialized value of type '@a', based on the value passed in.

generic alloc   : (     -> @a#)
generic zalloc  : (     -> @a#)

alloc allocates or free a single element of type @a, respectively. zalloc does the same, but zeros the memory allocated before returning it. free is used to return the memory allocated by these functions to the system. In general, mk is preferred over these functions, as it does not leave any values uninitialized.,

generic slalloc : (len : size   -> @a[:])
generic slzalloc    : (len : size   -> @a[:])

slalloc allocates or frees a slice of len items of type @a. slzalloc does the same, but zeros the memory allocated before returning it. slfree is used to return the memory to the system.

generic slgrow  : (sl : @a[:]#, len : size  -> @a[:])
generic slzgrow : (sl : @a[:]#, len : size  -> @a[:])

slgrow resizes the slize sl to length len, allocating the appropriate amount of memory. slzgrow does the same, but any elements between the old and new length are zeroed, as in slzalloc.

generic free    : (v:@a#    -> void)
generic slfree  : (sl : @a[:]   -> void)

free and slfree free the storage allocated allocated for the value or slice passed to them , allowing it to be reused again later in the program. This memory may be unmapped and returned to the operating system, or it may be cached within the program.

Any uses of memory after a free call is invalid.

const bytealloc : (sz:size  -> byte#)
const zbytealloc    : (sz:size  -> byte#)
const bytefree  : (m:byte#, sz:size -> void)

bytealloc bytezalloc, and bytefree are the low level raw-byte allocation interface, returning blobs of bytes. Since the only way to use more than one of these bytes is to cast to a different type, the generic versions are generally a better choice.

Examples

Overall, the examples here should not be unfamiliar to anyone who has used either C or C++.

Mk

std.mk should be used to create new, fully constructed values wherever possible. The code for this looks like:

Alloc and Zalloc

alloc and zalloc know the type that they're being assigned to, and use this to calulate the size to allocate:

Slalloc and Slzalloc

slalloc and slzalloc take a size to allocate, but infer the type similar to alloc and zalloc. They're freed with std.slfree() and slzfree(). Thankfully, unlike C++ delete and delete[], it's impossible to pass a slice to the wrong free function.

Growing slices can be done using slgrow() and slzgrow():