disjoint_interval_tree 0.1.0 → 0.2.0
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 +4 -4
- data/README.md +82 -29
- data/Rakefile +49 -4
- data/ext/disjoint_interval_tree/dit.c +63 -14
- data/ext/disjoint_interval_tree/dit.h +36 -9
- data/ext/disjoint_interval_tree/dit_ruby.c +157 -40
- data/lib/disjoint_interval_tree/version.rb +1 -1
- data/lib/disjoint_interval_tree.rb +11 -6
- data/test/c/test_dit.c +335 -65
- data/test/test_disjoint_interval_tree.rb +225 -36
- metadata +1 -1
|
@@ -27,13 +27,13 @@ class IntervalModel
|
|
|
27
27
|
def intersect(a, b)
|
|
28
28
|
return [] if a >= b
|
|
29
29
|
|
|
30
|
-
@intervals.select { |x, y| a < y && x < b }
|
|
30
|
+
@intervals.select { |x, y, _| a < y && x < b }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def insert(a, b)
|
|
33
|
+
def insert(a, b, obj = nil)
|
|
34
34
|
return false if a >= b || !intersect(a, b).empty?
|
|
35
35
|
|
|
36
|
-
@intervals << [a, b]
|
|
36
|
+
@intervals << [a, b, obj]
|
|
37
37
|
@intervals.sort!
|
|
38
38
|
true
|
|
39
39
|
end
|
|
@@ -93,7 +93,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
93
93
|
refute_empty @tree
|
|
94
94
|
assert_equal 1, @tree.size
|
|
95
95
|
assert_equal 1, @tree.height
|
|
96
|
-
assert_equal [[10, 20]], @tree.to_a
|
|
96
|
+
assert_equal [[10, 20, nil]], @tree.to_a
|
|
97
97
|
assert_equal [10, 20], @tree.hull
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -101,8 +101,8 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
101
101
|
@tree.insert(10, 20)
|
|
102
102
|
|
|
103
103
|
assert_nil @tree.at(9)
|
|
104
|
-
assert_equal [10, 20], @tree.at(10)
|
|
105
|
-
assert_equal [10, 20], @tree.at(19)
|
|
104
|
+
assert_equal [10, 20, nil], @tree.at(10)
|
|
105
|
+
assert_equal [10, 20, nil], @tree.at(19)
|
|
106
106
|
assert_nil @tree.at(20)
|
|
107
107
|
|
|
108
108
|
refute @tree.cover?(9)
|
|
@@ -117,14 +117,15 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
117
117
|
@tree.insert(20, 30)
|
|
118
118
|
|
|
119
119
|
assert_equal 3, @tree.size
|
|
120
|
-
assert_equal [[0, 10], [10, 20], [20, 30]], @tree.to_a
|
|
120
|
+
assert_equal [[0, 10, nil], [10, 20, nil], [20, 30, nil]], @tree.to_a
|
|
121
121
|
assert_equal [0, 30], @tree.hull
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
def test_intervals_are_ordered
|
|
125
125
|
[50, 10, 90, 30, 70, 0, 20].each { |a| @tree.insert(a, a + 5) }
|
|
126
126
|
|
|
127
|
-
assert_equal [[0, 5], [10, 15], [20, 25], [30, 35
|
|
127
|
+
assert_equal [[0, 5, nil], [10, 15, nil], [20, 25, nil], [30, 35, nil],
|
|
128
|
+
[50, 55, nil], [70, 75, nil], [90, 95, nil]],
|
|
128
129
|
@tree.to_a
|
|
129
130
|
assert_equal @tree.to_a, @tree.to_a.sort
|
|
130
131
|
end
|
|
@@ -165,7 +166,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
165
166
|
end
|
|
166
167
|
|
|
167
168
|
# the tree was left untouched
|
|
168
|
-
assert_equal [[10, 20], [30, 40]], @tree.to_a
|
|
169
|
+
assert_equal [[10, 20, nil], [30, 40, nil]], @tree.to_a
|
|
169
170
|
end
|
|
170
171
|
|
|
171
172
|
def test_overlap_error_is_a_standard_error
|
|
@@ -182,7 +183,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
182
183
|
assert @tree.insert?(10, 20)
|
|
183
184
|
refute @tree.insert?(15, 25)
|
|
184
185
|
assert @tree.insert?(20, 25)
|
|
185
|
-
assert_equal [[10, 20], [20, 25]], @tree.to_a
|
|
186
|
+
assert_equal [[10, 20, nil], [20, 25, nil]], @tree.to_a
|
|
186
187
|
end
|
|
187
188
|
|
|
188
189
|
def test_insert_empty_interval_raises
|
|
@@ -223,8 +224,8 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
223
224
|
def test_large_bounds_are_supported
|
|
224
225
|
@tree.insert(2**63, 2**63 + 10)
|
|
225
226
|
|
|
226
|
-
assert_equal [[2**63, 2**63 + 10]], @tree.to_a
|
|
227
|
-
assert_equal [2**63, 2**63 + 10], @tree.at(2**63 + 5)
|
|
227
|
+
assert_equal [[2**63, 2**63 + 10, nil]], @tree.to_a
|
|
228
|
+
assert_equal [2**63, 2**63 + 10, nil], @tree.at(2**63 + 5)
|
|
228
229
|
end
|
|
229
230
|
|
|
230
231
|
##############
|
|
@@ -234,14 +235,14 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
234
235
|
def test_intersect_yields_matching_intervals
|
|
235
236
|
tree = spaced_tree
|
|
236
237
|
seen = []
|
|
237
|
-
result = tree.intersect(5, 45) { |a, b| seen << [a, b] }
|
|
238
|
+
result = tree.intersect(5, 45) { |a, b, obj| seen << [a, b, obj] }
|
|
238
239
|
|
|
239
240
|
assert_same tree, result
|
|
240
|
-
assert_equal [[0, 10], [20, 30], [40, 50]], seen
|
|
241
|
+
assert_equal [[0, 10, nil], [20, 30, nil], [40, 50, nil]], seen
|
|
241
242
|
end
|
|
242
243
|
|
|
243
244
|
def test_intersect_without_block_returns_an_array
|
|
244
|
-
assert_equal [[0, 10], [20, 30], [40, 50]], spaced_tree.intersect(5, 45)
|
|
245
|
+
assert_equal [[0, 10, nil], [20, 30, nil], [40, 50, nil]], spaced_tree.intersect(5, 45)
|
|
245
246
|
end
|
|
246
247
|
|
|
247
248
|
def test_intersect_reports_nothing_when_querying_a_hole
|
|
@@ -252,8 +253,8 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
252
253
|
tree = spaced_tree
|
|
253
254
|
|
|
254
255
|
assert_equal [], tree.intersect(10, 20)
|
|
255
|
-
assert_equal [[0, 10]], tree.intersect(9, 20)
|
|
256
|
-
assert_equal [[20, 30]], tree.intersect(10, 21)
|
|
256
|
+
assert_equal [[0, 10, nil]], tree.intersect(9, 20)
|
|
257
|
+
assert_equal [[20, 30, nil]], tree.intersect(10, 21)
|
|
257
258
|
end
|
|
258
259
|
|
|
259
260
|
def test_intersect_on_an_empty_query
|
|
@@ -347,7 +348,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
347
348
|
|
|
348
349
|
# reading is still fine
|
|
349
350
|
assert_equal 4, tree.size
|
|
350
|
-
assert_equal [[0, 10]], tree.intersect(0, 10)
|
|
351
|
+
assert_equal [[0, 10, nil]], tree.intersect(0, 10)
|
|
351
352
|
tree.check!
|
|
352
353
|
end
|
|
353
354
|
|
|
@@ -371,7 +372,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
371
372
|
assert_equal 4, tree.size
|
|
372
373
|
|
|
373
374
|
assert_equal 3, tree.remove(5, 45)
|
|
374
|
-
assert_equal [[60, 70]], tree.to_a
|
|
375
|
+
assert_equal [[60, 70, nil]], tree.to_a
|
|
375
376
|
end
|
|
376
377
|
|
|
377
378
|
def test_remove_does_not_split_intervals
|
|
@@ -380,7 +381,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
380
381
|
assert_equal 1, tree.remove(25, 26)
|
|
381
382
|
assert_nil tree.at(20)
|
|
382
383
|
assert_nil tree.at(29)
|
|
383
|
-
assert_equal [[0, 10], [40, 50], [60, 70]], tree.to_a
|
|
384
|
+
assert_equal [[0, 10, nil], [40, 50, nil], [60, 70, nil]], tree.to_a
|
|
384
385
|
end
|
|
385
386
|
|
|
386
387
|
def test_remove_ignores_adjacency
|
|
@@ -403,9 +404,9 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
403
404
|
tree = spaced_tree
|
|
404
405
|
seen = []
|
|
405
406
|
|
|
406
|
-
assert_equal 3, tree.remove(5, 45) { |a, b| seen << [a, b] }
|
|
407
|
-
assert_equal [[0, 10], [20, 30], [40, 50]], seen
|
|
408
|
-
assert_equal [[60, 70]], tree.to_a
|
|
407
|
+
assert_equal 3, tree.remove(5, 45) { |a, b, obj| seen << [a, b, obj] }
|
|
408
|
+
assert_equal [[0, 10, nil], [20, 30, nil], [40, 50, nil]], seen
|
|
409
|
+
assert_equal [[60, 70, nil]], tree.to_a
|
|
409
410
|
end
|
|
410
411
|
|
|
411
412
|
def test_remove_then_reinsert
|
|
@@ -446,18 +447,18 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
446
447
|
|
|
447
448
|
assert_kind_of Enumerator, enumerator
|
|
448
449
|
assert_equal 4, enumerator.size
|
|
449
|
-
assert_equal [[0, 10], [20, 30], [40, 50], [60, 70]], enumerator.to_a
|
|
450
|
+
assert_equal [[0, 10, nil], [20, 30, nil], [40, 50, nil], [60, 70, nil]], enumerator.to_a
|
|
450
451
|
end
|
|
451
452
|
|
|
452
453
|
def test_enumerable_methods
|
|
453
454
|
tree = spaced_tree
|
|
454
455
|
|
|
455
456
|
assert_equal [10, 10, 10, 10], tree.map { |a, b| b - a }
|
|
456
|
-
assert_equal [[0, 10]], tree.select { |a, _| a.zero? }
|
|
457
|
-
assert_equal [0, 10], tree.first
|
|
458
|
-
assert_equal [[0, 10], [20, 30]], tree.first(2)
|
|
459
|
-
assert tree.include?([20, 30])
|
|
460
|
-
refute tree.include?([20, 31])
|
|
457
|
+
assert_equal [[0, 10, nil]], tree.select { |a, _| a.zero? }
|
|
458
|
+
assert_equal [0, 10, nil], tree.first
|
|
459
|
+
assert_equal [[0, 10, nil], [20, 30, nil]], tree.first(2)
|
|
460
|
+
assert tree.include?([20, 30, nil])
|
|
461
|
+
refute tree.include?([20, 31, nil])
|
|
461
462
|
assert_equal 4, tree.count
|
|
462
463
|
assert_equal 40, tree.sum { |a, b| b - a }
|
|
463
464
|
end
|
|
@@ -473,7 +474,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
473
474
|
def test_new_with_intervals
|
|
474
475
|
tree = DisjointIntervalTree.new([[20, 30], [0, 10]])
|
|
475
476
|
|
|
476
|
-
assert_equal [[0, 10], [20, 30]], tree.to_a
|
|
477
|
+
assert_equal [[0, 10, nil], [20, 30, nil]], tree.to_a
|
|
477
478
|
end
|
|
478
479
|
|
|
479
480
|
def test_new_with_overlapping_intervals_raises
|
|
@@ -484,7 +485,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
484
485
|
|
|
485
486
|
def test_new_with_garbage_raises
|
|
486
487
|
assert_raises(TypeError) { DisjointIntervalTree.new(42) }
|
|
487
|
-
assert_raises(ArgumentError) { DisjointIntervalTree.new([[0, 10, 20]]) }
|
|
488
|
+
assert_raises(ArgumentError) { DisjointIntervalTree.new([[0, 10, nil, 20]]) }
|
|
488
489
|
assert_raises(ArgumentError) { DisjointIntervalTree.new([0]) }
|
|
489
490
|
end
|
|
490
491
|
|
|
@@ -508,7 +509,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
508
509
|
assert_equal DisjointIntervalTree.new, DisjointIntervalTree.new
|
|
509
510
|
assert_equal spaced_tree, spaced_tree
|
|
510
511
|
refute_equal spaced_tree, DisjointIntervalTree.new
|
|
511
|
-
refute_equal spaced_tree, [[0, 10], [20, 30], [40, 50], [60, 70]]
|
|
512
|
+
refute_equal spaced_tree, [[0, 10, nil], [20, 30, nil], [40, 50, nil], [60, 70, nil]]
|
|
512
513
|
end
|
|
513
514
|
|
|
514
515
|
##################
|
|
@@ -523,7 +524,7 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
523
524
|
@tree.insert(1, max - 1)
|
|
524
525
|
|
|
525
526
|
assert_equal [0, max], @tree.hull
|
|
526
|
-
assert_equal [max - 1, max], @tree.at(max - 1)
|
|
527
|
+
assert_equal [max - 1, max, nil], @tree.at(max - 1)
|
|
527
528
|
|
|
528
529
|
# no half-open interval can ever contain MAX
|
|
529
530
|
assert_nil @tree.at(max)
|
|
@@ -586,8 +587,10 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
586
587
|
case rand(3)
|
|
587
588
|
when 0
|
|
588
589
|
if model.intersect(a, b).empty?
|
|
589
|
-
|
|
590
|
-
|
|
590
|
+
# an object whose content identifies the interval it belongs to, so
|
|
591
|
+
# that a payload moved to the wrong node is caught by the comparison
|
|
592
|
+
@tree.insert(a, b, "obj-#{a}")
|
|
593
|
+
model.insert(a, b, "obj-#{a}")
|
|
591
594
|
else
|
|
592
595
|
assert_raises(DisjointIntervalTree::OverlapError) { @tree.insert(a, b) }
|
|
593
596
|
end
|
|
@@ -644,6 +647,192 @@ class TestDisjointIntervalTree < Minitest::Test
|
|
|
644
647
|
GC.compact if GC.respond_to?(:compact)
|
|
645
648
|
|
|
646
649
|
@tree.insert(0, 10)
|
|
647
|
-
assert_equal [[0, 10]], @tree.to_a
|
|
650
|
+
assert_equal [[0, 10, nil]], @tree.to_a
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
###########
|
|
654
|
+
# OBJECTS #
|
|
655
|
+
###########
|
|
656
|
+
|
|
657
|
+
def test_objects_are_optional
|
|
658
|
+
@tree.insert(0, 10)
|
|
659
|
+
@tree.insert(20, 30, :something)
|
|
660
|
+
|
|
661
|
+
assert_equal [[0, 10, nil], [20, 30, :something]], @tree.to_a
|
|
662
|
+
assert_nil @tree[5]
|
|
663
|
+
assert_equal :something, @tree[25]
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
def test_objects_are_returned_by_identity
|
|
667
|
+
payload = Object.new
|
|
668
|
+
@tree.insert(0, 10, payload)
|
|
669
|
+
|
|
670
|
+
assert_same payload, @tree[5]
|
|
671
|
+
assert_same payload, @tree.at(5)[2]
|
|
672
|
+
assert_same payload, @tree.to_a.first[2]
|
|
673
|
+
assert_same payload, @tree.intersect(0, 100).first[2]
|
|
674
|
+
|
|
675
|
+
@tree.intersect(0, 100) { |_a, _b, obj| assert_same payload, obj }
|
|
676
|
+
@tree.each { |_a, _b, obj| assert_same payload, obj }
|
|
677
|
+
@tree.remove(0, 100) { |_a, _b, obj| assert_same payload, obj }
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
def test_any_object_can_be_stored
|
|
681
|
+
objects = [nil, false, true, 42, :sym, 'str', [1, 2], { a: 1 }, Object.new, 2**80]
|
|
682
|
+
|
|
683
|
+
objects.each_with_index { |obj, i| @tree.insert(10 * i, 10 * i + 5, obj) }
|
|
684
|
+
@tree.check!
|
|
685
|
+
|
|
686
|
+
objects.each_with_index do |obj, i|
|
|
687
|
+
assert_same obj, @tree[10 * i], "object #{obj.inspect}"
|
|
688
|
+
end
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
def test_several_intervals_may_share_an_object
|
|
692
|
+
shared = 'shared'
|
|
693
|
+
@tree.insert(0, 10, shared)
|
|
694
|
+
@tree.insert(20, 30, shared)
|
|
695
|
+
|
|
696
|
+
assert_same shared, @tree[5]
|
|
697
|
+
assert_same shared, @tree[25]
|
|
698
|
+
|
|
699
|
+
# removing one leaves the other untouched
|
|
700
|
+
@tree.remove(0, 10)
|
|
701
|
+
assert_same shared, @tree[25]
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
def test_aref_cannot_tell_a_nil_object_from_a_missing_interval
|
|
705
|
+
@tree.insert(0, 10, nil)
|
|
706
|
+
|
|
707
|
+
assert_nil @tree[5]
|
|
708
|
+
assert_nil @tree[15]
|
|
709
|
+
|
|
710
|
+
# ... but #at and #cover? can
|
|
711
|
+
assert_equal [0, 10, nil], @tree.at(5)
|
|
712
|
+
assert @tree.cover?(5)
|
|
713
|
+
assert_nil @tree.at(15)
|
|
714
|
+
refute @tree.cover?(15)
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def test_objects_follow_their_interval_through_rebalancing
|
|
718
|
+
n = 512
|
|
719
|
+
|
|
720
|
+
# insert in an order that forces rotations, then delete in an order that
|
|
721
|
+
# forces two-children deletions -- the case that moves an interval from
|
|
722
|
+
# one node to another, and where its object could be left behind
|
|
723
|
+
(0...n).to_a.shuffle.each { |i| @tree.insert(10 * i, 10 * i + 5, "obj-#{i}") }
|
|
724
|
+
@tree.check!
|
|
725
|
+
|
|
726
|
+
@tree.each { |a, _b, obj| assert_equal "obj-#{a / 10}", obj }
|
|
727
|
+
|
|
728
|
+
(0...n).to_a.shuffle.each do |i|
|
|
729
|
+
assert_equal 1, @tree.remove(10 * i, 10 * i + 5) { |a, _b, obj|
|
|
730
|
+
assert_equal "obj-#{a / 10}", obj
|
|
731
|
+
}
|
|
732
|
+
@tree.each { |a, _b, obj| assert_equal "obj-#{a / 10}", obj }
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
assert_empty @tree
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
def test_dup_shares_the_objects
|
|
739
|
+
payload = Object.new
|
|
740
|
+
@tree.insert(0, 10, payload)
|
|
741
|
+
|
|
742
|
+
copy = @tree.dup
|
|
743
|
+
|
|
744
|
+
assert_equal @tree, copy
|
|
745
|
+
assert_same payload, copy[5]
|
|
746
|
+
assert_same @tree[5], copy[5]
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def test_equality_compares_objects
|
|
750
|
+
one = DisjointIntervalTree.new([[0, 10, :a]])
|
|
751
|
+
two = DisjointIntervalTree.new([[0, 10, :a]])
|
|
752
|
+
three = DisjointIntervalTree.new([[0, 10, :b]])
|
|
753
|
+
|
|
754
|
+
assert_equal one, two
|
|
755
|
+
refute_equal one, three
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def test_an_object_only_referenced_by_the_tree_survives_gc
|
|
759
|
+
@tree.insert(0, 10, +'only-the-tree-holds-me')
|
|
760
|
+
@tree.insert(20, 30, Object.new)
|
|
761
|
+
|
|
762
|
+
GC.start
|
|
763
|
+
GC.start
|
|
764
|
+
|
|
765
|
+
assert_equal 'only-the-tree-holds-me', @tree[5]
|
|
766
|
+
refute_nil @tree[25]
|
|
767
|
+
@tree.check!
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
# A finalizer must be built outside the scope holding the object it watches:
|
|
771
|
+
# its binding is kept alive by the ObjectSpace finalizer table, so a
|
|
772
|
+
# finalizer defined next to the object would keep that object reachable and
|
|
773
|
+
# the test would measure nothing.
|
|
774
|
+
def counting_finalizer(counter)
|
|
775
|
+
->(_id) { counter[0] += 1 }
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
def fill_with_finalized_objects(tree, finalizer, n)
|
|
779
|
+
n.times do |i|
|
|
780
|
+
obj = Object.new
|
|
781
|
+
ObjectSpace.define_finalizer(obj, finalizer)
|
|
782
|
+
tree.insert(10 * i, 10 * i + 5, obj)
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
def test_objects_are_collectable_once_removed
|
|
787
|
+
counter = [0]
|
|
788
|
+
fill_with_finalized_objects(@tree, counting_finalizer(counter), 10)
|
|
789
|
+
|
|
790
|
+
GC.start
|
|
791
|
+
GC.start
|
|
792
|
+
assert_equal 0, counter[0], 'objects held by the tree must not be collected'
|
|
793
|
+
|
|
794
|
+
@tree.clear
|
|
795
|
+
GC.start
|
|
796
|
+
GC.start
|
|
797
|
+
|
|
798
|
+
assert_operator counter[0], :>, 0,
|
|
799
|
+
'objects must become collectable once the tree drops them'
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
def test_objects_are_collectable_once_their_interval_is_removed
|
|
803
|
+
counter = [0]
|
|
804
|
+
fill_with_finalized_objects(@tree, counting_finalizer(counter), 10)
|
|
805
|
+
|
|
806
|
+
GC.start
|
|
807
|
+
assert_equal 0, counter[0]
|
|
808
|
+
|
|
809
|
+
assert_equal 4, @tree.remove(0, 35)
|
|
810
|
+
GC.start
|
|
811
|
+
GC.start
|
|
812
|
+
|
|
813
|
+
assert_operator counter[0], :>, 0
|
|
814
|
+
assert_equal 6, @tree.size
|
|
815
|
+
@tree.check!
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def test_objects_survive_compaction
|
|
819
|
+
skip 'GC.compact is not available' unless GC.respond_to?(:compact)
|
|
820
|
+
|
|
821
|
+
100.times { |i| @tree.insert(10 * i, 10 * i + 5, +"obj-#{i}") }
|
|
822
|
+
|
|
823
|
+
GC.compact
|
|
824
|
+
|
|
825
|
+
100.times { |i| assert_equal "obj-#{i}", @tree[10 * i] }
|
|
826
|
+
@tree.check!
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
def test_objects_under_gc_stress
|
|
830
|
+
GC.stress = true
|
|
831
|
+
|
|
832
|
+
20.times { |i| @tree.insert(10 * i, 10 * i + 5, +"obj-#{i}") }
|
|
833
|
+
assert_equal 20, @tree.intersect(0, 1000).size
|
|
834
|
+
@tree.each { |a, _b, obj| assert_equal "obj-#{a / 10}", obj }
|
|
835
|
+
ensure
|
|
836
|
+
GC.stress = false
|
|
648
837
|
end
|
|
649
838
|
end
|