hamster 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 / 2009-10-21
2
+
3
+ * Initial version
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Simon Harris
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ = Hamster
2
+
3
+ Hash Array Mapped Tries (HAMT) for Ruby.
4
+
5
+ See http://lamp.epfl.ch/papers/idealhashtrees.pdf
@@ -0,0 +1,5 @@
1
+ Dir["tasks/**/*.rb"].each do |task_file|
2
+ require task_file
3
+ end
4
+
5
+ task :default => [ :spec ]
data/TODO ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ require 'hamster/entry'
2
+ require 'hamster/trie'
3
+ require 'hamster/version'
@@ -0,0 +1,18 @@
1
+ module Hamster
2
+
3
+ class Entry
4
+
5
+ attr_reader :key, :value
6
+
7
+ def initialize(key, value)
8
+ @key = key
9
+ @value = value
10
+ end
11
+
12
+ def has_key?(key)
13
+ @key == key
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,101 @@
1
+ module Hamster
2
+
3
+ class Trie
4
+
5
+ include Enumerable
6
+
7
+ def initialize(significant_bits = 0)
8
+ @significant_bits = significant_bits
9
+ @entries = []
10
+ @children = []
11
+ end
12
+
13
+ # Returns the number of key-value pairs in the trie.
14
+ def size
15
+ # TODO: This definitely won't scale!
16
+ to_a.size
17
+ end
18
+
19
+ # Returns <tt>true</tt> if the trie contains no key-value pairs.
20
+ def empty?
21
+ size == 0
22
+ end
23
+
24
+ # Returns <tt>true</tt> if the given key is present in the trie.
25
+ def has_key?(key)
26
+ !! get(key)
27
+ end
28
+
29
+ # Calls <tt>block</tt> once for each key in the trie, passing the key-value pair as parameters.
30
+ # Returns <tt>self</tt>
31
+ def each
32
+ block_given? or return enum_for(__method__)
33
+ @entries.each { |entry| yield entry.key, entry.value if entry }
34
+ @children.each do |child|
35
+ child.each { |key, value| yield key, value } if child
36
+ end
37
+ self
38
+ end
39
+
40
+ # Returns a copy of <tt>self</tt> with given value associated with the key.
41
+ def put(key, value)
42
+ dup.put!(key, value)
43
+ end
44
+
45
+ # Associates the given value with the key and returns <tt>self</tt>
46
+ def put!(key, value)
47
+ index = index_for(key)
48
+ entry = @entries[index]
49
+ if entry && !entry.has_key?(key)
50
+ child = @children[index]
51
+ @children[index] = if child
52
+ child.put(key, value)
53
+ else
54
+ self.class.new(@significant_bits + 5).put!(key, value)
55
+ end
56
+ else
57
+ @entries[index] = Entry.new(key, value)
58
+ end
59
+ self
60
+ end
61
+
62
+ # Retrieves the value corresponding to the given key. If not found, returns <tt>nil</tt>.
63
+ def get(key)
64
+ index = index_for(key)
65
+ entry = @entries[index]
66
+ if entry
67
+ if entry.has_key?(key)
68
+ entry.value
69
+ else
70
+ child = @children[index]
71
+ child.get(key) if child
72
+ end
73
+ end
74
+ end
75
+
76
+ # Returns a copy of <tt>self</tt> with the given key/value pair removed. If not found, returns <tt>self</tt>.
77
+ def remove(key)
78
+ has_key?(key) or return self
79
+ dup.remove!(key)
80
+ end
81
+
82
+ # Removes the given key/value pair and returns <tt>self</tt>
83
+ def remove!(key)
84
+ self
85
+ end
86
+
87
+ private
88
+
89
+ def initialize_copy(other)
90
+ @significant_bits = other.instance_eval{@significant_bits}
91
+ @entries = other.instance_eval{@entries}.dup
92
+ @children = other.instance_eval{@children}.dup
93
+ end
94
+
95
+ def index_for(key)
96
+ (key.hash.abs >> @significant_bits) & 31
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,5 @@
1
+ module Hamster
2
+
3
+ VERSION = "0.1.0".freeze
4
+
5
+ end
@@ -0,0 +1,266 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Hamster
4
+
5
+ describe Trie do
6
+
7
+ before do
8
+ @expected_pairs = {}
9
+ @trie = Trie.new
10
+ ("A".."Z").each do |letter|
11
+ @expected_pairs.store(letter, letter.downcase)
12
+ @trie = @trie.put(letter, letter.downcase)
13
+ end
14
+ end
15
+
16
+ it "returns values associated with existing keys" do
17
+ @expected_pairs.each do |key, value|
18
+ @trie.get(key).should == value
19
+ end
20
+ end
21
+
22
+ it "is Enumerable" do
23
+ Trie.is_a?(Enumerable)
24
+ end
25
+
26
+ describe "#empty?" do
27
+
28
+ it "initially returns true" do
29
+ Trie.new.should be_empty
30
+ end
31
+
32
+ it "returns false once items have been added" do
33
+ @trie.should_not be_empty
34
+ end
35
+
36
+ end
37
+
38
+ describe "#each" do
39
+
40
+ describe "with a block (internal iteration)" do
41
+
42
+ it "returns self" do
43
+ @trie.each {}.should == @trie
44
+
45
+ end
46
+
47
+ it "yields all key value pairs" do
48
+ actual_pairs = {}
49
+ @trie.each do |key, value|
50
+ actual_pairs[key] = value
51
+ end
52
+ actual_pairs.should == @expected_pairs
53
+ end
54
+
55
+ end
56
+
57
+ describe "with no block (external iteration)" do
58
+
59
+ it "returns an enumerator over all key value pairs" do
60
+ actual_pairs = {}
61
+ enum = @trie.each
62
+ loop do
63
+ key, value = enum.next
64
+ actual_pairs[key] = value
65
+ end
66
+ actual_pairs.should == @expected_pairs
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ describe "#get" do
74
+
75
+ it "returns values associated with existing keys" do
76
+ @expected_pairs.each do |key, value|
77
+ @trie.get(key).should == value
78
+ end
79
+ end
80
+
81
+ it "returns nil for non-existing" do
82
+ @trie.get("missing").should be_nil
83
+ end
84
+
85
+ end
86
+
87
+ describe "#has_key?" do
88
+
89
+ it "returns true for existing keys" do
90
+ @expected_pairs.each_key do |key|
91
+ @trie.has_key?(key).should be_true
92
+ end
93
+ end
94
+
95
+ it "returns false for non-existing keys" do
96
+ @trie.has_key?("missing").should be_false
97
+ end
98
+
99
+ end
100
+
101
+ describe "#put" do
102
+
103
+ describe "with key/value pairs that already exists" do
104
+
105
+ before do
106
+ @copy = @trie.put("J", "jay")
107
+ end
108
+
109
+ it "returns a modified copy" do
110
+ @copy.should_not === @trie
111
+ end
112
+
113
+ describe "the original" do
114
+
115
+ it "returns values associated with existing keys" do
116
+ @expected_pairs.each do |key, value|
117
+ @trie.get(key).should == value
118
+ end
119
+ end
120
+
121
+ it "has the original size" do
122
+ @trie.size.should == @expected_pairs.size
123
+ end
124
+
125
+ end
126
+
127
+ describe "the modified copy" do
128
+
129
+ it "has the new key/value pair" do
130
+ @copy.get("J").should == "jay"
131
+ end
132
+
133
+ it "has the original size" do
134
+ @trie.size.should == @expected_pairs.size
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
141
+ describe "with key/value pairs that don't exist"
142
+
143
+ before do
144
+ @copy = @trie.put("missing", "in action")
145
+ end
146
+
147
+ it "returns a modified copy" do
148
+ @copy.should_not === @trie
149
+ end
150
+
151
+ describe "the original" do
152
+
153
+ it "returns values associated with existing keys" do
154
+ @expected_pairs.each do |key, value|
155
+ @trie.get(key).should == value
156
+ end
157
+ end
158
+
159
+ it "doesn't contain the new key/value pair" do
160
+ @trie.has_key?("missing").should be_false
161
+ end
162
+
163
+ it "has the original size" do
164
+ @trie.size.should == @expected_pairs.size
165
+ end
166
+
167
+ end
168
+
169
+ describe "the modified copy" do
170
+
171
+ it "returns values associated with existing keys" do
172
+ @expected_pairs.each do |key, value|
173
+ @copy.get(key).should == value
174
+ end
175
+ end
176
+
177
+ it "has the new key/value pair" do
178
+ @copy.get("missing").should == "in action"
179
+ end
180
+
181
+ it "size is increased by 1" do
182
+ @copy.size.should == @expected_pairs.size + 1
183
+ end
184
+
185
+ end
186
+
187
+ end
188
+
189
+ describe "#remove" do
190
+
191
+ describe "with existing keys" do
192
+
193
+ before do
194
+ @copy = @trie.remove("J")
195
+ end
196
+
197
+ it "returns a modified copy" do
198
+ @copy.should_not === @trie
199
+ end
200
+
201
+ describe "the original" do
202
+
203
+ it "returns values associated with existing keys" do
204
+ @expected_pairs.each do |key, value|
205
+ @trie.get(key).should == value
206
+ end
207
+ end
208
+
209
+ it "has the original size" do
210
+ @trie.size.should == @expected_pairs.size
211
+ end
212
+
213
+ end
214
+
215
+ describe "the modified copy" do
216
+
217
+ it "doesn't have the removed key" do
218
+ @copy.has_key?("J").should be_false
219
+ end
220
+
221
+ it "returns values associated with all but the removed key" do
222
+ @expected_pairs.each do |key, value|
223
+ next if key == "J"
224
+ @copy.get(key).should == value
225
+ end
226
+ end
227
+
228
+ it "has one less than the original" do
229
+ @copy.size.should == @expected_pairs.size - 1
230
+ end
231
+
232
+ end
233
+
234
+ end
235
+
236
+ describe "with non-existing keys" do
237
+
238
+ before do
239
+ @copy = @trie.remove("missing")
240
+ end
241
+
242
+ it "returns self" do
243
+ @copy.should === @trie
244
+ end
245
+
246
+ describe "the original" do
247
+
248
+ it "returns values associated with existing keys" do
249
+ @expected_pairs.each do |key, value|
250
+ @trie.get(key).should == value
251
+ end
252
+ end
253
+
254
+ it "has the original size" do
255
+ @trie.size.should == @expected_pairs.size
256
+ end
257
+
258
+ end
259
+
260
+ end
261
+
262
+ end
263
+
264
+ end
265
+
266
+ end
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --loadby random
3
+ --backtrace
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+
3
+ # Support running specs with "rake spec" and "spec"
4
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ require 'hamster'
@@ -0,0 +1,6 @@
1
+ require "spec/rake/spectask"
2
+
3
+ desc "Run specifications"
4
+ Spec::Rake::SpecTask.new(:spec) do |t|
5
+ t.spec_opts << "--options" << "spec/spec.opts" if File.exists?("spec/spec.opts")
6
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hamster
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Harris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-23 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Hash Array Mapped Tries (HAMT) for Ruby
17
+ email: haruki.zaemon@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - History.rdoc
25
+ - TODO
26
+ - LICENSE
27
+ files:
28
+ - lib/hamster/entry.rb
29
+ - lib/hamster/trie.rb
30
+ - lib/hamster/version.rb
31
+ - lib/hamster.rb
32
+ - spec/hamster/trie_spec.rb
33
+ - spec/spec.opts
34
+ - spec/spec_helper.rb
35
+ - tasks/spec.rb
36
+ - Rakefile
37
+ - README.rdoc
38
+ - History.rdoc
39
+ - TODO
40
+ - LICENSE
41
+ has_rdoc: true
42
+ homepage: http://github.com/harukizaemon/hamster
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.5
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Hash Array Mapped Tries (HAMT) for Ruby
69
+ test_files: []
70
+