Skip to content

Commit 0e2c552

Browse files
Merge pull request #26 from c42f/cjf/cache-module-in-constructor
Allow cache module to be given in RGF constructor
2 parents 076d6df + eec806a commit 0e2c552

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)