# `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` | |