Luke Gorrie wrote: > Can someone tell me if this is a good implementation, or how to > do it better? local function protected(type, base, offset, size) type = ffi.typeof(type) local bound = (size + 0ULL) / ffi.sizeof(type) local tptr = ffi.typeof("$ *", type) local wrap = ffi.metatype(ffi.typeof("struct { $ _ptr; }", tptr), { __index = function(w, idx) assert(idx < bound) return w._ptr[idx] end, __newindex = function(w, idx, val) assert(idx < bound) w._ptr[idx] = val end, }) return wrap(ffi.cast(tptr, ffi.cast("uint8_t *", base) + offset)) end This generates machine code that would be identical with e.g. C++ bounds checking templates. Here's a simple test: local mem = ffi.new("int32_t[400]") local t = protected("int32_t", mem, 0, 400*4) for i=0,399 do t[i] = i end for i=0,399 do assert(t[i] == i) end And here's the machine code of the two inner loops: ->LOOP: 394cffe0 cmp rbp, 0x190 Bounds check 394cffe7 jnb 0x394c0024 ->5 394cffed mov [rax+rbp*4], ebp Store 394cfff0 add ebp, +0x01 Loop counter 394cfff3 cmp ebp, 0x18f 394cfff9 jle 0x394cffe0 ->LOOP ->LOOP: 394cff20 cmp rbp, 0x190 Bounds check 394cff27 jnb 0x394c002c ->7 394cff2d cmp ebp, [rcx+rbp*4] Load + assert 394cff30 jnz 0x394c0030 ->8 394cff36 add ebp, +0x01 Loop counter 394cff39 cmp ebp, 0x18f 394cff3f jle 0x394cff20 ->LOOP Note that the array bound has been constified and that a single unsigned compare is sufficient. [BTW: Avoid uint32_t as far as possible in FFI code. int32_t is almost always a better choice.] --Mike