@@ -3,15 +3,29 @@ unrolled_foreach!(f, ::Tuple{}) = nothing
33
44"""
55```julia
6- recursivecopy(a::Union{AbstractArray{T, N}, AbstractVectorOfArray{T, N}} )
6+ recursivecopy(a)
77```
88
99A recursive `copy` function. Acts like a `deepcopy` on arrays of arrays, but
10- like `copy` on arrays of scalars.
11- """
12- function recursivecopy (a)
13- deepcopy (a)
10+ like `copy` on arrays of scalars. For struct types, recursively copies each
11+ field, creating new instances while preserving the struct type.
12+
13+ ## Examples
14+
15+ ```julia
16+ # Basic array copying
17+ arr = [[1, 2], [3, 4]]
18+ copied = recursivecopy(arr) # New arrays at each level
19+
20+ # Struct copying
21+ struct MyStruct
22+ data::Vector{Float64}
23+ metadata::String
1424end
25+ original = MyStruct([1.0, 2.0], "test")
26+ copied = recursivecopy(original) # New struct with new vector
27+ ```
28+ """
1529function recursivecopy (a:: Union {StaticArraysCore. SVector, StaticArraysCore. SMatrix,
1630 StaticArraysCore. SArray, Number})
1731 copy (a)
@@ -35,6 +49,42 @@ function recursivecopy(a::AbstractVectorOfArray)
3549 return b
3650end
3751
52+ function _is_basic_julia_type (T)
53+ # Check if this is a built-in Julia type that we should not handle as a user struct
54+ # We check the module to identify Core/Base types vs user-defined types
55+ mod = Base. parentmodule (T)
56+ return T <: AbstractString || T <: Number || T <: Symbol || T <: Tuple ||
57+ T <: UnitRange || T <: StepRange || T <: Regex ||
58+ T === Nothing || T === Missing ||
59+ mod === Core || mod === Base
60+ end
61+
62+ function recursivecopy (s:: T ) where {T}
63+ # Only handle user-defined immutable structs. Many basic Julia types (String, Symbol,
64+ # Tuple, etc.) are technically structs but should use copy() or return as-is.
65+ if Base. isstructtype (T) && ! _is_basic_julia_type (T)
66+ if Base. ismutabletype (T)
67+ error (" recursivecopy for mutable structs is not currently implemented. Use deepcopy instead." )
68+ else
69+ # Handle immutable structs only
70+ field_values = ntuple (fieldcount (T)) do i
71+ field_value = getfield (s, i)
72+ recursivecopy (field_value)
73+ end
74+ return T (field_values... )
75+ end
76+ elseif _is_basic_julia_type (T)
77+ # For basic Julia types, use copy if available, otherwise return as-is (for immutable types)
78+ if hasmethod (copy, Tuple{T})
79+ return copy (s)
80+ else
81+ return s # Immutable basic types like Symbol, Nothing, Missing don't need copying
82+ end
83+ else
84+ deepcopy (s)
85+ end
86+ end
87+
3888"""
3989```julia
4090recursivecopy!(b::AbstractArray{T, N}, a::AbstractArray{T, N})
0 commit comments