Memoize 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ == 0.1.0 / 2007-05-25
2
+
3
+ * First release memoized package.
@@ -0,0 +1,7 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/memoize
6
+ lib/memoize.rb
7
+ test/test_memoize.rb
@@ -0,0 +1,48 @@
1
+ Memoize
2
+ by Rakuto Furutani <rakuto@gmail.com>
3
+ Blog: http://rakuto.blogspot.com/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Memoize is implementation Memoization for Ruby, this techinique to make functions faster.
8
+ This memoization library support own storage to save memoized data.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * Memoization - http://en.wikipedia.org/wiki/Memoization
13
+
14
+ == SYNOPSIS:
15
+
16
+
17
+ == REQUIREMENTS:
18
+
19
+ None
20
+
21
+ == INSTALL:
22
+
23
+ % sudo gem install memoize
24
+
25
+ == LICENSE:
26
+
27
+ MIT License
28
+
29
+ Copyright (c) 2007 Rakuto Furutani
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining
32
+ a copy of this software and associated documentation files (the
33
+ 'Software'), to deal in the Software without restriction, including
34
+ without limitation the rights to use, copy, modify, merge, publish,
35
+ distribute, sublicense, and/or sell copies of the Software, and to
36
+ permit persons to whom the Software is furnished to do so, subject to
37
+ the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be
40
+ included in all copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
43
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
47
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
48
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/memoize.rb'
6
+
7
+ Hoe.new('Memoize', Memoize::VERSION) do |p|
8
+ p.rubyforge_name = 'memoize'
9
+ p.summary = 'Make functions faster by Memoization techniques'
10
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
11
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
12
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
13
+ end
14
+
15
+ # vim: syntax=Ruby
File without changes
@@ -0,0 +1,302 @@
1
+ # Memoize is implementation Memoization for Ruby, this techinique to make functions faster.
2
+ #
3
+ # == Caveats:
4
+ # * Do not memoize a function whose behaviou depends on program state.
5
+ # * Do not memoize a function with side effects.
6
+ # * Do not memoize a function that returns a data structure that is modified by it's caller.
7
+ #
8
+ # == See:
9
+ # Memoization - http://en.wikipedia.org/wiki/Memoization
10
+ #
11
+ module Memoize
12
+ VERSION = '0.1.0'
13
+ @@stores = {}
14
+
15
+ # Memoize::Storable class is abstract class. You must implement class which memoization data is saved.
16
+ # This module offer two storage class.
17
+ #
18
+ # * Memoize::MemoryStore -
19
+ # * Memoize::PStore - Persisten cache support.
20
+ #
21
+ class Storable
22
+ # {{{
23
+ attr_accessor :store
24
+
25
+ def initialize(name)
26
+ raise "Memoize::Strable don't instantiage for abstract class."
27
+ end
28
+
29
+ def set(key, value)
30
+ end
31
+
32
+ def get(key)
33
+ end
34
+
35
+ def update(key)
36
+ end
37
+
38
+ def delete(key)
39
+ end
40
+
41
+ def delete_all
42
+ end
43
+ # }}}
44
+ end
45
+
46
+ # MemoryStore is class which store memoization data to memory.
47
+ class MemoryStore < Memoize::Storable
48
+ # {{{
49
+ attr_accessor :store
50
+
51
+ def initialize
52
+ @store = {}
53
+ end
54
+
55
+ def get(key)
56
+ @store[key]
57
+ end
58
+
59
+ def set(key, value)
60
+ @store[key] = value
61
+ end
62
+
63
+ def delete(key)
64
+ @store.delete(key)
65
+ end
66
+
67
+ def delete_all
68
+ @store = {}
69
+ end
70
+ # }}}
71
+ end
72
+
73
+ # PStore is class which store memoization data with local file system.
74
+ # This store class be able to use persistent cache, because this class write out
75
+ # cache data on file when process is exit.
76
+ class PStore < Memoize::MemoryStore
77
+ # {{{
78
+ attr_accessor :store
79
+ PREFIX_SAVE_FILE_DIR = "/tmp"
80
+ SUFFIX_SAVE_FILE_EXT = ".cache"
81
+
82
+ def initialize(name)
83
+ @name = name
84
+ filename = encoded_filename(@name)
85
+ begin
86
+ if File.exists?(filename)
87
+ File.open(filename, "rb") do |io|
88
+ @store = Marshal.load(io)
89
+ end
90
+ else
91
+ @store = {}
92
+ end
93
+ rescue
94
+ @store = {}
95
+ end
96
+ # Write out cache
97
+ at_exit {
98
+ File.open("#{filename}", "wb+") do |io|
99
+ io.flock(File::LOCK_EX)
100
+ Marshal.dump(@store, io)
101
+ io.flock(File::LOCK_UN)
102
+ end
103
+ }
104
+ end
105
+
106
+ # Delete all memoized data and persisten cache fille
107
+ def delete_all
108
+ filename = encoded_filename(@name)
109
+ File.exists?(filename) && File.unlink(filename)
110
+ @store = {}
111
+ end
112
+
113
+ private
114
+ # Get the encoded file name
115
+ def encoded_filename(name)
116
+ File.join(PREFIX_SAVE_FILE_DIR, [name].pack('m').chomp+SUFFIX_SAVE_FILE_EXT)
117
+ end
118
+ # }}}
119
+ end
120
+
121
+ module_function
122
+ # Make memoized function.
123
+ #
124
+ # Parameters:
125
+ # * klass - You must surely specify 'self'. This parameter used to overwrite Toplevell function and
126
+ # register as toplevel function. I need to think better the means ;)
127
+ # * name - an memorized function name.
128
+ # * options - an specify options. <tt>:as</tt> is memorized function name, default is the same second arguments value.
129
+ # <tt>:store</tt> is specify class which store memorized data.
130
+ #
131
+ # == Memoized function examples
132
+ # def fib(n)
133
+ # return 1 if n < 2
134
+ # fib(n-1) + fib(n-2)
135
+ # end
136
+ #
137
+ # end
138
+ # Memoize.register(self, 'fib')
139
+ # fib(30) # => 1346269 fast
140
+ # fib(30) # => 1346269 very fast
141
+ #
142
+ # # Unmemorize
143
+ # Memoize.unmemoize(self, 'fib')
144
+ # fib(30) # => very slow
145
+ #
146
+ # == Memoized one Object methods
147
+ # class Math2
148
+ # def self.fib(N)
149
+ # return 1 if n < 2
150
+ # fib(n-1) + fib(n-2)
151
+ # end
152
+ # end
153
+ #
154
+ # Memoize.memorize(self, 'Math2.fib')
155
+ # Math.fib(30) # => fast
156
+ # Math.fib(30) # => very fast
157
+ # Memoize.unmemoize(self, 'Math2.fib')
158
+ #
159
+ # == Custom storage
160
+ # You can use own memoized data storage, in doing so you must implementaion following method
161
+ #
162
+ # Method/Arity:
163
+ # * initialize/1 - this is constructor
164
+ # * get/1 - an get the cache data with key
165
+ # * set/2 - an set the cache data with key and value
166
+ # * delete/1 - an delete the cache data with key
167
+ # * delete_all/0 - an delete all cache
168
+ #
169
+ # Following class is MemCache storage sample.
170
+ #
171
+ # # Memoized data storage using MemCache
172
+ # require 'memcache'
173
+ #
174
+ # class MemCacheStore < Memoize::Storable
175
+ # attr_accessor :cache, :keys
176
+ # def initialize(name)
177
+ # @keys = []
178
+ # @cache = MemCache.new 'localhost:11211', :namespace => 'rakuto.blogspot.com'
179
+ # end
180
+ #
181
+ # def get(key)
182
+ # @cache.get(key)
183
+ # end
184
+ #
185
+ # def set(key, value)
186
+ # @keys << key unless @keys.include?(key)
187
+ # @cache.set(key, value)
188
+ # end
189
+ #
190
+ # def delete(key)
191
+ # @cache.delete(key)
192
+ # end
193
+ #
194
+ # def delete_all
195
+ # @keys.each { |key| @cache.delete(key) }
196
+ # end
197
+ # end
198
+ #
199
+ # Memoize.register(self, 'fib', :store => MemCacheStore)
200
+ # fib(30) # => fast
201
+ # fib(30) # => fast
202
+ #
203
+ def register(klass, name, options={})
204
+ ns = name.split(/::|\./)
205
+ method, klass = ns.pop, (ns.empty? ? klass : Object.const_get(ns.join("::")))
206
+ store = options[:store].nil? ? PStore.new(name) : options[:store].new(name)
207
+ as_method = options[:as] || method
208
+ Memoize._set_store(name, store)
209
+ (class<<klass;self;end).instance_eval do # for Ruby1.9
210
+ method_name = "#{as_method}_without_memoize"
211
+ memoized_method_name = "#{as_method}_with_memoize"
212
+ define_method(memoized_method_name) do |*args|
213
+ store = Memoize._get_store(name)
214
+ ret = store.get(args)
215
+ if ret.nil?
216
+ ret = send(method_name, *args)
217
+ store.set(args, ret)
218
+ end
219
+ ret
220
+ end
221
+ alias_method method_name, method
222
+ alias_method as_method, memoized_method_name
223
+ end
224
+ end
225
+
226
+ # Specify unmemoize method.
227
+ # If you delete persistent cache when set delete_all true.
228
+ #
229
+ # == Example
230
+ # Memoize.memoize(self, 'slow_func')
231
+ # slow_func(arg)
232
+ # Memoize.unmemoize(self, 'slow_func')
233
+ #
234
+ def unmemoize(klass, name, delete_all=false)
235
+ (class<<klass;self;end).class_eval do
236
+ undef_method("#{name}_with_memoize")
237
+ alias_method name, "#{name}_without_memoize"
238
+ end
239
+ delete_all && @store.delete_all
240
+ end
241
+
242
+ # This method is public, but you don't need call directly.
243
+ def _set_store(name, store)
244
+ @@stores[name] = store
245
+ end
246
+
247
+ # This method is public, but you don't need call directly.
248
+ def _get_store(name)
249
+ @@stores[name]
250
+ end
251
+
252
+ # Not implemented
253
+ module Expire
254
+ end
255
+ end
256
+
257
+ if $0 == __FILE__
258
+ def fib(n)
259
+ return 1 if n < 2
260
+ fib(n-1) + fib(n-2)
261
+ end
262
+
263
+ class Math2
264
+ def self.fib(n)
265
+ return 1 if n < 2
266
+ fib(n-1) + fib(n-2)
267
+ end
268
+ end
269
+
270
+ class MemCacheStore < Memoize::Storable
271
+ attr_accessor :cache, :keys
272
+ def initialize(name)
273
+ @keys = []
274
+ @cache = MemCache.new 'localhost:11211', :namespace => 'rakuto.blogspot.com'
275
+ end
276
+
277
+ def get(key)
278
+ @cache.get(key)
279
+ end
280
+
281
+ def set(key, value)
282
+ @keys << key unless @keys.include?(key)
283
+ @cache.set(key, value)
284
+ end
285
+
286
+ def delete(key)
287
+ @cache.delete(key)
288
+ end
289
+
290
+ def delete_all
291
+ @keys.each { |key| @cache.delete(key) }
292
+ end
293
+ end
294
+
295
+
296
+ Memoize.register(self, 'Math2.fib', :store => MemCacheStore)
297
+ Benchmark.bm do |b|
298
+ b.report("fib(30) with memoize: ") { Math2.fib(30) }
299
+ #Memoize.unmemoize(self, 'fib')
300
+ b.report("fib(30)") { Math2.fib(30) }
301
+ end
302
+ end
@@ -0,0 +1,37 @@
1
+ $: << '../lib/'
2
+ require 'memoize'
3
+ require 'benchmark'
4
+
5
+ def fib(n)
6
+ return 1 if n < 2
7
+ fib(n-1) + fib(n-2)
8
+ end
9
+
10
+ class Math2
11
+ def self.fib(n)
12
+ return 1 if n < 2
13
+ fib(n-1) + fib(n-2)
14
+ end
15
+ end
16
+
17
+ Benchmark.bm do |b|
18
+ b.report("fib(30): ") { fib(30) }
19
+ Memoize.register(self, 'fib')
20
+ b.report("fib(30) with memoize") { fib(30) }
21
+ b.report("fib(30) with memoize") { fib(30) }
22
+ Memoize.unmemoize(self, 'fib')
23
+ end
24
+
25
+ Benchmark.bm do |b|
26
+ Memoize.register(self, 'fib', :as => 'fastfib')
27
+ b.report("fastfib(30) with memoize") { fastfib(30) }
28
+ b.report("fastfib(30) with memoize") { fastfib(30) }
29
+ Memoize.unmemoize(self, 'fastfib')
30
+ end
31
+
32
+ Benchmark.bm do |b|
33
+ b.report("fib(30): ") { Math2.fib(30) }
34
+ Memoize.register(self, 'Math2.fib')
35
+ b.report("fib(30) with memoize") { Math2.fib(30) }
36
+ b.report("fib(30) with memoize") { Math2.fib(30) }
37
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: Memoize
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2007-05-24 00:00:00 +00:00
8
+ summary: Make functions faster by Memoization techniques
9
+ require_paths:
10
+ - lib
11
+ email: ryand-ruby@zenspider.com
12
+ homepage: " by Rakuto Furutani <rakuto@gmail.com>"
13
+ rubyforge_project: memoize
14
+ description: "== FEATURES/PROBLEMS: * Memoization - http://en.wikipedia.org/wiki/Memoization == SYNOPSIS: == REQUIREMENTS: None"
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Ryan Davis
30
+ files:
31
+ - History.txt
32
+ - Manifest.txt
33
+ - README.txt
34
+ - Rakefile
35
+ - bin/memoize
36
+ - lib/memoize.rb
37
+ - test/test_memoize.rb
38
+ test_files:
39
+ - test/test_memoize.rb
40
+ rdoc_options: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ executables:
45
+ - memoize
46
+ extensions: []
47
+
48
+ requirements: []
49
+
50
+ dependencies:
51
+ - !ruby/object:Gem::Dependency
52
+ name: hoe
53
+ version_requirement:
54
+ version_requirements: !ruby/object:Gem::Version::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 1.2.0
59
+ version: