@@ -34,11 +34,16 @@ function Base.similar(A::NamedArrayPartition)
3434 )
3535end
3636
37- # return ArrayPartition when possible, otherwise next best thing of the correct size
37+ # return NamedArrayPartition when the requested dims still match the partition layout;
38+ # otherwise fall back to the plain backing array of the correct size. ArrayPartition's
39+ # own `similar(A, dims)` already does this degradation (it returns a Vector when
40+ # `dims != size(A)`), and we simply propagate that result instead of trying to
41+ # wrap a non-ArrayPartition in a NamedArrayPartition (which would hit the inner
42+ # constructor signature `NamedArrayPartition(::A<:ArrayPartition, ::NamedTuple)`).
3843function Base. similar (A:: NamedArrayPartition , dims:: NTuple{N, Int} ) where {N}
39- return NamedArrayPartition (
40- similar ( getfield (A, :array_partition ), dims), getfield (A, :names_to_indices )
41- )
44+ inner = similar ( getfield (A, :array_partition ), dims)
45+ inner isa ArrayPartition || return inner
46+ return NamedArrayPartition (inner, getfield (A, :names_to_indices ) )
4247end
4348
4449# similar array partition of common type
4853 )
4954end
5055
51- # return ArrayPartition when possible, otherwise next best thing of the correct size
5256function Base. similar (A:: NamedArrayPartition , :: Type{T} , dims:: NTuple{N, Int} ) where {T, N}
53- return NamedArrayPartition (
54- similar ( getfield (A, :array_partition ), T, dims), getfield (A, :names_to_indices )
55- )
57+ inner = similar ( getfield (A, :array_partition ), T, dims)
58+ inner isa ArrayPartition || return inner
59+ return NamedArrayPartition (inner, getfield (A, :names_to_indices ) )
5660end
5761
5862# similar array partition with different types
@@ -96,6 +100,28 @@ Base.length(x::NamedArrayPartition) = length(ArrayPartition(x))
96100# Use concrete index types to avoid invalidating AbstractArray's generic setindex!.
97101Base. @propagate_inbounds Base. getindex (x:: NamedArrayPartition , i:: Int ) = ArrayPartition (x)[i]
98102Base. @propagate_inbounds Base. setindex! (x:: NamedArrayPartition , v, i:: Int ) = (ArrayPartition (x)[i] = v)
103+
104+ # Indexing with non-scalar indices (UnitRange, Vector{Int}, etc.) goes through
105+ # AbstractArray's generic path, which routes via `similar(A, T, dims)`. NAP's
106+ # `similar(::NAP, T, dims)` cannot in general produce a NamedArrayPartition for
107+ # arbitrary `dims` (the partition layout is fixed by `names_to_indices`), so it
108+ # falls back to a plain Vector — making the inferred return type a small Union.
109+ #
110+ # Mirror ArrayPartition's `_unsafe_getindex` shortcut at `array_partition.jl:317`:
111+ # allocate the destination directly off the first underlying array and fill it
112+ # via `_unsafe_getindex!`. The result is always a Vector for non-scalar indexing,
113+ # so `x[I]` is type-stable. This matches the v3 indexing semantics (`x[1:end]`
114+ # returns a `Vector`, not a `NamedArrayPartition`); use `similar(x)` /
115+ # `copy(x)` if you want a NamedArrayPartition back.
116+ Base. @propagate_inbounds function Base. _unsafe_getindex (
117+ :: IndexStyle , A:: NamedArrayPartition ,
118+ I:: Vararg{Union{Real, AbstractArray}, N}
119+ ) where {N}
120+ shape = Base. index_shape (I... )
121+ dest = similar (getfield (A, :array_partition ). x[1 ], shape)
122+ Base. _unsafe_getindex! (dest, A, I... )
123+ return dest
124+ end
99125function Base. map (f, x:: NamedArrayPartition )
100126 return NamedArrayPartition (map (f, ArrayPartition (x)), getfield (x, :names_to_indices ))
101127end
0 commit comments