-
Notifications
You must be signed in to change notification settings - Fork 24
/
cache.rb
143 lines (121 loc) · 3.53 KB
/
cache.rb
1
2
3
4
5
6
7
8
9
10
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
require 'thread'
module ThreadSafe
autoload :JRubyCacheBackend, 'thread_safe/jruby_cache_backend'
autoload :MriCacheBackend, 'thread_safe/mri_cache_backend'
autoload :NonConcurrentCacheBackend, 'thread_safe/non_concurrent_cache_backend'
autoload :AtomicReferenceCacheBackend, 'thread_safe/atomic_reference_cache_backend'
autoload :SynchronizedCacheBackend, 'thread_safe/synchronized_cache_backend'
ConcurrentCacheBackend = if defined?(RUBY_ENGINE)
case RUBY_ENGINE
when 'jruby'; JRubyCacheBackend
when 'ruby'; MriCacheBackend
when 'rbx'; AtomicReferenceCacheBackend
else
warn 'ThreadSafe: unsupported Ruby engine, using a fully synchronized ThreadSafe::Cache implementation' if $VERBOSE
SynchronizedCacheBackend
end
else
MriCacheBackend
end
class Cache < ConcurrentCacheBackend
KEY_ERROR = defined?(KeyError) ? KeyError : IndexError # there is no KeyError in 1.8 mode
def initialize(options = nil, &block)
if options.kind_of?(::Hash)
validate_options_hash!(options)
else
options = nil
end
super(options)
@default_proc = block
end
def [](key)
if value = super
value
elsif @default_proc && !key?(key)
@default_proc.call(self, key)
else
value
end
end
alias_method :get, :[]
alias_method :put, :[]=
def fetch(key, default_value = NULL)
if NULL != (value = get_or_default(key, NULL))
value
elsif block_given?
yield key
elsif NULL != default_value
default_value
else
raise KEY_ERROR, 'key not found'
end
end
def put_if_absent(key, value)
computed = false
result = compute_if_absent(key) do
computed = true
value
end
computed ? nil : result
end unless method_defined?(:put_if_absent)
def value?(value)
each_value do |v|
return true if value.equal?(v)
end
false
end unless method_defined?(:value?)
def keys
arr = []
each_pair {|k, v| arr << k}
arr
end unless method_defined?(:keys)
def values
arr = []
each_pair {|k, v| arr << v}
arr
end unless method_defined?(:values)
def each_key
each_pair {|k, v| yield k}
end unless method_defined?(:each_key)
def each_value
each_pair {|k, v| yield v}
end unless method_defined?(:each_value)
def empty?
each_pair {|k, v| return false}
true
end unless method_defined?(:empty?)
def size
count = 0
each_pair {|k, v| count += 1}
count
end unless method_defined?(:size)
def marshal_dump
raise TypeError, "can't dump hash with default proc" if @default_proc
h = {}
each_pair {|k, v| h[k] = v}
h
end
def marshal_load(hash)
initialize
populate_from(hash)
end
undef :freeze
private
def initialize_copy(other)
super
populate_from(other)
end
def populate_from(hash)
hash.each_pair {|k, v| self[k] = v}
self
end
def validate_options_hash!(options)
if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Fixnum) || initial_capacity < 0)
raise ArgumentError, ":initial_capacity must be a positive Fixnum"
end
if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)
raise ArgumentError, ":load_factor must be a number between 0 and 1"
end
end
end
end