|
| 1 | +# Recursively return x + f(y), where y is active, otherwise x |
| 2 | + |
| 3 | +@inline function recursive_add( |
| 4 | + x::T, |
| 5 | + y::T, |
| 6 | + f::F = identity, |
| 7 | + forcelhs::F2 = guaranteed_const, |
| 8 | +) where {T,F,F2} |
| 9 | + if forcelhs(T) |
| 10 | + return x |
| 11 | + end |
| 12 | + splatnew(T, ntuple(Val(fieldcount(T))) do i |
| 13 | + Base.@_inline_meta |
| 14 | + prev = getfield(x, i) |
| 15 | + next = getfield(y, i) |
| 16 | + recursive_add(prev, next, f, forcelhs) |
| 17 | + end) |
| 18 | +end |
| 19 | + |
| 20 | +@inline function recursive_add( |
| 21 | + x::T, |
| 22 | + y::T, |
| 23 | + f::F = identity, |
| 24 | + forcelhs::F2 = guaranteed_const, |
| 25 | +) where {T<:AbstractFloat,F,F2} |
| 26 | + if forcelhs(T) |
| 27 | + return x |
| 28 | + end |
| 29 | + return x + f(y) |
| 30 | +end |
| 31 | + |
| 32 | +@inline function recursive_add( |
| 33 | + x::T, |
| 34 | + y::T, |
| 35 | + f::F = identity, |
| 36 | + forcelhs::F2 = guaranteed_const, |
| 37 | +) where {T<:Complex,F,F2} |
| 38 | + if forcelhs(T) |
| 39 | + return x |
| 40 | + end |
| 41 | + return x + f(y) |
| 42 | +end |
| 43 | + |
| 44 | +@inline mutable_register(::Type{T}) where {T<:Integer} = true |
| 45 | +@inline mutable_register(::Type{T}) where {T<:AbstractFloat} = false |
| 46 | +@inline mutable_register(::Type{Complex{T}}) where {T<:AbstractFloat} = false |
| 47 | +@inline mutable_register(::Type{T}) where {T<:Tuple} = false |
| 48 | +@inline mutable_register(::Type{T}) where {T<:NamedTuple} = false |
| 49 | +@inline mutable_register(::Type{Core.Box}) = true |
| 50 | +@inline mutable_register(::Type{T}) where {T<:Array} = true |
| 51 | +@inline mutable_register(::Type{T}) where {T} = ismutabletype(T) |
| 52 | + |
| 53 | +# Recursively In-place accumulate(aka +=). E.g. generalization of x .+= f(y) |
| 54 | +@inline function recursive_accumulate(x::Array{T}, y::Array{T}, f::F = identity) where {T,F} |
| 55 | + if !mutable_register(T) |
| 56 | + for I in eachindex(x) |
| 57 | + prev = x[I] |
| 58 | + @inbounds x[I] = recursive_add(x[I], (@inbounds y[I]), f, mutable_register) |
| 59 | + end |
| 60 | + end |
| 61 | +end |
| 62 | + |
| 63 | + |
| 64 | +# Recursively In-place accumulate(aka +=). E.g. generalization of x .+= f(y) |
| 65 | +@inline function recursive_accumulate(x::Core.Box, y::Core.Box, f::F = identity) where {F} |
| 66 | + recursive_accumulate(x.contents, y.contents, seen, f) |
| 67 | +end |
| 68 | + |
| 69 | +@inline function recursive_accumulate(x::T, y::T, f::F = identity) where {T,F} |
| 70 | + @assert !Base.isabstracttype(T) |
| 71 | + @assert Base.isconcretetype(T) |
| 72 | + nf = fieldcount(T) |
| 73 | + |
| 74 | + for i = 1:nf |
| 75 | + if isdefined(x, i) |
| 76 | + xi = getfield(x, i) |
| 77 | + ST = Core.Typeof(xi) |
| 78 | + if !mutable_register(ST) |
| 79 | + @assert ismutable(x) |
| 80 | + yi = getfield(y, i) |
| 81 | + nexti = recursive_add(xi, yi, f, mutable_register) |
| 82 | + setfield!(x, i, nexti) |
| 83 | + end |
| 84 | + end |
| 85 | + end |
| 86 | +end |
0 commit comments