# `nupp.mem.heap` Owned, malloc-backed C arrays. The returned array is affine and is released with `free` at scope exit. Its logical element count moves with the allocation and its pointer is available only through checked span views. ```nupp local heap = nupp.mem.heap do local values = heap.allocate(ffi.typeof(), 4) local writable = values:write() writable[1] = 42 as int32 drop writable local readable = values:read() print(readable[1], #readable) end -- free runs here ``` An allocation here sits outside LuaJIT's GC allocation limit, which is the reason to reach for one over a `carray`. Reading and writing are the operations `nupp.mem.span` defines, and a live reader and a live writer over one array report `NUPP2607`. ::: tip Nonescaping views at -O1 A nonescaping `read` or `write` can remain virtual, so no span wrapper is allocated. An escape or an opaque call materializes the same checked span. ::: See [c-interop.md](../../../../learn/runtime/c-interop/index.html#c-arrays) for how this sits beside `carray`, and [ownership.md](../../../../learn/runtime/ownership/borrowing/index.html) for the borrow rules the views are written against. ## Types ### `Array` _record_ ```nupp record heap.Array is heap.ArrayToken readonly count: integer drop: nosuspend function(takes self: Array): nil close: nosuspend function(takes self: Array): nil read: function(borrows self: Array): span.Span borrows (self) write: function(exclusive self: Array): span.Writable borrows (self) end ``` An owned contiguous native allocation whose logical count cannot be separated from its pointer in checked code. #### Type parameters | Name | Description | | --- | --- | | `T` | | #### Methods ##### `drop` ```nupp drop: nosuspend function(takes self: Array): nil ``` Releases the allocation. Scope exit invokes this automatically. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `takes self` | `Array\` | | ###### Returns | Type | Description | | --- | --- | | `nil` | | ##### `close` ```nupp close: nosuspend function(takes self: Array): nil ``` Frees the allocation. `drop` and scope exit both reach this. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `takes self` | `Array\` | | ###### Returns | Type | Description | | --- | --- | | `nil` | | ##### `read` ```nupp read: function(borrows self: Array): span.Span borrows (self) ``` Borrows the whole allocation as a shared checked span. The borrow lasts as long as the span does, so a writer cannot be taken out while one is live. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `borrows self` | `Array\` | | ###### Returns | Type | Description | | --- | --- | | `span.Span\ borrows (self)` | | ##### `write` ```nupp write: function(exclusive self: Array): span.Writable borrows (self) ``` Borrows the whole allocation as an affine checked write span. Exclusive for as long as the writer is live, so `read` reports `NUPP2607` until the writer is dropped. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `exclusive self` | `Array\` | | ###### Returns | Type | Description | | --- | --- | | `span.Writable\ borrows (self)` | | #### Fields ##### `count` ```nupp count: integer ``` How many elements the allocation holds. ### `ArrayToken` _interface_ ```nupp sealed interface heap.ArrayToken close: nosuspend function(takes self: ArrayToken): nil end ``` #### Methods ##### `close` ```nupp close: nosuspend function(takes self: ArrayToken): nil ``` ###### Arguments | Name | Type | Description | | --- | --- | --- | | `takes self` | `ArrayToken` | | ###### Returns | Type | Description | | --- | --- | | `nil` | | ## Functions ### `heap.allocate` _function_ ```nupp function heap.allocate(element: ctype, count: integer): affine(heap.Array, heap.destroyArray) ``` Allocates `count` contiguous values of `element` outside LuaJIT's GC allocation limit. The result owns the allocation and frees it at its lexical boundary. The bytes are not zeroed, so a program that reads before it writes reads whatever was there. ```nupp do local values = heap.allocate(ffi.typeof(), 1000000) print(values.count) end ``` #### Type parameters | Name | Description | | --- | --- | | `T` | | #### Arguments | Name | Type | Description | | --- | --- | --- | | `element` | `ctype\` | the ctype of one element | | `count` | `integer` | how many elements to allocate | #### Returns | Type | Description | | --- | --- | | `affine(heap.Array\, heap.destroyArray)` | the array, owned by the caller | #### Raises - when count is negative, the byte size overflows a Lua integer, or malloc fails ### `heap.destroyArray` _function_ ```nupp function heap.destroyArray(takes self: T): nil ``` Frees an allocation, which is what every heap array's contract names. Nothing calls this by hand. It is the terminal consumer `affine` carries, so a scope boundary or an explicit `drop` reaches it. #### Type parameters | Name | Description | | --- | --- | | `T` | | #### Arguments | Name | Type | Description | | --- | --- | --- | | `takes self` | `T` | the array, spent by this call | #### Returns | Type | Description | | --- | --- | | `nil` | |