Repository: JuliaLang/julia
File: base/reshapedarray.jl (Julia)

Code before:
_checkcontiguous(::Type{Bool}, A::AbstractArray) = false
# `strides(A::DenseArray)` calls `size_to_strides` by default.
# Thus it's OK to assume all `DenseArray`s are contiguously stored.
_checkcontiguous(::Type{Bool}, A::DenseArray) = true
_checkcontiguous(::Type{Bool}, A::ReshapedArray) = _checkcontiguous(Bool, parent(A))
_checkcontiguous(::Type{Bool}, A::FastContiguousSubArray) = _checkcontiguous(Bool, parent(A))

function strides(a::ReshapedArray)
    _checkcontiguous(Bool, a) && return size_to_strides(1, size(a)...)
    apsz::Dims = size(a.parent)
    apst::Dims = strides(a.parent)
    msz, mst, n = merge_adjacent_dim(apsz, apst) # Try to perform "lazy" reshape
    n == ndims(a.parent) && return size_to_strides(mst, size(a)...) # Parent is stridevector like
    return _reshaped_strides(size(a), 1, msz, mst, n, apsz, apst)
end

function _reshaped_strides(::Dims{0}, reshaped::Int, msz::Int, ::Int, ::Int, ::Dims, ::Dims)
    reshaped == msz && return ()
    throw(ArgumentError("Input is not strided."))
end
function _reshaped_strides(sz::Dims, reshaped::Int, msz::Int, mst::Int, n::Int, apsz::Dims, apst::Dims)
    st = reshaped * mst
    reshaped = reshaped * sz[1]
    if length(sz) > 1 && reshaped == msz && sz[2] != 1
        msz, mst, n = merge_adjacent_dim(apsz, apst, n + 1)
        reshaped = 1
    end
    sts = _reshaped_strides(tail(sz), reshaped, msz, mst, n, apsz, apst)
    return (st, sts...)
end

merge_adjacent_dim(::Dims{0}, ::Dims{0}) = 1, 1, 0
merge_adjacent_dim(apsz::Dims{1}, apst::Dims{1}) = apsz[1], apst[1], 1
function merge_adjacent_dim(apsz::Dims{N}, apst::Dims{N}, n::Int = 1) where {N}
    sz, st = apsz[n], apst[n]
    while n < N
        szₙ, stₙ = apsz[n+1], apst[n+1]
        if sz == 1
            sz, st = szₙ, stₙ
        elseif stₙ == st * sz || szₙ == 1
            sz *= szₙ
        else
            break
        end
        n += 1
    end
    return sz, st, n
end


Review comment (suggestion):
I feel like these should be `cconvert(Ptr{S}, parent)` to actually match up the types, but oh well

Code after:
    byte_offset::Int
    cconv_parent::C
end

# Avoid unneeded nesting
function _offset_cconvert(::Type{Ptr{T}}, byte_offset::Int, cconv_parent::OffsetCConvert{T}) where {T}
    _offset_cconvert(
        Ptr{T},
        cconv_parent.byte_offset + byte_offset,
        cconv_parent.cconv_parent,
    )
end
function _offset_cconvert(::Type{Ptr{T}}, byte_offset::Int, cconv_parent::C) where {T,C}
    OffsetCConvert{T,C}(
        byte_offset,
        cconv_parent,
    )
end

function unsafe_convert(::Type{Ptr{S}}, c::OffsetCConvert{T}) where {S, T}
    Ptr{S}(unsafe_convert(Ptr{T}, c.cconv_parent) + c.byte_offset)
end

function cconvert(::Type{Ptr{S}}, V::SubArray{T,N,P,<:Tuple{Vararg{Union{RangeIndex,ReshapedUnitRange}}}}) where {S,T,N,P}
    parent = V.parent
    p = cconvert(Ptr{T}, parent)
    Δmem = if _checkcontiguous(Bool, parent)
        (first_index(V) - firstindex(parent)) * elsize(parent)
    else
        _memory_offset(parent, map(first, V.indices)...)
    end
    _offset_cconvert(
        Ptr{T},
        Int(Δmem),
        p,
    )
end

_checkcontiguous(::Type{Bool}, A::AbstractArray) = false
# `strides(A::DenseArray)` calls `size_to_strides` by default.
# Thus it's OK to assume all `DenseArray`s are contiguously stored.
_checkcontiguous(::Type{Bool}, A::DenseArray) = true
_checkcontiguous(::Type{Bool}, A::ReshapedArray) = _checkcontiguous(Bool, parent(A))
_checkcontiguous(::Type{Bool}, A::FastContiguousSubArray) = _checkcontiguous(Bool, parent(A))

function strides(a::ReshapedArray)
    _checkcontiguous(Bool, a) && return size_to_strides(1, size(a)...)
    apsz::Dims = size(a.parent)
    apst::Dims = strides(a.parent)
    msz, mst, n = merge_adjacent_dim(apsz, apst) # Try to perform "lazy" reshape
    n == ndims(a.parent) && return size_to_strides(mst, size(a)...) # Parent is stridevector like