# Memory allocation

In Forth, memory allocated with "allot" and the "," family of words can't be
reclaimed except through "forget", which has limited applications. This kind of
allocation is thus for data that has a permanent lifetime.

To manage data with temporary and semi-tempory lifetimes, different mechanisms
need to be used.

## Static allocation

Static allocation is the simplest:

    create mybuf 42 allot

"mybuf" can now be used to store your temporary data while you work on it. If
this kind of allocation fits your constraints, it's the best way to proceed.

## Dynamic allocation

Dusk has 3 ways of dynamically allocating memory:

1. Scratchpad for short-lived allocations [doc/mem/scratch]
2. Arena for groups of allocations that have more or less the same lifetime
   [doc/mem/arena]
3. malloc for the rest [doc/mem/malloc].

## Allocator API

All dynamic allocators mentioned above are struct that extend the Allocator
struct which provides a common API.

:ensure ( n self -- a )
  Ensure that the allocator has at least "n" bytes of contiguous memory
  available. If not, do its "thing" (rollover, create a new arena, etc.). Return
  the (still unallocated!) address of that memory.

  That address is always aligned to 4 bytes.

  If permanent memory has to be allocated to provide that memory, "realallot"
  [doc/mem/here] is used,

:allot ( n self -- a )
  allocate n bytes in the allocator and return the address of the allocated
  memory space.

  That address is always aligned to 4 bytes.

:allot0 ( n self -- a )
  Same as :allot, but initialize the memory to 0.

:move ( src u self -- a )
  allocate u bytes and copy the range "src u" into it. Then, return the
  allocated memory space.

:[]>str ( a u self -- str )
  allocate u bytes and copy that range to it as an encoded string, then return
  that string.

:[ ( sz self -- )
  reserve sz bytes (we don't allocate it yet, but we ensure that there's at
  least that many bytes left in the buffer) and make "here" point to
  that reserved buffer. From that point on, all "write" words will write to that
  buffer. When you're finished, call :]

:] ( self -- a )
  finalize a :[ operation by allocating the actual number of bytes that were
  written to "here". If that number was less than reserved, we only allocate
  that lesser size. If it was higher, we error out (you never want to go over
  that limit because that means corrupting your system memory). Restore "here"
  to the value it had before the :[ call. Then, return the memory address of the
  allocated memory.

:, ( n self -- a )
  shortcut for "4 :[ , :]"

:s, ( str self -- a )
  write string str to the allocator and return the resulting address.

:entry ( payloadsz 'dict name self -- payload )
  Write a new dictionary entry (see "entry" in [doc/dict] for the meaning of
  "'dict" and "name") using memory from the allocator. Moreover, pre-allocate
  "payloadsz" in addition to the entry, ensuring that the entry and the payload
  will always be adjacent in memory. Yields the address of the first byte of
  the payload.

:freesz ( self -- sz )
  number of bytes left in the buffer before it "does its thing".

:alignto ( n self -- )
  Make it so all further allocations of this allocator will be aligned to "n",
  which must be a power of 2. By default, an allocator aligns to 4 bytes.

## Other words in the unit

alignn ( n -- )
  Align here to n bytes, n being a power of 2.

## C API

Allocator API can be exposed to C by loading mem/alloc.h, which add these
functions:

int alloc_allot(int self, uint n) --> :allot
