Skip to content

Commit

Permalink
feat: improvepermute_args performance with dynamic eval
Browse files Browse the repository at this point in the history
Rename original one `permute_args_dynamic` with dynamic argument ordering
  • Loading branch information
Beforerr committed Nov 19, 2024
1 parent 8100f3a commit 1beb660
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/PermuteArgs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ using Combinatorics: permutations
export @permute_args, permute_args, permute_args!
include("macro.jl")
include("function.jl")
include("utils.jl")

end
41 changes: 37 additions & 4 deletions src/function.jl
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
inverse_p(p) = ntuple(i -> findfirst(==(i), p), length(p))
"""
permute_args(m::Method; mod=nothing)
Create a new function that allows arbitrary argument order based on the method signature.
If `mod` is not provided, the new function is defined in an anonymous module.
"""
function permute_args(m::Method; mod=nothing)
# Extract the original function and its signature types
mod = something(mod, Module())
sig, fname = m.sig, m.name
func = m.sig.types[1].instance
types = sig.types[2:end] # Exclude the function type itself
n = length(types)

methods = Expr[]
for p in permutations(1:n)
inv_perm = inverse_permutation(p)

args = [Symbol("arg$(i)") for i in 1:n]
typed_args = [:($(args[i])::$(types[p[i]])) for i in 1:n]
reordered_args = [:($(args[inv_perm[i]])) for i in 1:n]

# Define the new method with permuted argument types
new_call = Expr(:call, fname, typed_args...)
func_body = Expr(:call, func, reordered_args...)
method = Expr(:function, new_call, func_body)
push!(methods, method)
end

return Base.eval(mod, Expr(:block, methods...))
end

"""
permute_args(m::Method)
permute_args_dynamic(m::Method)
Create a new function that allows arbitrary argument order based on the method signature.
This returned function is not type-stable and internally uses a lookup table to reorder arguments.
"""
function permute_args(m::Method)
function permute_args_dynamic(m::Method)
types = m.sig.types[2:end]
func = m.sig.types[1].instance
n = length(types)

# Precompute all permutations and their inverse mappings
perms = permutations(1:n)
# Create a lookup dictionary for each permutation
perm_lookups = Tuple((types[p], inverse_p(p)) for p in perms)
perm_lookups = Tuple((types[p], inverse_permutation(p)) for p in perms)

# Create new function with type-stable internals
new_fund_ex = quote
Expand Down
1 change: 1 addition & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
inverse_permutation(p) = ntuple(i -> findfirst(==(i), p), length(p))

1 comment on commit 1beb660

@Beforerr
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to #2

Please sign in to comment.