22
33abstract type MethodTableView; end
44
5+ struct MethodLookupResult
6+ # Really Vector{Core.MethodMatch}, but it's easier to represent this as
7+ # and work with Vector{Any} on the C side.
8+ matches:: Vector{Any}
9+ valid_worlds:: WorldRange
10+ ambig:: Bool
11+ end
12+ length (result:: MethodLookupResult ) = length (result. matches)
13+ function iterate (result:: MethodLookupResult , args... )
14+ r = iterate (result. matches, args... )
15+ r === nothing && return nothing
16+ match, state = r
17+ return (match:: MethodMatch , state)
18+ end
19+ getindex (result:: MethodLookupResult , idx:: Int ) = getindex (result. matches, idx):: MethodMatch
20+
21+ struct MethodMatchResult
22+ matches:: MethodLookupResult
23+ overlayed:: Bool
24+ end
25+
526"""
627 struct InternalMethodTable <: MethodTableView
728
@@ -23,25 +44,21 @@ struct OverlayMethodTable <: MethodTableView
2344 mt:: Core.MethodTable
2445end
2546
26- struct MethodLookupResult
27- # Really Vector{Core.MethodMatch}, but it's easier to represent this as
28- # and work with Vector{Any} on the C side.
29- matches:: Vector{Any}
30- valid_worlds:: WorldRange
31- ambig:: Bool
32- end
33- length (result:: MethodLookupResult ) = length (result. matches)
34- function iterate (result:: MethodLookupResult , args... )
35- r = iterate (result. matches, args... )
36- r === nothing && return nothing
37- match, state = r
38- return (match:: MethodMatch , state)
47+ """
48+ struct CachedMethodTable <: MethodTableView
49+
50+ Overlays another method table view with an additional local fast path cache that
51+ can respond to repeated, identical queries faster than the original method table.
52+ """
53+ struct CachedMethodTable{T} <: MethodTableView
54+ cache:: IdDict{Any, Union{Missing, MethodMatchResult}}
55+ table:: T
3956end
40- getindex (result :: MethodLookupResult , idx :: Int ) = getindex (result . matches, idx) :: MethodMatch
57+ CachedMethodTable (table :: T ) where T = CachedMethodTable {T} ( IdDict {Any, Union{Missing, MethodMatchResult}} (), table)
4158
4259"""
4360 findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) ->
44- (matches::MethodLookupResult, overlayed::Bool) or missing
61+ MethodMatchResult (matches::MethodLookupResult, overlayed::Bool) or missing
4562
4663Find all methods in the given method table `view` that are applicable to the given signature `sig`.
4764If no applicable methods are found, an empty result is returned.
@@ -51,7 +68,7 @@ If the number of applicable methods exceeded the specified limit, `missing` is r
5168function findall (@nospecialize (sig:: Type ), table:: InternalMethodTable ; limit:: Int = Int (typemax (Int32)))
5269 result = _findall (sig, nothing , table. world, limit)
5370 result === missing && return missing
54- return result, false
71+ return MethodMatchResult ( result, false )
5572end
5673
5774function findall (@nospecialize (sig:: Type ), table:: OverlayMethodTable ; limit:: Int = Int (typemax (Int32)))
@@ -60,18 +77,20 @@ function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int
6077 nr = length (result)
6178 if nr ≥ 1 && result[nr]. fully_covers
6279 # no need to fall back to the internal method table
63- return result, true
80+ return MethodMatchResult ( result, true )
6481 end
6582 # fall back to the internal method table
6683 fallback_result = _findall (sig, nothing , table. world, limit)
6784 fallback_result === missing && return missing
6885 # merge the fallback match results with the internal method table
69- return MethodLookupResult (
70- vcat (result. matches, fallback_result. matches),
71- WorldRange (
72- max (result. valid_worlds. min_world, fallback_result. valid_worlds. min_world),
73- min (result. valid_worlds. max_world, fallback_result. valid_worlds. max_world)),
74- result. ambig | fallback_result. ambig), ! isempty (result)
86+ return MethodMatchResult (
87+ MethodLookupResult (
88+ vcat (result. matches, fallback_result. matches),
89+ WorldRange (
90+ max (result. valid_worlds. min_world, fallback_result. valid_worlds. min_world),
91+ min (result. valid_worlds. max_world, fallback_result. valid_worlds. max_world)),
92+ result. ambig | fallback_result. ambig),
93+ ! isempty (result))
7594end
7695
7796function _findall (@nospecialize (sig:: Type ), mt:: Union{Nothing,Core.MethodTable} , world:: UInt , limit:: Int )
@@ -85,6 +104,17 @@ function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable},
85104 return MethodLookupResult (ms:: Vector{Any} , WorldRange (_min_val[], _max_val[]), _ambig[] != 0 )
86105end
87106
107+ function findall (@nospecialize (sig:: Type ), table:: CachedMethodTable ; limit:: Int = typemax (Int))
108+ if isconcretetype (sig)
109+ # as for concrete types, we cache result at on the next level
110+ return findall (sig, table. table; limit)
111+ end
112+ box = Core. Box (sig)
113+ return get! (table. cache, sig) do
114+ findall (box. contents, table. table; limit)
115+ end
116+ end
117+
88118"""
89119 findsup(sig::Type, view::MethodTableView) ->
90120 (match::MethodMatch, valid_worlds::WorldRange, overlayed::Bool) or nothing
@@ -129,6 +159,10 @@ function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable},
129159 return match, valid_worlds
130160end
131161
162+ # This query is not cached
163+ findsup (@nospecialize (sig:: Type ), table:: CachedMethodTable ) = findsup (sig, table. table)
164+
132165isoverlayed (:: MethodTableView ) = error (" unsatisfied MethodTableView interface" )
133166isoverlayed (:: InternalMethodTable ) = false
134167isoverlayed (:: OverlayMethodTable ) = true
168+ isoverlayed (mt:: CachedMethodTable ) = isoverlayed (mt. table)
0 commit comments