11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
# File 'lib/functor.rb', line 11
def self.included( k )
def k.functor_cache
@functor_cache ||= Hash.new { |hash, key| hash[key] = [ {},{},{},{} ] }
end
def k.functor_cache_config(options={})
@functor_cache_config = ( @functor_cache_config || Functor.cache_config ).merge(options)
end
def k.functor( name, *pattern, &action )
_functor( name, false, *pattern, &action)
end
def k.functor_with_self( name, *pattern, &action )
_functor( name, true, *pattern, &action)
end
def k.method_missing(name, *args)
args.empty? && name.to_s =~ /^_/ ? lambda { |args| true } : super
end
private
def k._functor( name, with_self=false, *pattern, &action)
name = name.to_s
mc = functor_cache[name] cache_size, cache_base = functor_cache_config[:size], functor_cache_config[:base]
c0_size, c1_size, c2_size, c3_size = cache_size * 4, cache_size * 3, cache_size * 2, cache_size
c1_thresh,c2_thresh,c3_thresh = cache_base.to_i, (cache_base ** 2).to_i, (cache_base ** 3).to_i
old_method = instance_method(name) if method_defined?( name ) define_method( name, action ) newest = instance_method(name)
define_method( name ) do | *args |
match_args = with_self ? [self] + args : args
sig = match_args.hash
if meth = mc[3][sig] meth[0].bind(self).call(*args)
elsif meth = mc[2][sig]
meth[1] += 1 mc[3][sig] = mc[2].delete(sig) if meth[1] > c3_thresh (mc[0], mc[1], mc[2], mc[3] = mc[1], mc[2], mc[3], {}) if mc[3].size >= c3_size meth[0].bind(self).call(*args)
elsif meth = mc[1][sig]
meth[1] += 1
mc[2][sig] = mc[1].delete(sig) if meth[1] > c2_thresh
mc[0], mc[1], mc[2] = mc[1], mc[2], {} if mc[2].size >= c2_size
meth[0].bind(self).call(*args)
elsif meth = mc[0][sig]
meth[1] += 1
mc[1][sig] = mc[0].delete(sig) if meth[1] > c1_thresh
mc[0], mc[1] = mc[1], {} if mc[1].size >= c1_size
meth[0].bind(self).call(*args)
elsif Functor.match?(match_args, pattern) (mc[0], mc[1], mc[2], mc[3] = mc[1], mc[2], mc[3], {}) if mc[3].size >= c3_size
mc[3][sig] = [newest, 0] newest.bind(self).call(*args)
elsif old_method old_method.bind(self).call(*args)
else raise NoMatch.new( "No functor matches the given arguments for method :#{name}." )
end
end
end
end
|