segment_tree 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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