1111An array type that stores data as indices of a range.
1212
1313# Fields
14- - `refs::RA<:AbstractArray{<:Any, N}`: an array of indices.
15- - `pool::P<:AbstractRange{T} `: a range that covers all possible values stored by the array.
14+ - `refs::RA<:AbstractArray{R, N}`: an array of indices.
15+ - `pool::P<:AbstractRange`: a range that covers all possible values stored by the array.
1616- `invpool::Dict{T,R}`: a map from array elements to indices of `pool`.
1717"""
1818mutable struct ScaledArray{T,R,N,RA,P} <: AbstractArray{T,N}
1919 refs:: RA
2020 pool:: P
2121 invpool:: Dict{T,R}
22- ScaledArray {T,R,N,RA,P} (rs:: RefArray{RA} , pool:: P , invpool:: Dict{T,R} ) where
23- {T, R, N, RA<: AbstractArray{R, N} , P<: AbstractRange{T} } =
24- new {T,R,N,RA,P} (rs. a, pool, invpool)
22+ function ScaledArray {T,R,N,RA,P} (rs:: RefArray{RA} , pool:: P , invpool:: Dict{T,R} ) where
23+ {T, R, N, RA<: AbstractArray{R, N} , P<: AbstractRange }
24+ eltype (P) == nonmissingtype (T) || throw (ArgumentError (
25+ " expect element type of pool being $(nonmissingtype (T)) ; got $(eltype (P)) " ))
26+ return new {T,R,N,RA,P} (rs. a, pool, invpool)
27+ end
2528end
2629
27- ScaledArray (rs:: RefArray{RA} , pool:: P , invpool:: Dict{T,R} ) where
28- {T,R,RA <: AbstractArray{R} ,P} = ScaledArray {T,R,ndims(RA),RA,P} (rs, pool, invpool)
30+ ScaledArray (rs:: RefArray{RA} , pool:: P , invpool:: Dict{T,R} ) where {T,R,RA <: AbstractArray{R} ,P} =
31+ ScaledArray {T,R,ndims(RA),RA,P} (rs, pool, invpool)
2932
3033const ScaledVector{T,R} = ScaledArray{T,R,1 }
3134const ScaledMatrix{T,R} = ScaledArray{T,R,2 }
3235
33- scale (sa:: ScaledArray ) = step (sa. pool)
36+ const ScaledArrOrSub = Union{ScaledArray, SubArray{<: Any , <: Any , <: ScaledArray }}
37+
38+ scale (sa:: ScaledArrOrSub ) = step (DataAPI. refpool (sa))
3439
3540function _validmin (min, xmin, isstart:: Bool )
3641 if min === nothing
@@ -178,6 +183,14 @@ ScaledArray(sa::ScaledArray, step=nothing; reftype::Type=eltype(refarray(sa)),
178183Base. size (sa:: ScaledArray ) = size (sa. refs)
179184Base. IndexStyle (:: Type{<:ScaledArray{T,R,N,RA}} ) where {T,R,N,RA} = IndexStyle (RA)
180185
186+ Base. similar (sa:: ScaledArray{T,R} , dims:: Dims = size (sa)) where {T,R} =
187+ ScaledArray (RefArray (ones (R, dims)), DataAPI. refpool (sa), Dict {T,R} ())
188+
189+ Base. similar (sa:: SubArray{<:Any, <:Any, <:ScaledArray{T,R}} , dims:: Dims = size (sa)) where {T,R} =
190+ ScaledArray (RefArray (ones (R, dims)), DataAPI. refpool (sa), Dict {T,R} ())
191+
192+ Base. similar (sa:: ScaledArrOrSub , dims:: Int... ) = similar (sa, dims)
193+
181194DataAPI. refarray (sa:: ScaledArray ) = sa. refs
182195DataAPI. refvalue (sa:: ScaledArray , n:: Integer ) = getindex (DataAPI. refpool (sa), n)
183196DataAPI. refpool (sa:: ScaledArray ) = sa. pool
@@ -202,19 +215,51 @@ DataAPI.invrefpool(ssa::SubArray{<:Any, <:Any, <:ScaledArray}) =
202215 return @inbounds pool[n]
203216end
204217
205- @inline function Base. getindex (sa:: ScaledArray , I... )
206- refs = DataAPI. refarray (sa)
207- @boundscheck checkbounds (refs, I... )
208- @inbounds ns = refs[I... ]
218+ Base. @propagate_inbounds function Base. getindex (sa:: ScaledArrOrSub , I:: AbstractVector )
219+ newrefs = DataAPI. refarray (sa)[I]
209220 pool = DataAPI. refpool (sa)
210- N = length (pool)
211- @boundscheck checkindex (Bool, 0 : N, ns) || throw_boundserror (pool, ns)
212- return @inbounds pool[ns]
221+ invpool = DataAPI. invrefpool (sa)
222+ return ScaledArray (RefArray (newrefs), pool, invpool)
223+ end
224+
225+ Base. @propagate_inbounds function Base. setindex! (sa:: ScaledArray , val, ind:: Int )
226+ invpool = DataAPI. invrefpool (sa)
227+ n = get (invpool, val, nothing )
228+ if n === nothing
229+ pool = DataAPI. refpool (sa)
230+ r = first (pool): step (pool): val
231+ last (r) > last (pool) && (sa. pool = r)
232+ n = length (r)
233+ invpool[val] = n
234+ end
235+ refs = DataAPI. refarray (sa)
236+ refs[ind] = n
237+ return sa
238+ end
239+
240+ Base. @propagate_inbounds function Base. setindex! (sa:: ScaledArray , :: Missing , ind:: Int )
241+ refs = DataAPI. refarray (sa)
242+ z = zero (eltype (refs))
243+ invpool = DataAPI. invrefpool (sa)
244+ invpool[missing ] = z
245+ refs[ind] = z
246+ return sa
247+ end
248+
249+ allowmissing (sa:: ScaledArray{T,R} ) where {T,R} =
250+ ScaledArray (RefArray (sa. refs), sa. pool, convert (Dict{Union{T,Missing},R}, sa. invpool))
251+
252+ function disallowmissing (sa:: ScaledArray{T,R} ) where {T,R}
253+ T1 = nonmissingtype (T)
254+ any (x-> iszero (x), sa. refs) && throw (ArgumentError (" cannot convert missing to $T1 " ))
255+ delete! (sa. invpool, missing )
256+ return ScaledArray (RefArray (sa. refs), sa. pool, convert (Dict{T1,R}, sa. invpool))
213257end
214258
215- function Base.:(== )(x:: ScaledArray , y:: ScaledArray )
259+ function Base.:(== )(x:: ScaledArrOrSub , y:: ScaledArrOrSub )
216260 size (x) == size (y) || return false
217- first (x. pool) == first (y. pool) && step (x. pool) == step (y. pool) && return x. refs == y. refs
261+ first (DataAPI. refpool (x)) == first (DataAPI. refpool (y)) &&
262+ scale (x) == scale (y) && return DataAPI. refarray (x) == DataAPI. refarray (y)
218263 eq = true
219264 for (p, q) in zip (x, y)
220265 # missing could arise
0 commit comments