rbtree-pure 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ # :nodoc: namespace
2
+ class RBTree
3
+
4
+ # A node in the red-black tree.
5
+ #
6
+ # Nodes should only be manipulated directly by the RedBlackTree class.
7
+ class Node
8
+ attr_accessor :key
9
+ attr_accessor :value
10
+
11
+ attr_accessor :color
12
+ attr_accessor :left
13
+ attr_accessor :right
14
+ attr_accessor :parent
15
+
16
+ # Creates a new node.
17
+ #
18
+ # New tree nodes are red by default.
19
+ def initialize(key, value, guard)
20
+ @color = :red
21
+ @key = key
22
+ @value = value
23
+ @left = @right = @parent = guard
24
+ end
25
+
26
+ # True for black nodes.
27
+ def black?
28
+ @color == :black
29
+ end
30
+
31
+ # True for red nodes.
32
+ def red?
33
+ @color == :red
34
+ end
35
+
36
+ # Returns an array of the node's [key, value].
37
+ #
38
+ # This method is used for nodes in a RBTree's tree.
39
+ def to_a
40
+ [@key, @value]
41
+ end
42
+
43
+ # Returns an array of the node's [key, first value].
44
+ #
45
+ # This method is used for nodes in a MultiRBTree's tree.
46
+ def to_single_a
47
+ [@key, @value.first]
48
+ end
49
+
50
+ def inspect
51
+ <<ENDI
52
+ <RBTree::Node (#{@color}) #{@key.inspect} -> #{@value.inspect}
53
+ Left: [#{@left.inspect.gsub!("\n", "\n ")}]
54
+ Right: [#{@right.inspect.gsub!("\n", "\n ")}]>
55
+ ENDI
56
+ end
57
+ end # class RBTree::Node
58
+
59
+ end # namespace RBTree
@@ -0,0 +1,485 @@
1
+ # Sorted hash.
2
+ class RBTree
3
+ include Enumerable
4
+
5
+ # The red-black tree backing this store.
6
+ attr_reader :tree
7
+
8
+ # The value returned when trying to read keys that don't exist in the tree.
9
+ def default(key = nil)
10
+ @default_proc ? @default_proc.call(tree, key) : @default
11
+ end
12
+
13
+ # The value returned when trying to read keys that don't exist in the tree.
14
+ def default=(new_default)
15
+ @default_proc = nil
16
+ @default = new_default
17
+ end
18
+
19
+ # Block called when trying to read keys that don't exist in the tree.
20
+ attr_reader :default_proc
21
+
22
+ # Block called when trying to read keys that don't exist in the tree.
23
+ def default_proc=(new_proc)
24
+ @default = nil
25
+ @default_proc = new_proc
26
+ end
27
+
28
+ # Block used to implement custom comparisons.
29
+ attr_reader :cmp_proc
30
+
31
+ def initialize(default = nil, &default_proc)
32
+ raise ArgumentError, "wrong number of arguments" if default && default_proc
33
+ @default = default
34
+ @default_proc = default_proc
35
+ @cmp_proc = nil
36
+ @lock_count = 0
37
+ @tree = RBTree::Tree.new
38
+ end
39
+
40
+ def initialize_copy(source)
41
+ super
42
+ @tree = source.tree.dup
43
+ @lock_count = 0
44
+ end
45
+
46
+ def self.[](*key_values)
47
+ if key_values.length == 1
48
+ hash = key_values.first
49
+ unless hash.respond_to? :values_at
50
+ raise ArgumentError, "expected a Hash-like argument"
51
+ end
52
+ if self == RBTree && hash.instance_of?(MultiRBTree)
53
+ raise TypeError, "can't convert MultiRBTree to RBTree"
54
+ end
55
+ tree = self.new
56
+ begin
57
+ hash.each { |k, v| tree[k] = v }
58
+ rescue NoMethodError
59
+ raise ArgumentError, "expected a Hash-like argument"
60
+ end
61
+ return tree
62
+ end
63
+
64
+ if key_values.length % 2 == 1
65
+ raise ArgumentError, 'odd number of arguments for RBTree'
66
+ end
67
+
68
+ tree = self.new
69
+ 0.upto(key_values.length / 2 - 1) do |i|
70
+ tree[key_values[i * 2]] = key_values[i * 2 + 1]
71
+ end
72
+ tree
73
+ end
74
+
75
+ # Rejects changes while this method's block is executed.
76
+ def lock_changes
77
+ begin
78
+ @lock_count += 1
79
+ yield
80
+ ensure
81
+ @lock_count -= 1
82
+ end
83
+ end
84
+ private :lock_changes
85
+
86
+ def lower_bound(key)
87
+ @tree.lower_bound(key).to_a
88
+ end
89
+
90
+ def upper_bound(key)
91
+ @tree.upper_bound(key).to_a
92
+ end
93
+
94
+ def bound(lower_key, upper_key = nil)
95
+ result = []
96
+ bound_nodes lower_key, upper_key do |node|
97
+ if block_given?
98
+ yield node.key, node.value
99
+ else
100
+ result << node.to_a
101
+ end
102
+ end
103
+ block_given? ? self : result
104
+ end
105
+
106
+ # Internal version of bound that yields the corresponding nodes.
107
+ def bound_nodes(lower_key, upper_key = nil)
108
+ upper_key ||= lower_key
109
+ node = @tree.lower_bound(lower_key)
110
+ return block_given? ? self : [] if node.nil?
111
+
112
+ lock_changes do
113
+ if @cmp_proc
114
+ # Slow path
115
+ until node.nil? || @cmp_proc.call(upper_key, node.key) < 0
116
+ yield node
117
+ node = @tree.successor node
118
+ end
119
+ else
120
+ # Fast path.
121
+ until node.nil? || upper_key < node.key
122
+ yield node
123
+ node = @tree.successor node
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def to_rbtree
130
+ self
131
+ end
132
+
133
+ def readjust(*proc_arg, &new_cmp_proc)
134
+ raise TypeError, 'cannot modify rbtree in iteration' if @lock_count > 0
135
+
136
+ if new_cmp_proc
137
+ cmp_proc = new_cmp_proc
138
+ unless proc_arg.empty?
139
+ raise ArgumentError, "expected 0 arguments when given a block"
140
+ end
141
+ else
142
+ unless proc_arg.length <= 1
143
+ raise ArgumentError, "expected 1 arguments (given #{proc_arg.length})"
144
+ end
145
+ unless proc_arg.first.respond_to?(:call) || proc_arg.first.nil?
146
+ raise TypeError, "expected a proc argument"
147
+ end
148
+ cmp_proc = proc_arg.first
149
+ end
150
+
151
+ lock_changes do
152
+ if cmp_proc
153
+ new_tree = RBTree::TreeCmp.new(&cmp_proc)
154
+ else
155
+ new_tree = RBTree::Tree.new
156
+ end
157
+
158
+ @tree.inorder do |node|
159
+ new_tree.insert new_tree.node(node.key, node.value)
160
+ end
161
+ @tree = new_tree
162
+ @cmp_proc = cmp_proc
163
+ end
164
+ end
165
+
166
+ def replace(other)
167
+ raise TypeError, 'cannot modify rbtree in iteration' if @lock_count > 0
168
+ unless other.instance_of? RBTree
169
+ raise TypeError, "expected RBTree, got #{other.class}"
170
+ end
171
+
172
+ @tree = other.tree.dup
173
+ @default_proc = other.default_proc
174
+ @default = other.default
175
+ @cmp_proc = other.cmp_proc
176
+ self
177
+ end
178
+ end
179
+
180
+ # :nodoc: array behavior
181
+ class RBTree
182
+ # The [key, value] for the smallest key in the tree.
183
+ def first
184
+ node = @tree.minimum
185
+ node.nil? ? default : node.to_a
186
+ end
187
+
188
+ # The [key, value] for the largest key in the tree.
189
+ def last
190
+ node = @tree.maximum
191
+ node.nil? ? default : node.to_a
192
+ end
193
+
194
+ # Removes the largest key in the tree.
195
+ def pop
196
+ return default if (node = @tree.maximum).nil?
197
+ @tree.delete node
198
+ node.to_a
199
+ end
200
+
201
+ # Removes the smallest key in the tree.
202
+ def shift
203
+ return default if (node = @tree.minimum).nil?
204
+ @tree.delete node
205
+ node.to_a
206
+ end
207
+ end
208
+
209
+ # :nodoc: hash behavior
210
+ class RBTree
211
+ # See Hash#[]
212
+ def [](key)
213
+ node = tree.search key
214
+ node ? node.value : default(key)
215
+ end
216
+
217
+ # See Hash#[]=
218
+ def []=(key, value)
219
+ raise TypeError, 'cannot modify rbtree in iteration' if @lock_count > 0
220
+
221
+ key = key.clone.freeze if key.kind_of? String
222
+ @tree.insert(@tree.node(key, value)).value = value
223
+ end
224
+
225
+ # See Hash#size
226
+ def size
227
+ @tree.size
228
+ end
229
+
230
+ # See Hash#empty
231
+ def empty?
232
+ @tree.empty?
233
+ end
234
+
235
+ # See Hash#clear
236
+ def clear
237
+ @tree = RBTree::Tree.new
238
+ end
239
+
240
+ # See Hash#==
241
+ def ==(other)
242
+ return false unless other.kind_of?(RBTree)
243
+ return false unless other.size == self.size
244
+ return false unless other.cmp_proc == @cmp_proc
245
+
246
+ ary = self.to_a
247
+ other_ary = other.to_a
248
+ ary.each_with_index { |v, i| return false unless other_ary[i] == v }
249
+ true
250
+ end
251
+
252
+ # See Hash#each
253
+ def each
254
+ if block_given?
255
+ lock_changes do
256
+ @tree.inorder { |node| yield node.key, node.value }
257
+ end
258
+ else
259
+ Enumerator.new self, :each
260
+ end
261
+ end
262
+ alias :each_pair :each
263
+
264
+ # See Hash#reverse_each
265
+ def reverse_each
266
+ if block_given?
267
+ lock_changes do
268
+ @tree.reverse_inorder { |node| yield node.key, node.value }
269
+ end
270
+ else
271
+ Enumerator.new self, :reverse_each
272
+ end
273
+ end
274
+
275
+
276
+ # See Hash#index
277
+ def index(value)
278
+ each { |k, v| return k if value == v }
279
+ nil
280
+ end
281
+
282
+ # See Hash#fetch
283
+ def fetch(key, *default)
284
+ if default.length > 1
285
+ raise ArgumentError, "expected at most 1 default, got #{default.length}"
286
+ end
287
+ if default.length == 1 && block_given?
288
+ $stderr << "warning: block supersedes default value argument"
289
+ end
290
+
291
+ node = tree.search key
292
+ return node.value if node
293
+ if block_given?
294
+ yield key
295
+ else
296
+ if default.length == 1
297
+ default.first
298
+ else
299
+ raise IndexError, 'key not found'
300
+ end
301
+ end
302
+ end
303
+
304
+ # See Hash#delete
305
+ def delete(key)
306
+ node = @tree.search key
307
+ unless node
308
+ return block_given? ? yield : nil
309
+ end
310
+ @tree.delete node
311
+ node.value
312
+ end
313
+
314
+ # See Hash#delete_if
315
+ def delete_if(&block)
316
+ reject!(&block)
317
+ self
318
+ end
319
+
320
+ # See Hash#reject!
321
+ def reject!
322
+ if block_given?
323
+ dead_nodes = []
324
+ lock_changes do
325
+ @tree.inorder do |node|
326
+ dead_nodes << node if yield node.key, node.value
327
+ end
328
+ end
329
+ dead_nodes.each { |node| @tree.delete node }
330
+ dead_nodes.empty? ? nil : self
331
+ else
332
+ Enumerator.new self, :each
333
+ end
334
+ end
335
+
336
+ # See Hash#reject
337
+ def reject(&block)
338
+ copy = self.dup
339
+ copy.reject!(&block)
340
+ # NOTE: the correct answer should be "copy", but we're copying RBTree
341
+ # bug-for-bug
342
+ # copy
343
+ end
344
+
345
+ # See Hash#each_key.
346
+ def each_key
347
+ if block_given?
348
+ lock_changes do
349
+ @tree.inorder { |node| yield node.key }
350
+ end
351
+ else
352
+ Enumerator.new self, :each_key
353
+ end
354
+ end
355
+
356
+ # See Hash#each_value.
357
+ def each_value
358
+ if block_given?
359
+ lock_changes do
360
+ @tree.inorder { |node| yield node.value }
361
+ end
362
+ else
363
+ Enumerator.new self, :each_value
364
+ end
365
+ end
366
+
367
+ # See Hash#keys.
368
+ def keys
369
+ result = Array.new
370
+ each_key { |key| result << key }
371
+ result
372
+ end
373
+
374
+ # See Hash#values.
375
+ def values
376
+ result = Array.new
377
+ each_value { |value| result << value }
378
+ result
379
+ end
380
+
381
+ # See Hash#has_key?
382
+ def has_key?(key)
383
+ !!@tree.search(key)
384
+ end
385
+
386
+ # See Hash#has_value?
387
+ def has_value?(value)
388
+ lock_changes do
389
+ each_value { |v| return true if value == v }
390
+ end
391
+ false
392
+ end
393
+
394
+ # See Hash#invert
395
+ def invert
396
+ tree = self.class.new
397
+ each { |key, value| tree[value] = key }
398
+ tree
399
+ end
400
+
401
+ # See Hash#values_at
402
+ def values_at(*keys)
403
+ keys.map { |key| self[key] }
404
+ end
405
+
406
+ # See Hash#merge!
407
+ def merge!(other)
408
+ unless other.instance_of? RBTree
409
+ raise TypeError, "wrong argument type #{other.class} (expected RBTree)"
410
+ end
411
+
412
+ if block_given?
413
+ other.each do |key, value|
414
+ if node = @tree.search(key)
415
+ node.value = yield key, node.value, value
416
+ else
417
+ self[key] = value
418
+ end
419
+ end
420
+ else
421
+ other.each { |key, value| self[key] = value }
422
+ end
423
+ self
424
+ end
425
+ alias :update :merge!
426
+
427
+ # See Hash#merge
428
+ def merge(other)
429
+ copy = self.dup
430
+ copy.merge! other
431
+ copy
432
+ end
433
+
434
+ # :nodoc:
435
+ def to_s
436
+ to_a.to_s
437
+ end
438
+
439
+ # A new Hash with the same contents and defaults as this RBTree instance.
440
+ def to_hash
441
+ if @default_proc && !Hash.method_defined?(:default_proc=)
442
+ # Slow path for default block and Ruby 1.8.7
443
+ hash = Hash.new &@default_proc
444
+ each { |key, value| hash[key] = value }
445
+ return hash
446
+ end
447
+
448
+ hash = Hash[to_a]
449
+ if @default_proc
450
+ hash.default_proc = @default_proc if hash.respond_to? :default_proc=
451
+ else
452
+ hash.default = @default
453
+ end
454
+ hash
455
+ end
456
+
457
+ # :nodoc:
458
+ def inspect
459
+ contents = map { |k, v|
460
+ k_inspect = k.equal?(self) ? '#<RBTree: ...>' : k.inspect
461
+ v_inspect = v.equal?(self) ? '#<RBTree: ...>' : v.inspect
462
+ "#{k_inspect}=>#{v_inspect}"
463
+ }.join(', ')
464
+ default_inspect = default.equal?(self) ? '#<RBTree: ...>' : default.inspect
465
+ "#<RBTree: {#{contents}}, default=#{default_inspect}, cmp_proc=#{@cmp_proc.inspect}>"
466
+ end
467
+
468
+ def pretty_print(q)
469
+ q.group(1, '#<RBTree: ', '>') do
470
+ q.pp_hash self
471
+ q.text ','
472
+ q.breakable ' '
473
+ q.text 'default='
474
+ q.pp default
475
+ q.text ','
476
+ q.breakable ' '
477
+ q.text 'cmp_proc='
478
+ q.pp cmp_proc
479
+ end
480
+ end
481
+
482
+ def pretty_print_cycle(q)
483
+ q.text '"#<RBTree: ...>"'
484
+ end
485
+ end # class RBTree::RBTree