|
27 | 27 | getfield(v,:data)[i]
|
28 | 28 | end
|
29 | 29 |
|
| 30 | +# copied from `jl_is_layout_opaque`, |
| 31 | +# which is not available for use becaused marked as static inline. |
| 32 | +function is_layout_opaque(@nospecialize(T::DataType)) |
| 33 | + layout = unsafe_load(convert(Ptr{Base.DataTypeLayout}, T.layout)) |
| 34 | + layout.nfields == 0 && layout.npointers > 0 |
| 35 | +end |
| 36 | +is_layout_opaque(T) = true |
| 37 | + |
30 | 38 | @propagate_inbounds function setindex!(v::MArray, val, i::Int)
|
31 | 39 | @boundscheck checkbounds(v,i)
|
32 | 40 | T = eltype(v)
|
33 | 41 |
|
34 | 42 | if isbitstype(T)
|
35 | 43 | GC.@preserve v unsafe_store!(Base.unsafe_convert(Ptr{T}, pointer_from_objref(v)), convert(T, val), i)
|
| 44 | + elseif isconcretetype(T) && ismutabletype(T) && !is_layout_opaque(T) |
| 45 | + # The tuple contains object pointers. |
| 46 | + # Replace the pointer at `i` by that of the new mutable value. |
| 47 | + GC.@preserve v begin |
| 48 | + data_ptr = Ptr{UInt}(pointer_from_objref(v)) |
| 49 | + value_ptr = Ptr{UInt}(pointer_from_objref(val)) |
| 50 | + unsafe_store!(data_ptr, value_ptr, i) |
| 51 | + end |
36 | 52 | else
|
37 |
| - # This one is unsafe (#27) |
38 |
| - # unsafe_store!(Base.unsafe_convert(Ptr{Ptr{Nothing}}, pointer_from_objref(v.data)), pointer_from_objref(val), i) |
39 |
| - error("setindex!() with non-isbitstype eltype is not supported by StaticArrays. Consider using SizedArray.") |
| 53 | + # For non-isbitstype immutable data, it is safer to replace the whole `.data` field directly after update. |
| 54 | + # For more context see #27. |
| 55 | + updated = Base.setindex(v.data, convert(T, val), i) |
| 56 | + v.data = updated |
40 | 57 | end
|
41 | 58 |
|
42 | 59 | return v
|
|
0 commit comments