Skip to content

Commit eec806a

Browse files
committed
Allow cache module to be given in RGF constructor
This exposes the full constructor (without the need for specifying module tags), as we seem to need this for utility functions which want to cache the RGF in a user-specified module.
1 parent 076d6df commit eec806a

File tree

5 files changed

+59
-33
lines changed

5 files changed

+59
-33
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "RuntimeGeneratedFunctions"
22
uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47"
33
authors = ["Chris Rackauckas <accounts@chrisrackauckas.com> and contributors"]
4-
version = "0.5.0"
4+
version = "0.5.1"
55

66
[deps]
77
ExprTools = "e2ba6199-217a-4e67-a87a-7c52f15ade04"

src/RuntimeGeneratedFunctions.jl

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,15 @@ module RuntimeGeneratedFunctions
22

33
using ExprTools, Serialization, SHA
44

5-
export @RuntimeGeneratedFunction
5+
export RuntimeGeneratedFunction, @RuntimeGeneratedFunction
66

77

8-
"""
9-
RuntimeGeneratedFunction
10-
11-
This type should be constructed via the macro @RuntimeGeneratedFunction.
12-
"""
13-
struct RuntimeGeneratedFunction{argnames, cache_tag, context_tag, id} <: Function
14-
body::Expr
15-
function RuntimeGeneratedFunction(cache_tag, context_tag, ex)
16-
def = splitdef(ex)
17-
args, body = normalize_args(def[:args]), def[:body]
18-
id = expr_to_id(body)
19-
cached_body = _cache_body(cache_tag, id, body)
20-
new{Tuple(args), cache_tag, context_tag, id}(cached_body)
21-
end
22-
end
23-
248
"""
259
@RuntimeGeneratedFunction(function_expression)
2610
@RuntimeGeneratedFunction(context_module, function_expression)
2711
12+
RuntimeGeneratedFunction(cache_module, context_module, function_expression)
13+
2814
Construct a function from `function_expression` which can be called immediately
2915
without world age problems. Somewhat like using `eval(function_expression)` and
3016
then calling the resulting function. The differences are:
@@ -40,6 +26,11 @@ If provided, `context_module` is module in which symbols within
4026
`function_expression` will be looked up. By default this is module in which
4127
`@RuntimeGeneratedFunction` is expanded.
4228
29+
`cache_module` is the module where the expression `code` will be cached. If
30+
`RuntimeGeneratedFunction` is used during precompilation, this must be a module
31+
which is currently being precompiled. Normally this would be set to
32+
`@__MODULE__` using one of the macro constructors.
33+
4334
# Examples
4435
```
4536
RuntimeGeneratedFunctions.init(@__MODULE__) # Required at module top-level
@@ -51,28 +42,46 @@ function foo()
5142
end
5243
```
5344
"""
54-
macro RuntimeGeneratedFunction(code)
55-
_RGF_constructor_code(:(@__MODULE__), esc(code))
56-
end
57-
macro RuntimeGeneratedFunction(context_module, code)
58-
_RGF_constructor_code(esc(context_module), esc(code))
45+
struct RuntimeGeneratedFunction{argnames, cache_tag, context_tag, id} <: Function
46+
body::Expr
47+
function RuntimeGeneratedFunction(cache_tag, context_tag, ex)
48+
def = splitdef(ex)
49+
args, body = normalize_args(def[:args]), def[:body]
50+
id = expr_to_id(body)
51+
cached_body = _cache_body(cache_tag, id, body)
52+
new{Tuple(args), cache_tag, context_tag, id}(cached_body)
53+
end
5954
end
6055

61-
function _RGF_constructor_code(context_module, code)
62-
quote
63-
code = $code
64-
cache_module = @__MODULE__
65-
context_module = $context_module
66-
if #==# !isdefined(cache_module, $(QuoteNode(_tagname))) ||
67-
!isdefined(context_module, $(QuoteNode(_tagname)))
68-
init_mods = unique([context_module, cache_module])
56+
function _check_rgf_initialized(mods...)
57+
for mod in mods
58+
if !isdefined(mod, _tagname)
6959
error("""You must use `RuntimeGeneratedFunctions.init(@__MODULE__)` at module
70-
top level before using runtime generated functions in $init_mods""")
60+
top level before using runtime generated functions in $mod""")
7161
end
72-
RuntimeGeneratedFunction(cache_module.$_tagname, context_module.$_tagname, $code)
7362
end
7463
end
7564

65+
function RuntimeGeneratedFunction(cache_module::Module, context_module::Module, code)
66+
_check_rgf_initialized(cache_module, context_module)
67+
RuntimeGeneratedFunction(getfield(cache_module, _tagname),
68+
getfield(context_module, _tagname), code)
69+
end
70+
71+
macro RuntimeGeneratedFunction(code)
72+
quote
73+
RuntimeGeneratedFunction(@__MODULE__, @__MODULE__, $(esc(code)))
74+
end
75+
end
76+
macro RuntimeGeneratedFunction(context_module, code)
77+
quote
78+
RuntimeGeneratedFunction(@__MODULE__, $(esc(context_module)), $(esc(code)))
79+
end
80+
end
81+
82+
# Duplicate RuntimeGeneratedFunction docs onto @RuntimeGeneratedFunction
83+
@eval @doc $(@doc RuntimeGeneratedFunction) var"@RuntimeGeneratedFunction"
84+
7685
function Base.show(io::IO, ::MIME"text/plain", f::RuntimeGeneratedFunction{argnames, cache_tag, context_tag, id}) where {argnames,cache_tag,context_tag,id}
7786
cache_mod = parentmodule(cache_tag)
7887
context_mod = parentmodule(context_tag)

test/precomp/RGFPrecompTest.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module RGFPrecompTest
22
using RuntimeGeneratedFunctions
3+
using RGFPrecompTest2
34
RuntimeGeneratedFunctions.init(@__MODULE__)
45

56
f = @RuntimeGeneratedFunction(:((x,y)->x+y))
7+
8+
g = RGFPrecompTest2.generate_rgf(@__MODULE__)
69
end

test/precomp/RGFPrecompTest2.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module RGFPrecompTest2
2+
using RuntimeGeneratedFunctions
3+
RuntimeGeneratedFunctions.init(@__MODULE__)
4+
5+
y_in_RGFPrecompTest2 = 2
6+
7+
# Simulates a helper function which generates an RGF, but caches it in a
8+
# different module.
9+
function generate_rgf(cache_module)
10+
context_module = @__MODULE__
11+
RuntimeGeneratedFunction(cache_module, @__MODULE__, :((x)->y_in_RGFPrecompTest2+x))
12+
end
13+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ push!(LOAD_PATH, joinpath(@__DIR__, "precomp"))
8383
using RGFPrecompTest
8484

8585
@test RGFPrecompTest.f(1,2) == 3
86+
@test RGFPrecompTest.g(40) == 42
8687

8788
# Test that RuntimeGeneratedFunction with identical body expressions (but
8889
# allocated separately) don't clobber each other when one is GC'd.

0 commit comments

Comments
 (0)