Skip to content

Commit 49c463b

Browse files
committed
Add isonebased trait to opt-out of OffsetArray wrappers
1 parent 1cae070 commit 49c463b

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

src/OffsetArrays.jl

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,35 @@ end
317317

318318
Base.similar(A::OffsetArray, ::Type{T}, dims::Dims) where T =
319319
similar(parent(A), T, dims)
320+
321+
"""
322+
isonebased(ax::AbstractUnitRange{<:Integer})
323+
324+
Return whether `firstindex(ax)` is statically known to be `1`. Custom axis types may extend this method
325+
to ensure that the axis offset is ignored, for example in `similar`.
326+
"""
327+
isonebased(_) = false
328+
isonebased(::Integer) = true
329+
isonebased(::Base.OneTo) = true
330+
isonebased(::IIUR{<:Base.OneTo}) = true
331+
332+
to_length(i::Integer) = i
333+
to_length(i::AbstractUnitRange) = length(i)
334+
335+
# Since the following is committing type-piracy, we provide an opt-out mechanism to the users
320336
function Base.similar(A::AbstractArray, ::Type{T}, shape::Tuple{OffsetAxisKnownLength,Vararg{OffsetAxisKnownLength}}) where T
321-
# strip IdOffsetRanges to extract the parent range and use it to generate the array
322-
new_shape = map(_strip_IdOffsetRange, shape)
323-
# route through _similar_axes_or_length to avoid a stack overflow if map(_strip_IdOffsetRange, shape) === shape
324-
# This tries to use new_shape directly in similar if similar(A, T, ::typeof(new_shape)) is defined
325-
# If this fails, it calls similar(A, T, map(_indexlength, new_shape)) to use the size along each axis
326-
# to generate the new array
327-
P = _similar_axes_or_length(A, T, new_shape, shape)
328-
return OffsetArray(P, map(_offset, axes(P), shape))
337+
if all(isonebased, shape)
338+
return similar(A, T, map(to_length, shape))
339+
else
340+
# strip IdOffsetRanges to extract the parent range and use it to generate the array
341+
new_shape = map(_strip_IdOffsetRange, shape)
342+
# route through _similar_axes_or_length to avoid a stack overflow if map(_strip_IdOffsetRange, shape) === shape
343+
# This tries to use new_shape directly in similar if similar(A, T, ::typeof(new_shape)) is defined
344+
# If this fails, it calls similar(A, T, map(_indexlength, new_shape)) to use the size along each axis
345+
# to generate the new array
346+
P = _similar_axes_or_length(A, T, new_shape, shape)
347+
return OffsetArray(P, map(_offset, axes(P), shape))
348+
end
329349
end
330350
Base.similar(::Type{A}, sz::Tuple{Vararg{Int}}) where {A<:OffsetArray} = similar(Array{eltype(A)}, sz)
331351
function Base.similar(::Type{T}, shape::Tuple{OffsetAxisKnownLength,Vararg{OffsetAxisKnownLength}}) where {T<:AbstractArray}
@@ -699,11 +719,11 @@ no_offset_view(a::Array) = a
699719
no_offset_view(i::Number) = i
700720
no_offset_view(A::AbstractArray) = _no_offset_view(axes(A), A)
701721
_no_offset_view(::Tuple{}, A::AbstractArray{T,0}) where T = A
702-
_no_offset_view(::Tuple{Base.OneTo, Vararg{Base.OneTo}}, A::AbstractArray) = A
703-
# the following method is needed for ambiguity resolution
704-
_no_offset_view(::Tuple{Base.OneTo, Vararg{Base.OneTo}}, A::AbstractUnitRange) = A
705-
_no_offset_view(::Any, A::AbstractArray) = OffsetArray(A, Origin(1))
706-
_no_offset_view(::Any, A::AbstractUnitRange) = UnitRange(A)
722+
function _no_offset_view(ax::Tuple, A::AbstractArray)
723+
all(isonebased, ax) ? A : __no_offset_view(A)
724+
end
725+
__no_offset_view(A::AbstractArray) = OffsetArray(A, Origin(1))
726+
__no_offset_view(A::AbstractUnitRange) = UnitRange(A)
707727

708728
#####
709729
# center/centered

0 commit comments

Comments
 (0)