rbtree-ruby 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea4c407bb808b5f0ce61e05d95bdb1b9a7efce1a6db4ef6c5688016d39eb66a1
4
- data.tar.gz: 1dec0818d2844494de2daf36cca3b018d28589316b580d71879756e34ca3adb0
3
+ metadata.gz: 89348dfde7177409ecdca6a4184ebee7f83f3a57eebb84b3f4925ad4460a7a92
4
+ data.tar.gz: bd46b055e05a121787b67ecf20836181800abe0a230800703872c1412826ccfa
5
5
  SHA512:
6
- metadata.gz: 654691a199723dd0b7426fea9165b372f4c71bcdadc8a58a90b76352b8eaade41145270ff6f88ffb37a4a22732a46b636d21515a07d4ae18b061c5d6fb154d53
7
- data.tar.gz: 8e619ef4f92f440e92350748bfaadc80dc65f8a1daed06d6df1b73e20c4228ee943677496f56e9a8e413cb7081b8d98e6c7711a0b6ffe50fcbf8ab00bb65ed5a
6
+ metadata.gz: 908a2d3d58bfac4c7d092e745ebe7f3f2c391551ea5fa7822871d1d0334c64985169df7433342e0e77cad9cf85f8a6b1a265ee427d96445095b3aa27da73d8ef
7
+ data.tar.gz: c7b5afe4a5189deee48c6abc5cbca6340c14ebfc65d581f2788117bfb84aabca7757582ab5b6bbcf7cc5866e6350be4f85f87fda78ea49af8c394dd0884de6b3
data/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] - 2026-01-14
9
+
10
+ ### Added
11
+ - **Enhanced iteration**: `each` now accepts `reverse:` and `safe:` options
12
+ - `tree.each(reverse: true) { ... }` (same as `reverse_each`)
13
+ - `tree.each(safe: true) { ... }` (modification-safe)
14
+ - `tree.each(reverse: true, safe: true) { ... }` (reverse modification-safe)
15
+ - In `MultiRBTree`, `reverse: true` also iterates over values in reverse insertion order.
16
+ - **Range query safe mode**: `safe:` option for `lt`, `lte`, `gt`, `gte`, `between`
17
+ - `tree.lt(10, safe: true) { |k, _| tree.delete(k) if k.even? }`
18
+ - Works with `:reverse` option: `tree.gt(5, reverse: true, safe: true)`
19
+ - Returns Enumerator: `tree.between(1, 100, safe: true).select { ... }`
20
+
21
+ ### Changed
22
+ - **MultiRBTree#get_all**: Now returns an `Enumerator` instead of an `Array` when no block is given.
23
+ - Improves consistency with other iteration methods.
24
+ - Safe handling for non-existent keys (returns empty Enumerator/nil logic handled safely).
25
+ - Use `.to_a` to get an Array: `tree.get_all(key).to_a`
26
+
8
27
  ## [0.2.0] - 2026-01-14
9
28
 
10
29
  ### Added
data/README.ja.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  🌍 *[English](README.md) | [日本語](README.ja.md)*
4
4
 
5
- Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)の時間計算量で実行できる、効率的な順序付きキーバリューストレージを提供します。
5
+ Red-Black Tree(赤黒木)データ構造のピュアRuby実装です。挿入、削除、検索操作がO(log n)の時間計算量で実行できる、
6
+ 効率的な順序付きキーバリューストレージを提供します。
6
7
 
7
8
  ## 特徴
8
9
 
@@ -60,6 +61,12 @@ tree.each { |key, value| puts "#{key}: #{value}" }
60
61
  # 10: ten
61
62
  # 20: twenty
62
63
 
64
+ # イテレーション中の変更
65
+ # 標準のHashやArrayとは異なり、`safe: true`オプションを指定することで
66
+ # イテレーション中に安全にキーの削除や挿入を行うことができます。
67
+ tree.each(safe: true) { |k, v| tree.delete(k) if k.even? }
68
+ tree.each(reverse: true) { |k, v| puts k } # reverse_eachと同じ
69
+
63
70
  # 最小値と最大値
64
71
  tree.min # => [1, "one"]
65
72
  tree.max # => [20, "twenty"]
@@ -100,8 +107,8 @@ tree.size # => 4 (キーバリューペアの総数)
100
107
  tree.get(1) # => "first one"
101
108
  tree[1] # => "first one"
102
109
 
103
- # キーの全ての値を取得
104
- tree.get_all(1) # => ["first one", "second one", "third one"]
110
+ # キーの全ての値を取得(Enumeratorを返す)
111
+ tree.get_all(1).to_a # => ["first one", "second one", "third one"]
105
112
 
106
113
  # 全キーバリューペアをイテレーション
107
114
  tree.each { |k, v| puts "#{k}: #{v}" }
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  🌍 *[English](README.md) | [日本語](README.ja.md)*
4
4
 
5
- A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
5
+ A pure Ruby implementation of the Red-Black Tree data structure, providing efficient ordered
6
+ key-value storage with O(log n) time complexity for insertion, deletion, and lookup operations.
6
7
 
7
8
  ## Features
8
9
 
@@ -60,6 +61,12 @@ tree.each { |key, value| puts "#{key}: #{value}" }
60
61
  # 10: ten
61
62
  # 20: twenty
62
63
 
64
+ # Modification during iteration
65
+ # Unlike standard Ruby Hash/Array, modification during iteration is fully supported
66
+ # with the `safe: true` option. This allows you to delete or insert keys safely while iterating.
67
+ tree.each(safe: true) { |k, v| tree.delete(k) if k.even? }
68
+ tree.each(reverse: true) { |k, v| puts k } # Same as reverse_each
69
+
63
70
  # Min and max
64
71
  tree.min # => [1, "one"]
65
72
  tree.max # => [20, "twenty"]
@@ -100,8 +107,8 @@ tree.size # => 4 (total number of key-value pairs)
100
107
  tree.get(1) # => "first one"
101
108
  tree[1] # => "first one"
102
109
 
103
- # Get all values for a key
104
- tree.get_all(1) # => ["first one", "second one", "third one"]
110
+ # Get all values for a key (returns Enumerator)
111
+ tree.get_all(1).to_a # => ["first one", "second one", "third one"]
105
112
 
106
113
  # Iterate over all key-value pairs
107
114
  tree.each { |k, v| puts "#{k}: #{v}" }
@@ -2,5 +2,5 @@
2
2
 
3
3
  class RBTree
4
4
  # The version of the rbtree-ruby gem
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.1"
6
6
  end
data/lib/rbtree.rb CHANGED
@@ -268,13 +268,15 @@ class RBTree
268
268
  def pop
269
269
  n = rightmost(@root)
270
270
  return nil if n == @nil_node
271
- result = [n.key, n.value]
271
+ result = n.pair
272
272
  delete(n.key)
273
273
  result
274
274
  end
275
275
 
276
- # Iterates over all key-value pairs in ascending order of keys.
276
+ # Iterates over all key-value pairs in ascending (or descending) order.
277
277
  #
278
+ # @param reverse [Boolean] if true, iterate in descending order (default: false)
279
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
278
280
  # @yield [key, value] each key-value pair in the tree
279
281
  # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
280
282
  # @example
@@ -284,9 +286,40 @@ class RBTree
284
286
  # # 1: one
285
287
  # # 2: two
286
288
  # # 3: three
287
- def each(&block)
288
- return enum_for(:each) unless block_given?
289
- traverse_asc(@root, &block)
289
+ #
290
+ # # Reverse iteration
291
+ # tree.each(reverse: true) { |k, v| ... }
292
+ #
293
+ # # Safe iteration for modifications
294
+ # tree.each(safe: true) do |k, v|
295
+ # tree.delete(k) if k.even?
296
+ # end
297
+ def each(reverse: false, safe: false, &block)
298
+ return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
299
+ if safe
300
+ if reverse
301
+ pair = find_max
302
+ while pair
303
+ current_key = pair[0]
304
+ yield pair[0], pair[1]
305
+ pair = find_predecessor(current_key)
306
+ end
307
+ else
308
+ pair = find_min
309
+ while pair
310
+ current_key = pair[0]
311
+ yield pair[0], pair[1]
312
+ pair = find_successor(current_key)
313
+ end
314
+ end
315
+ else
316
+ if reverse
317
+ traverse_desc(@root, &block)
318
+ else
319
+ traverse_asc(@root, &block)
320
+ end
321
+ end
322
+ self
290
323
  end
291
324
 
292
325
  # Iterates over all key-value pairs in descending order of keys.
@@ -300,10 +333,15 @@ class RBTree
300
333
  # # 3: three
301
334
  # # 2: two
302
335
  # # 1: one
303
- def reverse_each(&block)
304
- return enum_for(:reverse_each) unless block_given?
305
- traverse_desc(@root, &block)
306
- end
336
+ # Iterates over all key-value pairs in descending order of keys.
337
+ #
338
+ # This is an alias for `each(reverse: true)`.
339
+ #
340
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
341
+ # @yield [key, value] each key-value pair in the tree
342
+ # @return [Enumerator, RBTree] an Enumerator if no block is given, self otherwise
343
+ # @see #each
344
+ def reverse_each(safe: false, &block) = each(reverse: true, safe: safe, &block)
307
345
 
308
346
  # Returns the minimum key-value pair without removing it.
309
347
  #
@@ -311,9 +349,7 @@ class RBTree
311
349
  # @example
312
350
  # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
313
351
  # tree.min # => [1, "one"]
314
- def min
315
- @min_node == @nil_node ? nil : [@min_node.key, @min_node.value]
316
- end
352
+ def min = find_min
317
353
 
318
354
  # Returns the maximum key-value pair without removing it.
319
355
  #
@@ -321,25 +357,39 @@ class RBTree
321
357
  # @example
322
358
  # tree = RBTree.new({3 => 'three', 1 => 'one', 2 => 'two'})
323
359
  # tree.max # => [3, "three"]
324
- def max
325
- n = rightmost(@root)
326
- n == @nil_node ? nil : [n.key, n.value]
327
- end
360
+ def max = find_max
328
361
 
329
362
  # Retrieves all key-value pairs with keys less than the specified key.
330
363
  #
331
364
  # @param key [Object] the upper bound (exclusive)
332
365
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
366
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
333
367
  # @yield [key, value] each matching key-value pair (if block given)
334
368
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
335
369
  # @example
336
370
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
337
371
  # tree.lt(3).to_a # => [[1, "one"], [2, "two"]]
338
372
  # tree.lt(3, reverse: true).first # => [2, "two"]
339
- # tree.lt(3) { |k, v| puts k } # prints keys, returns self
340
- def lt(key, reverse: false, &block)
341
- return enum_for(:lt, key, reverse: reverse) unless block_given?
342
- if reverse
373
+ # tree.lt(3, safe: true) { |k, _| tree.delete(k) if k.even? } # safe to delete
374
+ def lt(key, reverse: false, safe: false, &block)
375
+ return enum_for(:lt, key, reverse: reverse, safe: safe) unless block_given?
376
+ if safe
377
+ if reverse
378
+ pair = find_predecessor(key)
379
+ while pair
380
+ current_key = pair[0]
381
+ yield pair
382
+ pair = find_predecessor(current_key)
383
+ end
384
+ else
385
+ pair = find_min
386
+ while pair && pair[0] < key
387
+ current_key = pair[0]
388
+ yield pair
389
+ pair = find_successor(current_key)
390
+ end
391
+ end
392
+ elsif reverse
343
393
  traverse_lt_desc(@root, key, &block)
344
394
  else
345
395
  traverse_lt(@root, key, &block)
@@ -351,15 +401,32 @@ class RBTree
351
401
  #
352
402
  # @param key [Object] the upper bound (inclusive)
353
403
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
404
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
354
405
  # @yield [key, value] each matching key-value pair (if block given)
355
406
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
356
407
  # @example
357
408
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
358
409
  # tree.lte(3).to_a # => [[1, "one"], [2, "two"], [3, "three"]]
359
410
  # tree.lte(3, reverse: true).first # => [3, "three"]
360
- def lte(key, reverse: false, &block)
361
- return enum_for(:lte, key, reverse: reverse) unless block_given?
362
- if reverse
411
+ def lte(key, reverse: false, safe: false, &block)
412
+ return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
413
+ if safe
414
+ if reverse
415
+ pair = @hash_index[key]&.pair || find_predecessor(key)
416
+ while pair
417
+ current_key = pair[0]
418
+ yield pair
419
+ pair = find_predecessor(current_key)
420
+ end
421
+ else
422
+ pair = find_min
423
+ while pair && pair[0] <= key
424
+ current_key = pair[0]
425
+ yield pair
426
+ pair = succ(current_key)
427
+ end
428
+ end
429
+ elsif reverse
363
430
  traverse_lte_desc(@root, key, &block)
364
431
  else
365
432
  traverse_lte(@root, key, &block)
@@ -371,15 +438,32 @@ class RBTree
371
438
  #
372
439
  # @param key [Object] the lower bound (exclusive)
373
440
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
441
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
374
442
  # @yield [key, value] each matching key-value pair (if block given)
375
443
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
376
444
  # @example
377
445
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
378
446
  # tree.gt(2).to_a # => [[3, "three"], [4, "four"]]
379
447
  # tree.gt(2, reverse: true).first # => [4, "four"]
380
- def gt(key, reverse: false, &block)
381
- return enum_for(:gt, key, reverse: reverse) unless block_given?
382
- if reverse
448
+ def gt(key, reverse: false, safe: false, &block)
449
+ return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
450
+ if safe
451
+ if reverse
452
+ pair = find_max
453
+ while pair && pair[0] > key
454
+ current_key = pair[0]
455
+ yield pair
456
+ pair = find_predecessor(current_key)
457
+ end
458
+ else
459
+ pair = find_successor(key)
460
+ while pair
461
+ current_key = pair[0]
462
+ yield pair
463
+ pair = find_successor(current_key)
464
+ end
465
+ end
466
+ elsif reverse
383
467
  traverse_gt_desc(@root, key, &block)
384
468
  else
385
469
  traverse_gt(@root, key, &block)
@@ -391,15 +475,32 @@ class RBTree
391
475
  #
392
476
  # @param key [Object] the lower bound (inclusive)
393
477
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
478
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
394
479
  # @yield [key, value] each matching key-value pair (if block given)
395
480
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
396
481
  # @example
397
482
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four'})
398
483
  # tree.gte(2).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
399
484
  # tree.gte(2, reverse: true).first # => [4, "four"]
400
- def gte(key, reverse: false, &block)
401
- return enum_for(:gte, key, reverse: reverse) unless block_given?
402
- if reverse
485
+ def gte(key, reverse: false, safe: false, &block)
486
+ return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
487
+ if safe
488
+ if reverse
489
+ pair = find_max
490
+ while pair && pair[0] >= key
491
+ current_key = pair[0]
492
+ yield pair
493
+ pair = find_predecessor(current_key)
494
+ end
495
+ else
496
+ pair = @hash_index[key]&.pair || find_successor(key)
497
+ while pair
498
+ current_key = pair[0]
499
+ yield pair
500
+ pair = find_successor(current_key)
501
+ end
502
+ end
503
+ elsif reverse
403
504
  traverse_gte_desc(@root, key, &block)
404
505
  else
405
506
  traverse_gte(@root, key, &block)
@@ -414,15 +515,34 @@ class RBTree
414
515
  # @param include_min [Boolean] whether to include the lower bound (default: true)
415
516
  # @param include_max [Boolean] whether to include the upper bound (default: true)
416
517
  # @param reverse [Boolean] if true, iterate in descending order (default: false)
518
+ # @param safe [Boolean] if true, safe for modifications during iteration (default: false)
417
519
  # @yield [key, value] each matching key-value pair (if block given)
418
520
  # @return [Enumerator, RBTree] Enumerator if no block given, self otherwise
419
521
  # @example
420
522
  # tree = RBTree.new({1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'})
421
523
  # tree.between(2, 4).to_a # => [[2, "two"], [3, "three"], [4, "four"]]
422
524
  # tree.between(2, 4, reverse: true).first # => [4, "four"]
423
- def between(min, max, include_min: true, include_max: true, reverse: false, &block)
424
- return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse) unless block_given?
425
- if reverse
525
+ def between(min, max, include_min: true, include_max: true, reverse: false, safe: false, &block)
526
+ return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse, safe: safe) unless block_given?
527
+ if safe
528
+ if reverse
529
+ pair = include_max && @hash_index[max]&.pair || find_predecessor(max)
530
+ while pair && pair[0] > min
531
+ current_key = pair[0]
532
+ yield pair
533
+ pair = find_predecessor(current_key)
534
+ end
535
+ yield pair if pair && include_min && pair[0] == min
536
+ else
537
+ pair = include_min && @hash_index[min]&.pair || find_successor(min)
538
+ while pair && pair[0] < max
539
+ current_key = pair[0]
540
+ yield pair
541
+ pair = find_successor(current_key)
542
+ end
543
+ yield pair if pair && include_max && pair[0] == max
544
+ end
545
+ elsif reverse
426
546
  traverse_between_desc(@root, min, max, include_min, include_max, &block)
427
547
  else
428
548
  traverse_between(@root, min, max, include_min, include_max, &block)
@@ -445,7 +565,7 @@ class RBTree
445
565
  def nearest(key)
446
566
  return nil unless key.respond_to?(:-)
447
567
  n = find_nearest_node(key)
448
- n == @nil_node ? nil : [n.key, n.value]
568
+ n == @nil_node ? nil : n.pair
449
569
  end
450
570
 
451
571
  # Returns the key-value pair with the largest key that is smaller than the given key.
@@ -462,7 +582,7 @@ class RBTree
462
582
  # tree.prev(1) # => nil (no predecessor)
463
583
  def prev(key)
464
584
  n = find_predecessor_node(key)
465
- n == @nil_node ? nil : [n.key, n.value]
585
+ n == @nil_node ? nil : n.pair
466
586
  end
467
587
 
468
588
  # Returns the key-value pair with the smallest key that is larger than the given key.
@@ -479,7 +599,7 @@ class RBTree
479
599
  # tree.succ(7) # => nil (no successor)
480
600
  def succ(key)
481
601
  n = find_successor_node(key)
482
- n == @nil_node ? nil : [n.key, n.value]
602
+ n == @nil_node ? nil : n.pair
483
603
  end
484
604
 
485
605
  # Validates the red-black tree properties.
@@ -515,7 +635,7 @@ class RBTree
515
635
  current = current.left
516
636
  end
517
637
  current = stack.pop
518
- yield current.key, current.value
638
+ yield current.pair
519
639
  current = current.right
520
640
  end
521
641
  end
@@ -534,7 +654,7 @@ class RBTree
534
654
  current = current.right
535
655
  end
536
656
  current = stack.pop
537
- yield current.key, current.value
657
+ yield current.pair
538
658
  current = current.left
539
659
  end
540
660
  end
@@ -550,7 +670,7 @@ class RBTree
550
670
 
551
671
  traverse_lt(node.left, key, &block)
552
672
  if (node.key <=> key) < 0
553
- yield node.key, node.value
673
+ yield node.pair
554
674
  traverse_lt(node.right, key, &block)
555
675
  end
556
676
  end
@@ -566,7 +686,7 @@ class RBTree
566
686
 
567
687
  traverse_lte(node.left, key, &block)
568
688
  if (node.key <=> key) <= 0
569
- yield node.key, node.value
689
+ yield node.pair
570
690
  traverse_lte(node.right, key, &block)
571
691
  end
572
692
  end
@@ -582,7 +702,7 @@ class RBTree
582
702
 
583
703
  if (node.key <=> key) > 0
584
704
  traverse_gt(node.left, key, &block)
585
- yield node.key, node.value
705
+ yield node.pair
586
706
  end
587
707
  traverse_gt(node.right, key, &block)
588
708
  end
@@ -598,7 +718,7 @@ class RBTree
598
718
 
599
719
  if (node.key <=> key) >= 0
600
720
  traverse_gte(node.left, key, &block)
601
- yield node.key, node.value
721
+ yield node.pair
602
722
  end
603
723
  traverse_gte(node.right, key, &block)
604
724
  end
@@ -622,7 +742,7 @@ class RBTree
622
742
  less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
623
743
 
624
744
  if greater && less
625
- yield node.key, node.value
745
+ yield node.pair
626
746
  end
627
747
 
628
748
  if (node.key <=> max) < 0
@@ -641,7 +761,7 @@ class RBTree
641
761
 
642
762
  if (node.key <=> key) < 0
643
763
  traverse_lt_desc(node.right, key, &block)
644
- yield node.key, node.value
764
+ yield node.pair
645
765
  end
646
766
  traverse_lt_desc(node.left, key, &block)
647
767
  end
@@ -657,7 +777,7 @@ class RBTree
657
777
 
658
778
  if (node.key <=> key) <= 0
659
779
  traverse_lte_desc(node.right, key, &block)
660
- yield node.key, node.value
780
+ yield node.pair
661
781
  end
662
782
  traverse_lte_desc(node.left, key, &block)
663
783
  end
@@ -673,7 +793,7 @@ class RBTree
673
793
 
674
794
  traverse_gt_desc(node.right, key, &block)
675
795
  if (node.key <=> key) > 0
676
- yield node.key, node.value
796
+ yield node.pair
677
797
  traverse_gt_desc(node.left, key, &block)
678
798
  end
679
799
  end
@@ -689,7 +809,7 @@ class RBTree
689
809
 
690
810
  traverse_gte_desc(node.right, key, &block)
691
811
  if (node.key <=> key) >= 0
692
- yield node.key, node.value
812
+ yield node.pair
693
813
  traverse_gte_desc(node.left, key, &block)
694
814
  end
695
815
  end
@@ -714,7 +834,7 @@ class RBTree
714
834
  less = include_max ? (node.key <=> max) <= 0 : (node.key <=> max) < 0
715
835
 
716
836
  if greater && less
717
- yield node.key, node.value
837
+ yield node.pair
718
838
  end
719
839
 
720
840
  if (node.key <=> min) > 0
@@ -1011,6 +1131,16 @@ class RBTree
1011
1131
  predecessor
1012
1132
  end
1013
1133
 
1134
+ # Finds the node with the largest key that is smaller than the given key.
1135
+ # Returns the key-value pair if found, or nil if the tree is empty.
1136
+ #
1137
+ # @param key [Object] the reference key
1138
+ # @return [Array(Object, Object), nil] the key-value pair, or nil if tree is empty
1139
+ def find_predecessor(key)
1140
+ n = find_predecessor_node(key)
1141
+ n == @nil_node ? nil : n.pair
1142
+ end
1143
+
1014
1144
  # Finds the node with the smallest key that is larger than the given key.
1015
1145
  #
1016
1146
  # If the key exists in the tree, returns its successor node.
@@ -1051,6 +1181,16 @@ class RBTree
1051
1181
  successor
1052
1182
  end
1053
1183
 
1184
+ # Finds the node with the smallest key that is larger than the given key.
1185
+ # Returns the key-value pair if found, or nil if the tree is empty.
1186
+ #
1187
+ # @param key [Object] the reference key
1188
+ # @return [Array(Object, Object), nil] the key-value pair, or nil if tree is empty
1189
+ def find_successor(key)
1190
+ n = find_successor_node(key)
1191
+ n == @nil_node ? nil : n.pair
1192
+ end
1193
+
1054
1194
  # Finds the leftmost (minimum) node in a subtree.
1055
1195
  #
1056
1196
  # @param node [Node] the root of the subtree
@@ -1062,6 +1202,11 @@ class RBTree
1062
1202
  node
1063
1203
  end
1064
1204
 
1205
+ # Returns the minimum key-value pair.
1206
+ #
1207
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1208
+ def find_min = @min_node == @nil_node ? nil : @min_node.pair
1209
+
1065
1210
  # Finds the rightmost (maximum) node in a subtree.
1066
1211
  #
1067
1212
  # @param node [Node] the root of the subtree
@@ -1073,6 +1218,11 @@ class RBTree
1073
1218
  node
1074
1219
  end
1075
1220
 
1221
+ # Returns the maximum key-value pair.
1222
+ #
1223
+ # @return [Array(Object, Object), nil] a two-element array [key, value], or nil if tree is empty
1224
+ def find_max = (n = rightmost(@root)) == @nil_node ? nil : n.pair
1225
+
1076
1226
  # Performs a left rotation on the given node.
1077
1227
  #
1078
1228
  # Transforms the tree structure:
@@ -1304,8 +1454,8 @@ class MultiRBTree < RBTree
1304
1454
  # tree.insert(1, 'second')
1305
1455
  # tree.get_all(1).to_a # => ["first", "second"]
1306
1456
  def get_all(key)
1307
- n = find_node(key)
1308
- n == @nil_node || n.value.empty? ? nil : n.value
1457
+ return enum_for(:get_all, key) unless block_given?
1458
+ @hash_index[key]&.value&.each { |v| yield v }
1309
1459
  end
1310
1460
 
1311
1461
  # Inserts a value for the given key.
@@ -1467,18 +1617,75 @@ class MultiRBTree < RBTree
1467
1617
  [n.key, last ? n.value.last : n.value.first]
1468
1618
  end
1469
1619
 
1470
- def prev(key, last: false)
1471
- n = find_predecessor_node(key)
1472
- return nil if n == @nil_node || n.value.empty?
1473
- [n.key, last ? n.value.last : n.value.first]
1620
+ def each(reverse: false, safe: false, &block)
1621
+ return enum_for(:each, reverse: reverse, safe: safe) unless block_given?
1622
+ if safe
1623
+ super do |k, vals|
1624
+ vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
1625
+ end
1626
+ else
1627
+ super
1628
+ end
1474
1629
  end
1475
1630
 
1476
- def succ(key, last: false)
1477
- n = find_successor_node(key)
1478
- return nil if n == @nil_node || n.value.empty?
1479
- [n.key, last ? n.value.last : n.value.first]
1631
+ def lt(key, reverse: false, safe: false, &block)
1632
+ return enum_for(:lt, key, reverse: reverse, safe: safe) unless block_given?
1633
+ if safe
1634
+ super do |k, vals|
1635
+ vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
1636
+ end
1637
+ else
1638
+ super
1639
+ end
1480
1640
  end
1481
1641
 
1642
+ def lte(key, reverse: false, safe: false, &block)
1643
+ return enum_for(:lte, key, reverse: reverse, safe: safe) unless block_given?
1644
+ if safe
1645
+ super do |k, vals|
1646
+ vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
1647
+ end
1648
+ else
1649
+ super
1650
+ end
1651
+ end
1652
+
1653
+ def gt(key, reverse: false, safe: false, &block)
1654
+ return enum_for(:gt, key, reverse: reverse, safe: safe) unless block_given?
1655
+ if safe
1656
+ super do |k, vals|
1657
+ vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
1658
+ end
1659
+ else
1660
+ super
1661
+ end
1662
+ end
1663
+
1664
+ def gte(key, reverse: false, safe: false, &block)
1665
+ return enum_for(:gte, key, reverse: reverse, safe: safe) unless block_given?
1666
+ if safe
1667
+ super do |k, vals|
1668
+ vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
1669
+ end
1670
+ else
1671
+ super
1672
+ end
1673
+ end
1674
+
1675
+ def between(min, max, include_min: true, include_max: true, reverse: false, safe: false, &block)
1676
+ return enum_for(:between, min, max, include_min: include_min, include_max: include_max, reverse: reverse, safe: safe) unless block_given?
1677
+ if safe
1678
+ super do |k, vals|
1679
+ vals.send(reverse ? :reverse_each : :each) { |v| yield k, v }
1680
+ end
1681
+ else
1682
+ super
1683
+ end
1684
+ end
1685
+
1686
+ def prev(key, last: false) = (n = super) && [n.key, last ? n.value.last : n.value.first]
1687
+ def succ(key, last: false) = (n = super) && [n.key, last ? n.value.last : n.value.first]
1688
+
1482
1689
  private
1483
1690
 
1484
1691
  def traverse_asc(node, &block)
@@ -1678,4 +1885,8 @@ class RBTree::Node
1678
1885
  # Checks if the node is black.
1679
1886
  # @return [Boolean] true if black, false otherwise
1680
1887
  def black? = @color == BLACK
1888
+
1889
+ # Returns the key-value pair.
1890
+ # @return [Array(Object, Object)] the key-value pair
1891
+ def pair = [key, value]
1681
1892
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbtree-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahito Suzuki