Creating Stable Types of Getfield Calls Using Generated Functions

I would like to be able to create a dispatch for a custom type that will essentially make an inplace copy. However, I would like to do it in a stable way, and therefore I would like not to use getfielddirectly, but instead try to use the generated function. Is it possible for type type

type UserType{T}
  x::Vector{T}
  y::Vector{T}
  z::T
end

to generate some function

recursivecopy!(A::UserType,B::UserType)
  # Do it for x
  if typeof(A.x) <: AbstractArray
    recursivecopy!(A.x,B.x)
  else
    A.x = B.x
  end
  # Now for y
  if typeof(A.y) <: AbstractArray
    recursivecopy!(A.y,B.y)
  else
    A.y = B.y
  end
  # Now for z
  if typeof(A.z) <: AbstractArray
    recursivecopy!(A.z,B.z)
  else
    A.z = B.z
  end
end

recursivecopy!in RecursiveArrayTools.jl makes this handle a nested ( Vector{Vector}) type, but the only problem is that I don’t know the fields that the user will have beforehand, only at compile time when this function is called. Sounds like work for the generated functions, but I'm not quite sure how to do this.

+4
1

, getfield setfield. , . , , ... for.

, , , - , getfield:

julia> immutable A
           x::Int
           y::Float64
       end

julia> @generated function f(x)
           args = [:(getfield(x, $i)) for i=1:nfields(x)]
           :(tuple($(args...)))
       end
f (generic function with 1 method)

julia> f(A(1,2.4))
(1,2.4)

julia> @code_warntype f(A(1,2.4))
Variables:
  #self#::#f
  x::A

Body:
  begin  # line 2:
      return (Main.tuple)((Main.getfield)(x::A,1)::Int64,(Main.getfield)(x::A,2)::Float64)::Tuple{Int64,Float64}
  end::Tuple{Int64,Float64}

, , .

julia> type B
           x::Int
           y::Float64
       end
julia> @generated function f!{T}(dest::T, src::T)
           assignments = [:(setfield!(dest, $i, getfield(src, $i))) for i=1:nfields(T)]
           :($(assignments...); dest)
       end
f! (generic function with 1 method)

julia> f!(B(0,0), B(1, 2.4))
B(1,2.4)

julia> @code_warntype f!(B(0,0), B(1, 2.4))
Variables:
  #self#::#f!
  dest::B
  src::B

Body:
  begin  # line 2:
      (Main.setfield!)(dest::B,1,(Main.getfield)(src::B,1)::Int64)::Int64
      (Main.setfield!)(dest::B,2,(Main.getfield)(src::B,2)::Float64)::Float64
      return dest::B
  end::B

, , , . for. .

+5

Source: https://habr.com/ru/post/1669013/


All Articles