Hey! I ran into some trouble while cleaning up my wrapper of a C library for GBA development.
One of the things that the library exposes is a 2D array which maps out several chunks of 512 tiles (a.k.a. charblocks) in video memory.
type
Tile* {.importc: "TILE4", header: "tonc.h", completeStruct.} = object
data*: array[8, uint32]
Charblock* = array[512, Tile]
var tileMem* {.importc:"tile_mem", header: "tonc.h".}: array[4, Charblock]
## BG charblocks, 4bpp tiles.
## ::
## tileMemBlocks[i] # charblock i (Tile array)
## tileMemBlocks[i][j] # charblock i, tile j (Tile)
However, tile indexes in the GBA are 10 bits (values from 0..1023), which means in practise that tileMem[0][1000] is a perfectly valid access. It's expected that you'll reach outside the bounds of the array into the next one.
This has not caused issues for me yet because I always compile with checks disabled. I would like to make it possible to enable checks, for debug builds and such.
So I'm looking for a way to disable bounds checks on the Charblock type. I can't use UncheckedArray because I still want to retain the length/size info.
There used to be an {.unchecked.} pragma but it was removed from the language. I found an alternative which might work... But it's looking pretty ugly...
type Charblock = distinct array[512, Tile]
proc `[]`(a: var Charblock, i: int): var Tile {.inline.} =
cast[ptr UncheckedArray[Tile]](addr a)[i]
proc `[]=`(a: var Charblock, i: int, v: Tile) {.inline.} =
cast[ptr UncheckedArray[Tile]](addr a)[i] = v
converter toArray(a: var Charblock): var array[512, Tile] =
cast[ptr array[512, Tile]](addr a)[]
Does anyone know if there's something I could do to simplify this?
Is there any other way to selectively disable bounds checks?
Is there a chance of the unchecked pragma making a comeback in the future?
Thanks :)
Model it as
type
Charblock* = array[512*8, uint32]
and then have accessors that support a 3D view into the array.