Buffer protocol for DiscreteMap (np.asarray zero-copy) #334

Closed
opened 2026-07-02 12:29:40 +00:00 by john · 0 comments
Owner

From the 2026-07-02 memory-model review. Additive, tiny, and the template for all later buffer work.

Current state

DiscreteMap is already the right shape: dense uint8_t* with a data() accessor, and it exports the codebase's only zero-copy window today -- mask() -> PyMemoryView_FromMemory(values, w*h, PyBUF_WRITE) (src/PyDiscreteMap.cpp:1315-1317). But there is no tp_as_buffer anywhere in the codebase (only .tp_as_buffer = NULL at src/McRFPy_API.cpp:250), so np.asarray(dmap) fails; users must know the np.frombuffer(dmap.mask()).reshape(h, w) incantation.

Proposal

Implement tp_as_buffer (getbufferproc/releasebufferproc) on PyDiscreteMap producing a 2-D C-contiguous uint8 buffer, shape (h, w), writable. Then np.asarray(entity.perspective_map) is a zero-copy live view. Keep mask()/to_bytes()/from_bytes() for compatibility.

DiscreteMap has no dirty flags, so this sidesteps the bulk-edit-convention decision (#328) -- which is exactly why it should go first. Entity perspective (0=unknown/1=discovered/2=visible, src/UIEntity.h:75-80) becomes directly consumable as an RL observation plane.

Related: #55, #154, #156 (agent-simulation motivation); multi-root Dijkstra already consumes dmap->data->data() internally (src/UIGridPathfinding.cpp:857-878).

From the 2026-07-02 memory-model review. Additive, tiny, and the template for all later buffer work. ## Current state `DiscreteMap` is already the right shape: dense `uint8_t*` with a `data()` accessor, and it exports the codebase's **only** zero-copy window today -- `mask()` -> `PyMemoryView_FromMemory(values, w*h, PyBUF_WRITE)` (`src/PyDiscreteMap.cpp:1315-1317`). But there is no `tp_as_buffer` anywhere in the codebase (only `.tp_as_buffer = NULL` at `src/McRFPy_API.cpp:250`), so `np.asarray(dmap)` fails; users must know the `np.frombuffer(dmap.mask()).reshape(h, w)` incantation. ## Proposal Implement `tp_as_buffer` (getbufferproc/releasebufferproc) on `PyDiscreteMap` producing a 2-D C-contiguous uint8 buffer, shape `(h, w)`, writable. Then `np.asarray(entity.perspective_map)` is a zero-copy live view. Keep `mask()`/`to_bytes()`/`from_bytes()` for compatibility. DiscreteMap has no dirty flags, so this sidesteps the bulk-edit-convention decision (#328) -- which is exactly why it should go first. Entity perspective (0=unknown/1=discovered/2=visible, `src/UIEntity.h:75-80`) becomes directly consumable as an RL observation plane. Related: #55, #154, #156 (agent-simulation motivation); multi-root Dijkstra already consumes `dmap->data->data()` internally (`src/UIGridPathfinding.cpp:857-878`).
john closed this issue 2026-07-11 14:42:07 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#334
No description provided.