# `EEVM.Interpreter.Memory`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/interpreter/memory.ex#L1)

EVM memory — a byte-addressable, dynamically expanding linear memory.

Memory expands in 32-byte words. Reads or writes beyond the current size
expand it, and new bytes read as zero. Gas cost increases quadratically with
memory size (see `EEVM.Gas.Memory`).

The contents are stored as 4 KiB binary chunks in a map keyed by chunk index.
Chunks that were never written are absent and read as zeros, so expansion
only bumps `size`. A write rebuilds just the chunks it touches, and reads
slice whole ranges out of the chunks. In `bench/` this beat both a map of
single bytes (the previous layout) and one flat binary, which must copy the
whole buffer on every write and falls far behind once memory grows past a
few KiB.

# `t`

```elixir
@type t() :: %EEVM.Interpreter.Memory{
  data: %{required(non_neg_integer()) =&gt; binary()},
  size: non_neg_integer()
}
```

# `copy`

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

Copies `length` bytes from `src` to `dst` within memory (memmove semantics).

This is the MCOPY operation (EIP-5656). Overlapping regions are handled
correctly because the source is read before anything is written.

# `load`

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

Loads a 256-bit (32-byte) word from the given byte offset.

This is the MLOAD operation. Unwritten bytes read as zero.

# `new`

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

Creates a new empty memory.

# `read_bytes`

```elixir
@spec read_bytes(t(), non_neg_integer(), non_neg_integer()) :: {binary(), t()}
```

Reads a range of bytes from memory as a binary, expanding memory to cover it.

Used by RETURN, REVERT, LOG, KECCAK256, CREATE, and the CALL family.

# `size`

```elixir
@spec size(t()) :: non_neg_integer()
```

Returns the current memory size in bytes (always a multiple of 32).

# `store`

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

Stores a 256-bit (32-byte) word at the given byte offset, big-endian.

This is the MSTORE operation.

# `store_byte`

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

Stores the low byte of `value` at the given offset.

This is the MSTORE8 operation.

# `write_output`

```elixir
@spec write_output(t(), non_neg_integer(), non_neg_integer(), binary()) :: t()
```

Copies a call's `output` into the caller's output area, `size` bytes at `offset`.

Only `min(size, byte_size(output))` bytes are written; the rest of the area keeps
its contents, though memory still expands over all of it, which the CALL already
paid for (execution-specs `generic_call`, `actual_output_size`).

# `write_slice`

```elixir
@spec write_slice(
  t(),
  non_neg_integer(),
  binary(),
  non_neg_integer(),
  non_neg_integer()
) :: t()
```

Writes `length` bytes of `source`, starting at `source_offset`, to memory at
`offset`. Bytes past the end of `source` are written as zero.

These are the semantics of CALLDATACOPY, CODECOPY, EXTCODECOPY, and
RETURNDATACOPY.

---

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