# `QuakeC`
[🔗](https://github.com/jaman/cauldron/blob/v0.2.2/quake_c/lib/quake_c.ex#L1)

A QuakeC program's memory: its globals, and every entity's fields laid end to end, as
the program addresses them.

Values are floats, integers (entity numbers, function indices, string offsets, field
offsets and pointers), or binaries for strings made while running. A slot never written
is `0`.

A pointer is a byte address: global slot `n` is at `4 * n`, field slot `f` of entity
`e` at `field_base() + 4 * (e * entity_fields + f)`, and memory from `alloc/2` at
`heap_base()` and up. `load/2` and `store/3` read and write through one.

Writes take effect in place (`QuakeC.Memory`): every copy of the struct sees them.
`copy/1` gives memory written apart from the original. The memory belongs to the
process that made it (`new/1`), works from any process while that process lives, and
`release/1` frees it sooner.

    qc = QuakeC.new(progs)
    QuakeC.put_global(qc, "time", 1.5)
    QuakeC.field(qc, 1, "origin")

# `t`

```elixir
@type t() :: %QuakeC{
  blocks: term(),
  field_offsets: term(),
  fields: term(),
  global_offsets: term(),
  globals: term(),
  heap: term(),
  heap_top: term(),
  progs: term(),
  size: term(),
  spare: term()
}
```

# `value`

```elixir
@type value() :: number() | binary()
```

# `vector`

```elixir
@type vector() :: {float(), float(), float()}
```

# `alloc`

```elixir
@spec alloc(t(), non_neg_integer()) :: {t(), pos_integer()}
```

`bytes` of fresh zeroed memory, rounded up to whole words: the memory and its address.

# `clear_entity`

```elixir
@spec clear_entity(t(), non_neg_integer()) :: t()
```

Every field of `entity` set back to zero.

# `copy`

```elixir
@spec copy(t()) :: t()
```

Memory holding the same values as `qc`, written apart from it.

# `field`

```elixir
@spec field(t(), non_neg_integer(), String.t()) :: value()
```

Field `name` of `entity`; `0` when the program has no such field.

# `field_address`

```elixir
@spec field_address(t(), non_neg_integer(), non_neg_integer()) :: pos_integer()
```

The address of field slot `offset` of `entity`.

# `field_base`

```elixir
@spec field_base() :: pos_integer()
```

The address of field slot 0 of entity 0.

# `field_offset`

```elixir
@spec field_offset(t(), String.t()) :: non_neg_integer() | nil
```

The offset of field `name`, or `nil` when the program has none.

# `field_slot`

```elixir
@spec field_slot(t(), non_neg_integer(), non_neg_integer()) :: value()
```

Field slot `offset` of `entity`.

# `field_type`

```elixir
@spec field_type(t(), String.t()) :: atom() | nil
```

The type of field `name`, or `nil`.

# `field_vector`

```elixir
@spec field_vector(t(), non_neg_integer(), String.t()) :: vector()
```

Vector field `name` of `entity`.

# `fill`

```elixir
@spec fill(t(), integer(), non_neg_integer(), number()) :: t()
```

Write integer or float `value` into `words` words from address `address`.

# `float`

```elixir
@spec float(value()) :: float()
```

A value as a float.

# `free`

```elixir
@spec free(t(), integer()) :: t()
```

Give back memory `alloc/2` handed out at `address`; any other address is left alone.

# `global`

```elixir
@spec global(t(), String.t()) :: value()
```

The global named `name`.

# `global?`

```elixir
@spec global?(t(), String.t()) :: boolean()
```

Whether the program has a global `name`.

# `global_vector`

```elixir
@spec global_vector(t(), String.t()) :: vector()
```

The vector global named `name`.

# `heap_base`

```elixir
@spec heap_base() :: pos_integer()
```

The address of the first word `alloc/2` hands out.

# `load`

```elixir
@spec load(t(), integer()) :: value()
```

The value at address `address`; an address outside every space reads `0`.

# `move`

```elixir
@spec move(t(), integer(), integer(), non_neg_integer()) :: t()
```

Copy `words` words from address `from` to address `to`, as they stood before the copy;
the ranges may overlap. Words from below address 0 read `0`; a copy to an address
outside every space raises.

# `new`

```elixir
@spec new(QuakeC.Progs.t()) :: t()
```

Fresh memory for `progs`: its initial globals, every entity field zero.

# `put_declared`

```elixir
@spec put_declared(t(), String.t(), value() | vector()) :: t()
```

Set the global named `name` when the program declares one; otherwise leave the memory as it is.

# `put_field`

```elixir
@spec put_field(t(), non_neg_integer(), String.t(), value() | vector()) :: t()
```

Set field `name` of `entity`; a vector sets three slots. A field the program lacks is left alone.

# `put_field_slot`

```elixir
@spec put_field_slot(t(), non_neg_integer(), non_neg_integer(), value()) :: t()
```

Set field slot `offset` of `entity`.

# `put_global`

```elixir
@spec put_global(t(), String.t(), value() | vector()) :: t()
```

Set the global named `name`; a vector sets three slots.

# `put_slot`

```elixir
@spec put_slot(t(), non_neg_integer(), value()) :: t()
```

Set global slot `offset`.

# `put_slot_vector`

```elixir
@spec put_slot_vector(t(), non_neg_integer(), vector()) :: t()
```

Set the three slots from `offset`.

# `release`

```elixir
@spec release(t()) :: :ok
```

Free `qc`'s memory (`QuakeC.Memory.delete/1`); neither it nor any copy may be used after.

# `slot`

```elixir
@spec slot(t(), non_neg_integer()) :: value()
```

The global slot `offset`.

# `slot_vector`

```elixir
@spec slot_vector(t(), non_neg_integer()) :: vector()
```

The three slots from `offset` as a vector.

# `store`

```elixir
@spec store(t(), integer(), value()) :: t()
```

Write `value` at address `address`.

# `string`

```elixir
@spec string(t(), value()) :: String.t()
```

A string value as text: an offset into the program's strings, or a made string.

# `update_slot`

```elixir
@spec update_slot(t(), non_neg_integer(), value()) :: :ok | t()
```

Set global slot `offset`: `:ok` when only the memory's words changed, or the memory to
use from then on (`QuakeC.Memory.put/3`).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
