range_set 0.0.1 → 0.0.2

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.
@@ -1,21 +1,30 @@
1
+ require 'rbtree'
2
+
1
3
  class RangeSet
2
- attr_accessor :ranges
4
+
5
+ def ranges
6
+ @rbtree.values
7
+ end
3
8
 
4
9
  def initialize(*ranges)
5
- @ranges = []
10
+ @rbtree = RBTree.new
6
11
  ranges.each do |r|
7
12
  union_with_range!(r)
8
13
  end
9
14
  self
10
15
  end
16
+
17
+ def clone
18
+ result = super
19
+ result.send(:rbtree=, result.send(:rbtree).clone)
20
+ result
21
+ end
11
22
 
12
23
  def intersect!(r)
13
24
  if r.is_a?(Range)
14
25
  intersect_with_range!(r)
15
26
  elsif r.is_a?(RangeSet)
16
- @ranges = r.ranges.inject(RangeSet.new) do |accum, range|
17
- accum + (self & range)
18
- end.ranges
27
+ intersect_with_rangeset!(r)
19
28
  end
20
29
  self
21
30
  end
@@ -28,7 +37,7 @@ class RangeSet
28
37
  if r.is_a?(Range)
29
38
  subtract_range!(r)
30
39
  elsif r.is_a?(RangeSet)
31
- r.each {|r| subtract_range!(r)}
40
+ subtract_rangeset!(r)
32
41
  end
33
42
  self
34
43
  end
@@ -41,7 +50,7 @@ class RangeSet
41
50
  if r.is_a?(Range)
42
51
  union_with_range!(r)
43
52
  elsif r.is_a?(RangeSet)
44
- r.each {|r| union_with_range!(r)}
53
+ union_with_rangeset!(r)
45
54
  end
46
55
  self
47
56
  end
@@ -51,61 +60,52 @@ class RangeSet
51
60
  end
52
61
 
53
62
  def each
54
- @ranges.each {|r| yield r}
63
+ @rbtree.each_value {|r| yield r}
55
64
  end
56
65
 
57
- #returns an array of RangeSets
58
- def split_at(*boundaries)
59
- result = []
60
- rs = RangeSet.new
61
- ranges = @ranges.clone
62
- boundaries.compact.sort.uniq.each do |boundary|
63
-
64
- while (range = ranges.shift)
65
- if range.end <= boundary
66
- rs += range
67
- elsif range.begin >= boundary
68
- ranges.unshift(range)
69
- break
70
- else
71
- rs += (range.begin .. boundary)
72
- ranges.unshift(boundary .. range.end)
73
- break
74
- end
75
- end
76
-
77
- unless rs.empty?
78
- result << rs
79
- rs = RangeSet.new
80
- end
81
- end
82
- result << RangeSet.new(*ranges) unless ranges.empty?
83
- result
84
- end
66
+ # #returns an array of RangeSets
67
+ # def split_at(*boundaries)
68
+ # result = []
69
+ # rs = RangeSet.new
70
+ # ranges = @rbtree.clone
71
+ # boundaries.compact.sort.uniq.each do |boundary|
72
+ # while (range = ranges.shift)
73
+ # if range.end <= boundary
74
+ # rs += range
75
+ # elsif range.begin >= boundary
76
+ # ranges.unshift(range)
77
+ # break
78
+ # else
79
+ # rs += (range.begin .. boundary)
80
+ # ranges.unshift(boundary .. range.end)
81
+ # break
82
+ # end
83
+ # end
84
+ # unless rs.empty?
85
+ # result << rs
86
+ # rs = RangeSet.new
87
+ # end
88
+ # end
89
+ # result << RangeSet.new(*ranges) unless ranges.empty?
90
+ # result
91
+ # end
85
92
 
86
93
  # TODO : need to be more explicit and careful about
87
94
  # whether or not a range's end is inclusive. For now,
88
95
  # we just assume that it's NOT inclusive.
89
96
  def include?(v)
90
- if v.is_a?(Range)
91
- each do |range|
92
- return true if range.begin <= v.begin && v.begin <= v.end && v.end <= range.end
93
- end
94
- elsif v.is_a?(RangeSet)
95
- v.ranges.each do |range|
96
- return false unless self.include?(range)
97
- end
98
- return true
97
+ case v
98
+ when Range
99
+ include_range?(v)
100
+ when RangeSet
101
+ include_rangeset?(v)
99
102
  else
100
- each do |range|
101
- return true if range.begin <= v && v < range.end
102
- end
103
+ include_scalar?(v)
103
104
  end
104
- false
105
105
  end
106
106
 
107
107
  def empty?
108
- @ranges.empty?
108
+ @rbtree.empty?
109
109
  end
110
110
 
111
111
  alias :- :subtract
@@ -114,60 +114,89 @@ class RangeSet
114
114
  alias :& :intersect
115
115
 
116
116
  private
117
+
118
+ attr_accessor :rbtree
117
119
 
118
120
  def subtract_range!(r)
119
121
  return if r.begin == r.end
120
122
  r = (r.end .. r.begin) unless r.begin < r.end
121
- result = []
122
- each do |range|
123
- if range.end < r.begin
124
- result << range
125
- elsif range.begin > r.end
126
- result << range
127
- else
128
- result << (range.begin .. r.begin) if range.begin < r.begin
129
- result << (r.end .. range.end) if range.end > r.end
130
- end
123
+ x, previous_range = @rbtree.upper_bound(r.begin)
124
+ @rbtree.bound([x,r.begin].compact.min, r.end).each do |key, range|
125
+ @rbtree.delete(key)
126
+ front_range = (range.begin .. [r.begin, range.end].min)
127
+ back_range = ([range.begin,r.end].max .. range.end)
128
+ @rbtree[front_range.begin] = front_range if front_range.begin < front_range.end
129
+ @rbtree[back_range.begin] = back_range if back_range.begin < back_range.end
130
+ end
131
+ end
132
+
133
+ def subtract_rangeset!(r)
134
+ r.each do |range|
135
+ subtract_range!(range)
131
136
  end
132
- @ranges = result
133
137
  end
134
138
 
135
139
  def intersect_with_range!(r)
136
140
  if r.begin == r.end
137
- @ranges = []
141
+ @rbtree = RBTree.new
138
142
  return
139
143
  elsif r.begin > r.end
140
144
  r = (r.end .. r.begin)
141
145
  end
142
- result = []
143
- each do |range|
144
- r2 = ([range.begin, r.begin].max .. [range.end, r.end].min)
145
- if (r2.begin < r2.end)
146
- result << r2
147
- end
146
+ replacement = RBTree.new
147
+ x, previous_range = @rbtree.upper_bound(r.begin)
148
+ @rbtree.bound([x,r.begin].compact.min, r.end) do |key, range|
149
+ range = ([range.begin,r.begin].max .. [range.end,r.end].min)
150
+ replacement[range.begin] = range if range.begin < range.end
151
+ end
152
+ @rbtree = replacement
153
+ end
154
+
155
+ def intersect_with_rangeset!(r)
156
+ #TODO: This could be greatly optimized!
157
+ replacement = RangeSet.new
158
+ r.each do |range|
159
+ replacement += self & range
148
160
  end
149
- @ranges = result
161
+ @rbtree = replacement.send(:rbtree)
150
162
  end
151
163
 
152
164
  def union_with_range!(r)
153
165
  return if r.begin == r.end
154
- joined = (r.begin < r.end) ? r : (r.end .. r.begin)
155
- still_need_joined = true
156
- result = []
157
- each do |range|
158
- if range.end < joined.begin
159
- result << range
160
- elsif range.end == joined.begin
161
- joined = (range.begin .. joined.end)
162
- elsif range.begin > joined.end
163
- result << joined if still_need_joined
164
- still_need_joined = false
165
- result << range
166
- else
167
- joined = ([range.begin,joined.begin].min .. [range.end,joined.end].max)
168
- end
166
+ r = (r.begin < r.end) ? r : (r.end .. r.begin)
167
+ @rbtree.bound(r.begin, r.end) do |key, range|
168
+ range = @rbtree.delete(key)
169
+ r = ([r.begin, range.begin].min .. [r.end, range.end].max)
170
+ end
171
+ x, previous_range = @rbtree.upper_bound(r.begin)
172
+ if previous_range && previous_range.end >= r.begin
173
+ @rbtree.delete(x)
174
+ r = (x .. r.end)
175
+ end
176
+ @rbtree[r.begin] = r
177
+ end
178
+
179
+ def union_with_rangeset!(r)
180
+ r.each do |range|
181
+ union_with_range!(range)
182
+ end
183
+ end
184
+
185
+ def include_scalar?(v)
186
+ x, previous_range = @rbtree.upper_bound(v)
187
+ previous_range && v < previous_range.end
188
+ end
189
+
190
+ def include_range?(r)
191
+ x, previous_range = @rbtree.upper_bound(r.begin)
192
+ previous_range && r.end <= previous_range.end
193
+ end
194
+
195
+ def include_rangeset?(r)
196
+ r.each do |range|
197
+ return false unless include_range?(range)
169
198
  end
170
- result << joined if still_need_joined
171
- @ranges = result
199
+ true
172
200
  end
201
+
173
202
  end
@@ -1,3 +1,3 @@
1
1
  class RangeSet
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
+ s.add_dependency "rbtree-pure", "~> 0.1"
20
21
  s.add_development_dependency "rspec", "~> 2.6"
21
22
  s.add_development_dependency "simplecov", "~> 0.4"
22
23
  s.add_development_dependency("rb-fsevent", "~> 0.4") if RUBY_PLATFORM =~ /darwin/i
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: range_set
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Chris Johnson
@@ -15,13 +15,28 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-02 00:00:00 -05:00
18
+ date: 2011-08-03 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: rspec
22
+ name: rbtree-pure
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 9
30
+ segments:
31
+ - 0
32
+ - 1
33
+ version: "0.1"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
25
40
  none: false
26
41
  requirements:
27
42
  - - ~>
@@ -32,11 +47,11 @@ dependencies:
32
47
  - 6
33
48
  version: "2.6"
34
49
  type: :development
35
- version_requirements: *id001
50
+ version_requirements: *id002
36
51
  - !ruby/object:Gem::Dependency
37
52
  name: simplecov
38
53
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
54
+ requirement: &id003 !ruby/object:Gem::Requirement
40
55
  none: false
41
56
  requirements:
42
57
  - - ~>
@@ -47,11 +62,11 @@ dependencies:
47
62
  - 4
48
63
  version: "0.4"
49
64
  type: :development
50
- version_requirements: *id002
65
+ version_requirements: *id003
51
66
  - !ruby/object:Gem::Dependency
52
67
  name: rb-fsevent
53
68
  prerelease: false
54
- requirement: &id003 !ruby/object:Gem::Requirement
69
+ requirement: &id004 !ruby/object:Gem::Requirement
55
70
  none: false
56
71
  requirements:
57
72
  - - ~>
@@ -62,11 +77,11 @@ dependencies:
62
77
  - 4
63
78
  version: "0.4"
64
79
  type: :development
65
- version_requirements: *id003
80
+ version_requirements: *id004
66
81
  - !ruby/object:Gem::Dependency
67
82
  name: guard
68
83
  prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
84
+ requirement: &id005 !ruby/object:Gem::Requirement
70
85
  none: false
71
86
  requirements:
72
87
  - - ~>
@@ -77,11 +92,11 @@ dependencies:
77
92
  - 5
78
93
  version: "0.5"
79
94
  type: :development
80
- version_requirements: *id004
95
+ version_requirements: *id005
81
96
  - !ruby/object:Gem::Dependency
82
97
  name: guard-bundler
83
98
  prerelease: false
84
- requirement: &id005 !ruby/object:Gem::Requirement
99
+ requirement: &id006 !ruby/object:Gem::Requirement
85
100
  none: false
86
101
  requirements:
87
102
  - - ~>
@@ -92,11 +107,11 @@ dependencies:
92
107
  - 1
93
108
  version: "0.1"
94
109
  type: :development
95
- version_requirements: *id005
110
+ version_requirements: *id006
96
111
  - !ruby/object:Gem::Dependency
97
112
  name: guard-rspec
98
113
  prerelease: false
99
- requirement: &id006 !ruby/object:Gem::Requirement
114
+ requirement: &id007 !ruby/object:Gem::Requirement
100
115
  none: false
101
116
  requirements:
102
117
  - - ~>
@@ -107,7 +122,7 @@ dependencies:
107
122
  - 4
108
123
  version: "0.4"
109
124
  type: :development
110
- version_requirements: *id006
125
+ version_requirements: *id007
111
126
  description: Set implementation based on ranges
112
127
  email:
113
128
  - chris@kindkid.com