segment_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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 59ea55a8bf39f04d9d5d8fc248c8d8eaa5cb2c65692fd25c22ccc3b5a5ac14d0
4
+ data.tar.gz: a9b683819704f99d933a04bbf89272dcb00e87908a2a876aebd798268ee1c35d
5
+ SHA512:
6
+ metadata.gz: 5bf8d0dbbad097d1e9f2ea887eaa71f02f253c27ee2d27bed792781ebc858a9e7e116cb42176939a10bc30a670ce820ad2eeb26be67ad40b752ce31f2d1eb455
7
+ data.tar.gz: 1cd80e31aaf356a599dea612fb6b0e21bb6551b02205a02eb982eb47a9ce6ea6d61336c17060c8b0444bc3764f8c6eb0a8fc0d0fa272c7ab90ce530605cbf1f1
@@ -1,3 +1,3 @@
1
1
  class SegmentTree
2
- VERSION = "0.1.0"
3
- end
2
+ VERSION = '0.2.0'
3
+ end
data/lib/segment_tree.rb CHANGED
@@ -31,8 +31,38 @@ class SegmentTree
31
31
  else cmp
32
32
  end
33
33
  end
34
+
35
+ def ==(other)
36
+ other.is_a?(self.class) &&
37
+ @range == other.range &&
38
+ @value == other.value
39
+ end
40
+
41
+ def eql?(other)
42
+ other.is_a?(self.class) &&
43
+ @range.eql?(other.range) &&
44
+ @value.eql?(other.value)
45
+ end
46
+
47
+ def hash
48
+ [@range, @value].hash
49
+ end
50
+
51
+ def marshal_dump
52
+ {
53
+ range: @range,
54
+ value: @value,
55
+ }
56
+ end
57
+
58
+ def marshal_load(serialized_tree)
59
+ @range = serialized_tree[:range]
60
+ @value = serialized_tree[:value]
61
+ end
34
62
  end
35
63
 
64
+ attr_reader :segments
65
+
36
66
  # Build a segment tree from +data+.
37
67
  #
38
68
  # Data can be one of the following:
@@ -83,6 +113,28 @@ class SegmentTree
83
113
  end
84
114
  end
85
115
 
116
+ def ==(other)
117
+ other.is_a?(self.class) && @segments == other.segments
118
+ end
119
+
120
+ def eql?(other)
121
+ other.is_a?(self.class) && @segments.eql?(other.segments)
122
+ end
123
+
124
+ def hash
125
+ @segments.hash
126
+ end
127
+
128
+ def marshal_dump
129
+ {
130
+ segments: @segments,
131
+ }
132
+ end
133
+
134
+ def marshal_load(serialized_tree)
135
+ @segments = serialized_tree[:segments]
136
+ end
137
+
86
138
  private
87
139
  def matches?(x, low_idx, high_idx, idx) #:nodoc:
88
140
  low, high = @segments[low_idx], @segments[high_idx]
@@ -91,9 +143,9 @@ class SegmentTree
91
143
  right = idx < @segments.size - 1 && @segments[idx + 1]
92
144
 
93
145
  case
94
- when left && (low.range.begin..left.range.end).include?(x) then -1
95
- when segment.range.include?(x) then 0
96
- when right && (right.range.begin..high.range.end).include?(x) then 1
146
+ when left && low.range.begin <= x && x <= left.range.end then -1
147
+ when segment.range.begin <=x && x <= segment.range.end then 0
148
+ when right && right.range.begin <=x && x <= high.range.end then 1
97
149
  else nil
98
150
  end
99
151
  end
data/segment_tree.gemspec CHANGED
@@ -2,18 +2,19 @@
2
2
  require File.expand_path('../lib/segment_tree/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.author = "Alexei Mikhailov"
6
- gem.email = "amikhailov83@gmail.com"
5
+ gem.author = 'Alexei Mikhailov'
6
+ gem.email = 'amikhailov83@gmail.com'
7
7
  gem.description = %q{Tree data structure for storing segments. It allows querying which of the stored segments contain a given point.}
8
8
  gem.summary = %q{Tree data structure for storing segments. It allows querying which of the stored segments contain a given point.}
9
- gem.homepage = "https://github.com/take-five/segment_tree"
9
+ gem.homepage = 'https://github.com/take-five/segment_tree'
10
10
 
11
11
  gem.files = `git ls-files`.split($\).grep(/lib|spec/)
12
12
  gem.test_files = gem.files.grep(/spec/)
13
- gem.name = "segment_tree"
13
+ gem.name = 'segment_tree'
14
14
  gem.require_paths = %W(lib)
15
15
  gem.version = SegmentTree::VERSION
16
16
 
17
- gem.add_development_dependency "bundler", ">= 1.0"
18
- gem.add_development_dependency "rspec", ">= 2.11"
17
+ gem.add_development_dependency 'bundler', '>= 1.0'
18
+ gem.add_development_dependency 'rspec', '>= 3.1.0'
19
+ gem.add_development_dependency 'rake'
19
20
  end
@@ -1,5 +1,5 @@
1
- require "spec_helper"
2
- require "segment_tree"
1
+ require 'spec_helper'
2
+ require 'segment_tree'
3
3
 
4
4
  # subject { tree }
5
5
  # it { should query(12).and_return("b") }
@@ -13,10 +13,10 @@ RSpec::Matchers.define :query do |key|
13
13
  result = tree.find(key)
14
14
  result &&= result.value
15
15
 
16
- result.should eq @expected
16
+ expect(result).to eq @expected
17
17
  end
18
18
 
19
- failure_message_for_should do |tree|
19
+ failure_message do |tree|
20
20
  result = tree.find(key)
21
21
  result &&= result.value
22
22
 
@@ -28,15 +28,15 @@ end
28
28
  describe SegmentTree do
29
29
  # some fixtures
30
30
  # [[0..9, "a"], [10..19, "b"], ..., [90..99, "j"]] - spanned intervals
31
- let(:sample_spanned) { (0..9).zip("a".."j").map { |num, letter| [(num * 10)..(num + 1) * 10 - 1, letter] }.shuffle }
31
+ let(:sample_spanned) { (0..9).zip('a'..'j').map { |num, letter| [(num * 10)..(num + 1) * 10 - 1, letter] }.shuffle }
32
32
  # [[0..10, "a"], [10..20, "b"], ..., [90..100, "j"]] - partially overlapping intervals
33
- let(:sample_overlapping) { (0..9).zip("a".."j").map { |num, letter| [(num * 10)..(num + 1) * 10 + 2, letter] }.shuffle }
33
+ let(:sample_overlapping) { (0..9).zip('a'..'j').map { |num, letter| [(num * 10)..(num + 1) * 10 + 2, letter] }.shuffle }
34
34
  # [[0..5, "a"], [10..15, "b"], ..., [90..95, "j"]] - sparsed intervals
35
- let(:sample_sparsed) { (0..9).zip("a".."j").map { |num, letter| [(num * 10)..(num + 1) * 10 - 5, letter] }.shuffle }
35
+ let(:sample_sparsed) { (0..9).zip('a'..'j').map { |num, letter| [(num * 10)..(num + 1) * 10 - 5, letter] }.shuffle }
36
36
 
37
37
  # [[0..5, "a"], [0..7, "aa"], [10..15, "b"], [10..17, "bb"], ..., [90..97, "jj"]]
38
38
  let(:sample_overlapping2) do
39
- (0..9).zip("a".."j").map do |num, letter|
39
+ (0..9).zip('a'..'j').map do |num, letter|
40
40
  [(num * 10)..(num + 1) * 10 - 5, letter,
41
41
  (num * 10)..(num + 1) * 10 - 3, letter * 2]
42
42
  end.
@@ -46,89 +46,167 @@ describe SegmentTree do
46
46
  shuffle
47
47
  end
48
48
 
49
- describe ".new" do
50
- context "given a hash with ranges as keys" do
49
+ describe '.new' do
50
+ context 'given a hash with ranges as keys' do
51
51
  let :data do
52
- {7..9 => "a",
53
- 4..6 => "b",
54
- 0..3 => "c",
55
- 10..12 => "d"}
52
+ {7..9 => 'a',
53
+ 4..6 => 'b',
54
+ 0..3 => 'c',
55
+ 10..12 => 'd'}
56
56
  end
57
57
 
58
58
  subject(:tree) { SegmentTree.new(data) }
59
59
 
60
- it { should be_a SegmentTree }
60
+ it { is_expected.to be_a SegmentTree }
61
61
  end
62
62
 
63
- context "given an array of arrays" do
63
+ context 'given an array of arrays' do
64
64
  let :data do
65
- [[0..3, "a"],
66
- [4..6, "b"],
67
- [7..9, "c"],
68
- [10..12, "d"]].shuffle
65
+ [[0..3, 'a'],
66
+ [4..6, 'b'],
67
+ [7..9, 'c'],
68
+ [10..12, 'd']].shuffle
69
69
  end
70
70
 
71
71
  subject(:tree) { SegmentTree.new(data) }
72
72
 
73
- it { should be_a SegmentTree }
73
+ it { is_expected.to be_a SegmentTree }
74
74
  end
75
75
 
76
- context "given preordered data" do
76
+ context 'given preordered data' do
77
77
  let :data do
78
- [[0..3, "a"],
79
- [4..6, "b"],
80
- [7..9, "c"],
81
- [10..12, "d"]]
78
+ [[0..3, 'a'],
79
+ [4..6, 'b'],
80
+ [7..9, 'c'],
81
+ [10..12, 'd']]
82
82
  end
83
83
 
84
84
  subject(:tree) { SegmentTree.new(data, true) }
85
85
 
86
- it { should be_a SegmentTree }
87
- it { should query(8).and_return("c") }
86
+ it { is_expected.to be_a SegmentTree }
87
+ it { is_expected.to query(8).and_return('c') }
88
88
  end
89
89
 
90
- context "given nor hash neither array" do
90
+ context 'given nor hash neither array' do
91
91
  it { expect{ SegmentTree.new(Object.new) }.to raise_error(ArgumentError) }
92
92
  end
93
93
 
94
- context "given 1-dimensional array" do
94
+ context 'given 1-dimensional array' do
95
95
  let :data do
96
- [0..3, "a",
97
- 4..6, "b",
98
- 7..9, "c",
99
- 10..12, "d"]
96
+ [0..3, 'a',
97
+ 4..6, 'b',
98
+ 7..9, 'c',
99
+ 10..12, 'd']
100
100
  end
101
101
 
102
102
  it { expect{ SegmentTree.new(data) }.to raise_error(ArgumentError) }
103
103
  end
104
104
  end
105
105
 
106
- describe "querying" do
107
- context "given spanned intervals" do
106
+ describe 'querying' do
107
+ context 'given spanned intervals' do
108
108
  subject { SegmentTree.new(sample_spanned) }
109
109
 
110
- it { should query(12).and_return('b') }
111
- it { should query(101).and_return(:nothing) }
110
+ it { is_expected.to query(12).and_return('b') }
111
+ it { is_expected.to query(101).and_return(:nothing) }
112
112
  end
113
113
 
114
- context "given partially overlapping intervals" do
114
+ context 'given partially overlapping intervals' do
115
115
  subject { SegmentTree.new(sample_overlapping) }
116
116
 
117
- it { should query(11).and_return('a') }
117
+ it { is_expected.to query(11).and_return('a') }
118
118
  end
119
119
 
120
- context "given sparsed intervals" do
120
+ context 'given sparsed intervals' do
121
121
  subject { SegmentTree.new(sample_sparsed) }
122
122
 
123
- it { should query(12).and_return('b') }
124
- it { should query(8).and_return(:nothing) }
123
+ it { is_expected.to query(12).and_return('b') }
124
+ it { is_expected.to query(8).and_return(:nothing) }
125
125
  end
126
126
 
127
- context "given hardly overlapping intervals" do
127
+ context 'given hardly overlapping intervals' do
128
128
  subject { SegmentTree.new(sample_overlapping2) }
129
129
 
130
- it { should query(12).and_return('b') }
131
- it { should query(8).and_return(:nothing) }
130
+ it { is_expected.to query(12).and_return('b') }
131
+ it { is_expected.to query(8).and_return(:nothing) }
132
132
  end
133
133
  end
134
- end
134
+
135
+ describe '#==' do
136
+ subject { SegmentTree.new(sample_overlapping) }
137
+
138
+ it { is_expected.to eq(SegmentTree.new(sample_overlapping)) }
139
+ it { is_expected.not_to eq(SegmentTree.new(sample_overlapping2)) }
140
+
141
+ it 'is equal when a range coerces' do
142
+ expect(SegmentTree.new((1..2) => "a")).to eq(SegmentTree.new(((1.0)..(2.0)) => "a"))
143
+ end
144
+
145
+ it 'is equal when a value coerces' do
146
+ expect(SegmentTree.new((1..2) => 1)).to eq(SegmentTree.new((1..2) => 1.0))
147
+ end
148
+
149
+ it "isn't equal when only a range is different" do
150
+ expect(SegmentTree.new((1..2) => "a")).not_to eq(SegmentTree.new((1..3) => "a"))
151
+ end
152
+
153
+ it "isn't equal when only a value is different" do
154
+ expect(SegmentTree.new((1..2) => "a")).not_to eq(SegmentTree.new((1..2) => "b"))
155
+ end
156
+ end
157
+
158
+ describe '#eql?' do
159
+ subject { SegmentTree.new(sample_overlapping) }
160
+
161
+ it { is_expected.to be_eql(SegmentTree.new(sample_overlapping)) }
162
+ it { is_expected.not_to be_eql(SegmentTree.new(sample_overlapping2)) }
163
+
164
+ it "isn't equal when a range coerces" do
165
+ expect(SegmentTree.new((1..2) => "a")).not_to be_eql(SegmentTree.new(((1.0)..(2.0)) => "a"))
166
+ end
167
+
168
+ it "isn't equal when a value coerces" do
169
+ expect(SegmentTree.new((1..2) => 1)).not_to be_eql(SegmentTree.new((1..2) => 1.0))
170
+ end
171
+
172
+ it "isn't equal when only a range is different" do
173
+ expect(SegmentTree.new((1..2) => "a")).not_to be_eql(SegmentTree.new((1..3) => "a"))
174
+ end
175
+
176
+ it "isn't equal when only a value is different" do
177
+ expect(SegmentTree.new((1..2) => "a")).not_to be_eql(SegmentTree.new((1..2) => "b"))
178
+ end
179
+ end
180
+
181
+ describe '#hash' do
182
+ subject { SegmentTree.new(sample_overlapping).hash }
183
+
184
+ it { is_expected.to eq(SegmentTree.new(sample_overlapping).hash) }
185
+ it { is_expected.not_to eq(SegmentTree.new(sample_overlapping2).hash) }
186
+
187
+ it "isn't equal when only a range is different" do
188
+ expect(SegmentTree.new((1..2) => "a").hash).not_to eq(SegmentTree.new((1..3) => "a").hash)
189
+ end
190
+
191
+ it "isn't equal when only a value is different" do
192
+ expect(SegmentTree.new((1..2) => "a").hash).not_to eq(SegmentTree.new((1..2) => "b").hash)
193
+ end
194
+ end
195
+
196
+ describe 'marshaling' do
197
+ it 'dumps and loads successfully' do
198
+ aggregate_failures do
199
+ [
200
+ sample_spanned,
201
+ sample_sparsed,
202
+ sample_overlapping,
203
+ sample_overlapping2,
204
+ ].each do |sample|
205
+ tree = SegmentTree.new(sample)
206
+ dumped = Marshal.dump(tree)
207
+ expect(Marshal.load(dumped)).to eq(tree)
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "bundler/setup"
1
+ require 'bundler/setup'
2
2
 
3
3
  RSpec.configure do |config|
4
4
  # Run specs in random order to surface order dependencies. If you find an
@@ -9,8 +9,8 @@ RSpec.configure do |config|
9
9
  end
10
10
 
11
11
  if defined?(RUBY_ENGINE) &&
12
- RUBY_ENGINE == "ruby" &&
13
- RUBY_VERSION > "1.9"
14
- require "simplecov"
12
+ RUBY_ENGINE == 'ruby' &&
13
+ RUBY_VERSION > '1.9'
14
+ require 'simplecov'
15
15
  SimpleCov.start
16
16
  end
metadata CHANGED
@@ -1,48 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: segment_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Alexei Mikhailov
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-08-06 00:00:00.000000000 Z
11
+ date: 2023-03-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '1.0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '1.0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
- version: '2.11'
33
+ version: 3.1.0
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
- version: '2.11'
40
+ version: 3.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
46
55
  description: Tree data structure for storing segments. It allows querying which of
47
56
  the stored segments contain a given point.
48
57
  email: amikhailov83@gmail.com
@@ -50,7 +59,7 @@ executables: []
50
59
  extensions: []
51
60
  extra_rdoc_files: []
52
61
  files:
53
- - .rspec
62
+ - ".rspec"
54
63
  - lib/segment_tree.rb
55
64
  - lib/segment_tree/version.rb
56
65
  - segment_tree.gemspec
@@ -58,31 +67,29 @@ files:
58
67
  - spec/spec_helper.rb
59
68
  homepage: https://github.com/take-five/segment_tree
60
69
  licenses: []
61
- post_install_message:
70
+ metadata: {}
71
+ post_install_message:
62
72
  rdoc_options: []
63
73
  require_paths:
64
74
  - lib
65
75
  required_ruby_version: !ruby/object:Gem::Requirement
66
- none: false
67
76
  requirements:
68
- - - ! '>='
77
+ - - ">="
69
78
  - !ruby/object:Gem::Version
70
79
  version: '0'
71
80
  required_rubygems_version: !ruby/object:Gem::Requirement
72
- none: false
73
81
  requirements:
74
- - - ! '>='
82
+ - - ">="
75
83
  - !ruby/object:Gem::Version
76
84
  version: '0'
77
85
  requirements: []
78
- rubyforge_project:
79
- rubygems_version: 1.8.24
80
- signing_key:
81
- specification_version: 3
86
+ rubygems_version: 3.3.7
87
+ signing_key:
88
+ specification_version: 4
82
89
  summary: Tree data structure for storing segments. It allows querying which of the
83
90
  stored segments contain a given point.
84
91
  test_files:
85
- - .rspec
92
+ - ".rspec"
86
93
  - segment_tree.gemspec
87
94
  - spec/segment_tree_spec.rb
88
95
  - spec/spec_helper.rb