|
| 1 | +using Accessors: @set |
| 2 | +using Dictionaries: Dictionary, set! |
| 3 | +using MacroTools: @capture |
| 4 | +using ..SparseArraysBase: SparseArraysBase, AbstractSparseArray, getindex_zero_function |
| 5 | + |
| 6 | +# TODO: Parametrize by `data`? |
| 7 | +struct SparseArrayDOK{T,N,Zero} <: AbstractSparseArray{T,N} |
| 8 | + data::Dictionary{CartesianIndex{N},T} |
| 9 | + dims::Ref{NTuple{N,Int}} |
| 10 | + zero::Zero |
| 11 | + function SparseArrayDOK{T,N,Zero}(data, dims::NTuple{N,Int}, zero) where {T,N,Zero} |
| 12 | + return new{T,N,Zero}(data, Ref(dims), zero) |
| 13 | + end |
| 14 | +end |
| 15 | + |
| 16 | +# Constructors |
| 17 | +function SparseArrayDOK(data, dims::Tuple{Vararg{Int}}, zero) |
| 18 | + return SparseArrayDOK{eltype(data),length(dims),typeof(zero)}(data, dims, zero) |
| 19 | +end |
| 20 | + |
| 21 | +function SparseArrayDOK{T,N,Zero}(dims::Tuple{Vararg{Int}}, zero) where {T,N,Zero} |
| 22 | + return SparseArrayDOK{T,N,Zero}(default_data(T, N), dims, zero) |
| 23 | +end |
| 24 | + |
| 25 | +function SparseArrayDOK{T,N}(dims::Tuple{Vararg{Int}}, zero) where {T,N} |
| 26 | + return SparseArrayDOK{T,N,typeof(zero)}(dims, zero) |
| 27 | +end |
| 28 | + |
| 29 | +function SparseArrayDOK{T,N}(dims::Tuple{Vararg{Int}}) where {T,N} |
| 30 | + return SparseArrayDOK{T,N}(dims, default_zero()) |
| 31 | +end |
| 32 | + |
| 33 | +function SparseArrayDOK{T}(dims::Tuple{Vararg{Int}}) where {T} |
| 34 | + return SparseArrayDOK{T,length(dims)}(dims) |
| 35 | +end |
| 36 | + |
| 37 | +function SparseArrayDOK{T}(dims::Int...) where {T} |
| 38 | + return SparseArrayDOK{T}(dims) |
| 39 | +end |
| 40 | + |
| 41 | +# Specify zero function |
| 42 | +function SparseArrayDOK{T}(dims::Tuple{Vararg{Int}}, zero) where {T} |
| 43 | + return SparseArrayDOK{T,length(dims)}(dims, zero) |
| 44 | +end |
| 45 | + |
| 46 | +# undef |
| 47 | +function SparseArrayDOK{T,N,Zero}( |
| 48 | + ::UndefInitializer, dims::Tuple{Vararg{Int}}, zero |
| 49 | +) where {T,N,Zero} |
| 50 | + return SparseArrayDOK{T,N,Zero}(dims, zero) |
| 51 | +end |
| 52 | + |
| 53 | +function SparseArrayDOK{T,N}(::UndefInitializer, dims::Tuple{Vararg{Int}}, zero) where {T,N} |
| 54 | + return SparseArrayDOK{T,N}(dims, zero) |
| 55 | +end |
| 56 | + |
| 57 | +function SparseArrayDOK{T,N}(::UndefInitializer, dims::Tuple{Vararg{Int}}) where {T,N} |
| 58 | + return SparseArrayDOK{T,N}(dims) |
| 59 | +end |
| 60 | + |
| 61 | +function SparseArrayDOK{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}) where {T} |
| 62 | + return SparseArrayDOK{T}(dims) |
| 63 | +end |
| 64 | + |
| 65 | +# Axes version |
| 66 | +function SparseArrayDOK{T}( |
| 67 | + ::UndefInitializer, axes::Tuple{Vararg{AbstractUnitRange}} |
| 68 | +) where {T} |
| 69 | + @assert all(isone, first.(axes)) |
| 70 | + return SparseArrayDOK{T}(length.(axes)) |
| 71 | +end |
| 72 | + |
| 73 | +function SparseArrayDOK{T}(::UndefInitializer, dims::Int...) where {T} |
| 74 | + return SparseArrayDOK{T}(dims...) |
| 75 | +end |
| 76 | + |
| 77 | +function SparseArrayDOK{T}(::UndefInitializer, dims::Tuple{Vararg{Int}}, zero) where {T} |
| 78 | + return SparseArrayDOK{T}(dims, zero) |
| 79 | +end |
| 80 | + |
| 81 | +# Base `AbstractArray` interface |
| 82 | +Base.size(a::SparseArrayDOK) = a.dims[] |
| 83 | + |
| 84 | +SparseArraysBase.getindex_zero_function(a::SparseArrayDOK) = a.zero |
| 85 | +function SparseArraysBase.set_getindex_zero_function(a::SparseArrayDOK, f) |
| 86 | + return @set a.zero = f |
| 87 | +end |
| 88 | + |
| 89 | +function SparseArraysBase.setindex_notstored!( |
| 90 | + a::SparseArrayDOK{<:Any,N}, value, I::CartesianIndex{N} |
| 91 | +) where {N} |
| 92 | + set!(SparseArraysBase.sparse_storage(a), I, value) |
| 93 | + return a |
| 94 | +end |
| 95 | + |
| 96 | +function Base.similar(a::SparseArrayDOK, elt::Type, dims::Tuple{Vararg{Int}}) |
| 97 | + return SparseArrayDOK{elt}(undef, dims, getindex_zero_function(a)) |
| 98 | +end |
| 99 | + |
| 100 | +# `SparseArraysBase` interface |
| 101 | +SparseArraysBase.sparse_storage(a::SparseArrayDOK) = a.data |
| 102 | + |
| 103 | +function SparseArraysBase.dropall!(a::SparseArrayDOK) |
| 104 | + return empty!(SparseArraysBase.sparse_storage(a)) |
| 105 | +end |
| 106 | + |
| 107 | +SparseArrayDOK(a::AbstractArray) = SparseArrayDOK{eltype(a)}(a) |
| 108 | + |
| 109 | +SparseArrayDOK{T}(a::AbstractArray) where {T} = SparseArrayDOK{T,ndims(a)}(a) |
| 110 | + |
| 111 | +function SparseArrayDOK{T,N}(a::AbstractArray) where {T,N} |
| 112 | + return SparseArraysBase.sparse_convert(SparseArrayDOK{T,N}, a) |
| 113 | +end |
| 114 | + |
| 115 | +function Base.resize!(a::SparseArrayDOK{<:Any,N}, new_size::NTuple{N,Integer}) where {N} |
| 116 | + a.dims[] = new_size |
| 117 | + return a |
| 118 | +end |
| 119 | + |
| 120 | +function setindex_maybe_grow!(a::SparseArrayDOK{<:Any,N}, value, I::Vararg{Int,N}) where {N} |
| 121 | + if any(I .> size(a)) |
| 122 | + resize!(a, max.(I, size(a))) |
| 123 | + end |
| 124 | + a[I...] = value |
| 125 | + return a |
| 126 | +end |
| 127 | + |
| 128 | +function is_setindex!_expr(expr::Expr) |
| 129 | + return is_assignment_expr(expr) && is_getindex_expr(first(expr.args)) |
| 130 | +end |
| 131 | +is_setindex!_expr(x) = false |
| 132 | + |
| 133 | +is_getindex_expr(expr::Expr) = (expr.head === :ref) |
| 134 | +is_getindex_expr(x) = false |
| 135 | + |
| 136 | +is_assignment_expr(expr::Expr) = (expr.head === :(=)) |
| 137 | +is_assignment_expr(expr) = false |
| 138 | + |
| 139 | +macro maybe_grow(expr) |
| 140 | + if !is_setindex!_expr(expr) |
| 141 | + error( |
| 142 | + "@maybe_grow must be used with setindex! syntax (as @maybe_grow a[i,j,...] = value)" |
| 143 | + ) |
| 144 | + end |
| 145 | + @capture(expr, array_[indices__] = value_) |
| 146 | + return :(setindex_maybe_grow!($(esc(array)), $(esc(value)), $(esc.(indices)...))) |
| 147 | +end |
0 commit comments