From 58076584ab90e76902301193969a43bedd9f2fe1 Mon Sep 17 00:00:00 2001 From: Stefan Karpinski Date: Thu, 2 Oct 2014 16:03:03 -0400 Subject: [PATCH 1/3] deepcopy: recurse through immutable objects with mutable fields. --- base/deepcopy.jl | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index d96c36637c7a7..bc0ec967381e5 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -27,20 +27,23 @@ function deepcopy_internal(x, stackdict::ObjectIdDict) end function _deepcopy_t(x, T::DataType, stackdict::ObjectIdDict) - if T.names===() || !T.mutable - return x - end - ret = ccall(:jl_new_struct_uninit, Any, (Any,), T) - stackdict[x] = ret - for i in 1:length(T.names) - if isdefined(x,i) - ret.(i) = deepcopy_internal(x.(i), stackdict) + isempty(T.names) && return x + if T.mutable + y = ccall(:jl_new_struct_uninit, Any, (Any,), T) + stackdict[x] = y + for i in 1:length(T.names) + if isdefined(x,i) + y.(i) = deepcopy_internal(x.(i), stackdict) + end end + else + fields = Any[deepcopy_internal(x.(i), stackdict) for i in 1:length(T.names)] + y = ccall(:jl_new_structv, Any, (Any, Ptr{Void}, Uint32), + T, pointer(fields), length(fields)) end - return ret + return y::T end - function deepcopy_internal(x::Array, stackdict::ObjectIdDict) if haskey(stackdict, x) return stackdict[x] From 8b0d0f6fb69b219622f2f731efddf6f9f2f628ab Mon Sep 17 00:00:00 2001 From: Stefan Karpinski Date: Thu, 2 Oct 2014 17:18:22 -0400 Subject: [PATCH 2/3] deepcopy optimization: return bits types immediately. --- base/deepcopy.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index bc0ec967381e5..07e7add299cf2 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -27,7 +27,7 @@ function deepcopy_internal(x, stackdict::ObjectIdDict) end function _deepcopy_t(x, T::DataType, stackdict::ObjectIdDict) - isempty(T.names) && return x + isbits(T) | isempty(T.names) && return x if T.mutable y = ccall(:jl_new_struct_uninit, Any, (Any,), T) stackdict[x] = y From 4837f35ef3989076853220919d9e843a786befed Mon Sep 17 00:00:00 2001 From: Stefan Karpinski Date: Fri, 3 Oct 2014 00:12:55 -0400 Subject: [PATCH 3/3] deepcopy: update NEWS.md and docs. --- NEWS.md | 3 ++- doc/stdlib/base.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 38c0ef5c93bdf..87637f3a9d4c0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -55,8 +55,9 @@ Library improvements * New `Nullable` type for missing data ([#8152]). - * New ordschur and ordschur! functions for sorting a schur factorization by the eigenvalues + * New `ordschur` and `ordschur!` functions for sorting a schur factorization by the eigenvalues. + * `deepcopy` recurses through immutable types and makes copies of their mutable fields ([#8560]). Julia v0.3.0 Release Notes ========================== diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 7102958db9e0a..f02a30ee0a421 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -219,7 +219,7 @@ All Objects .. function:: deepcopy(x) - Create a deep copy of ``x``: everything is copied recursively, resulting in a fully independent object. For example, deep-copying an array produces a new array whose elements are deep-copies of the original elements. + Create a deep copy of ``x``: everything is copied recursively, resulting in a fully independent object. For example, deep-copying an array produces a new array whose elements are deep copies of the original elements. Calling `deepcopy` on an object should generally have the same effect as serializing and then deserializing it. As a special case, functions can only be actually deep-copied if they are anonymous, otherwise they are just copied. The difference is only relevant in the case of closures, i.e. functions which may contain hidden internal references.