What is the most idiomatic way to implement bounds checking in `getindex` for arbitrary types?

loonatick-src
Fri, 17 Feb 2023 09:17:41 +0000
General Usage

Specifically, I have two main requirements in mind.

1. It should throw BoundsError with complete information.

2. The @inbounds macro should work as intended for this type, i.e. elide the bounds checking entirely

Item 1 seems straightforward, just conditionally throw a BoundsError with the right arguments. But, it seems that I am not sure about item 2; how does one check if @inbounds is bypassing bounds checking in the first place? I tried using @code_warntype and friends on @inbounds foo[i] where foo isa Foo, but it seems to give info about the operations of the inbounds macro itself.

A toy example.

struct Foo{T}
    x::Vector{T}
    y::Vector{Int}
end

import Base.getindex

function Base.getindex(f::Foo{T}, i::Int) where {T}
    idx = f.y[i]
    if idx  > length(f.x)
        throw(BoundsError(x, idx))
    end
    f.x[idx]
end

How can one transform this code to make @inbounds work as intended, and how does one check if it is working as intended?

4 posts - 3 participants