range_list 1.1.0 → 1.3.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 +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +0 -1
- data/lib/range_list/avl_tree/abstract_adapter.rb +28 -0
- data/lib/range_list/avl_tree/rbtree_adapter.rb +39 -0
- data/lib/range_list/version.rb +1 -1
- data/lib/range_list.rb +44 -43
- data/range_list.gemspec +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bac3ba3fced62c57e3d3fafa0f1999667172d7083defe6ec6404ca8ecfb83af0
|
4
|
+
data.tar.gz: 12708960354b2930dd49ff8ee80e8b809340c8b8447953baac65351a914ad73b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebfdde12a2eca743326ffd44db017c23ff1ed796af325b4c0c0b1953cee76c427dd1a0ebf3d91e3a5674a2767332925881978292569fed01fca9ee30f5f55c28
|
7
|
+
data.tar.gz: dc711a4f3cf7a4157b11d9b0d7976f5411801f330daf7d501c427518434b3d3eb113f6d7aa3a65f019662bf230cf7f50f67b18266e4cc217ff3d6b2315d2c28b
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
range_list (1.1
|
5
|
-
|
4
|
+
range_list (1.3.1)
|
5
|
+
rbtree (~> 0.4.5)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
@@ -15,6 +15,7 @@ GEM
|
|
15
15
|
ast (~> 2.4.1)
|
16
16
|
rainbow (3.1.1)
|
17
17
|
rake (13.0.6)
|
18
|
+
rbtree (0.4.5)
|
18
19
|
regexp_parser (2.2.1)
|
19
20
|
rexml (3.2.5)
|
20
21
|
rubocop (1.25.1)
|
@@ -44,7 +45,6 @@ GEM
|
|
44
45
|
standard (1.7.2)
|
45
46
|
rubocop (= 1.25.1)
|
46
47
|
rubocop-performance (= 1.13.2)
|
47
|
-
treemap (1.0.3)
|
48
48
|
unicode-display_width (2.1.0)
|
49
49
|
webrick (1.7.0)
|
50
50
|
yard (0.9.27)
|
data/README.md
CHANGED
@@ -10,7 +10,6 @@ RangeList use AVL Tree processing internally, so range operations are very fast.
|
|
10
10
|
[](https://rubygems.org/gems/range_list)
|
11
11
|
[](https://rubydoc.info/gems/range_list)
|
12
12
|
[](https://gitlab.com/songhuangcn/range_list/-/commits/main)
|
13
|
-
[](https://gitlab.com/songhuangcn/range_list/-/commits/main)
|
14
13
|
|
15
14
|
## Installation
|
16
15
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RangeList
|
4
|
+
# @!visibility private
|
5
|
+
module AvlTree
|
6
|
+
class AbstractAdapter
|
7
|
+
def put(key, value)
|
8
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
9
|
+
end
|
10
|
+
|
11
|
+
def lower_entry(key)
|
12
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
13
|
+
end
|
14
|
+
|
15
|
+
def sub_map(from_key, to_key)
|
16
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove(key)
|
20
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rbtree"
|
4
|
+
require_relative "abstract_adapter"
|
5
|
+
|
6
|
+
class RangeList
|
7
|
+
# @!visibility private
|
8
|
+
module AvlTree
|
9
|
+
class RBTreeAdapter < AbstractAdapter
|
10
|
+
def initialize
|
11
|
+
@rbtree = RBTree.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def put(key, value)
|
15
|
+
rbtree[key] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def lower_entry(key)
|
19
|
+
rbtree.upper_bound(key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def sub_map(from_key, to_key)
|
23
|
+
rbtree.bound(from_key, to_key).to_a
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove(key)
|
27
|
+
rbtree.delete(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def each(&block)
|
31
|
+
rbtree.each(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :rbtree
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/range_list/version.rb
CHANGED
data/lib/range_list.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "treemap"
|
4
|
-
require_relative "range_list/version"
|
5
3
|
require_relative "range_list/errors"
|
4
|
+
require_relative "range_list/avl_tree/rbtree_adapter"
|
6
5
|
|
7
6
|
class RangeList
|
8
7
|
include Enumerable
|
9
8
|
|
10
9
|
def initialize
|
11
|
-
@
|
10
|
+
@avl_tree = AvlTree::RBTreeAdapter.new
|
12
11
|
end
|
13
12
|
|
14
13
|
# Add range into current range list.
|
@@ -18,32 +17,30 @@ class RangeList
|
|
18
17
|
# @raise [ArgumentError] when argement invalid
|
19
18
|
def add(range)
|
20
19
|
validate_range!(range)
|
21
|
-
|
22
|
-
# Return when range is empty.
|
23
20
|
return self if empty_range?(range)
|
24
21
|
|
25
22
|
# Get real range start.
|
26
|
-
|
27
|
-
range_start = if !
|
28
|
-
|
23
|
+
start_lower_range = avl_tree.lower_entry(range[0])
|
24
|
+
range_start = if !start_lower_range.nil? && start_lower_range[1] >= range[0]
|
25
|
+
start_lower_range[0]
|
29
26
|
else
|
30
27
|
range[0]
|
31
28
|
end
|
32
29
|
|
33
30
|
# Get real range end.
|
34
|
-
|
35
|
-
range_end = if !
|
36
|
-
|
31
|
+
end_lower_range = avl_tree.lower_entry(range[1])
|
32
|
+
range_end = if !end_lower_range.nil? && end_lower_range[1] >= range[1]
|
33
|
+
end_lower_range[1]
|
37
34
|
else
|
38
35
|
range[1]
|
39
36
|
end
|
40
37
|
|
41
38
|
# Insert or replace new range.
|
42
|
-
|
39
|
+
avl_tree.put(range_start, range_end)
|
43
40
|
|
44
41
|
# Remove keys between range, exclude start, include end.
|
45
|
-
|
46
|
-
|
42
|
+
sub_range = avl_tree.sub_map(range[0] + 1, range[1])
|
43
|
+
sub_range.each { |range_start, _range_end| avl_tree.remove(range_start) }
|
47
44
|
|
48
45
|
self
|
49
46
|
end
|
@@ -54,25 +51,23 @@ class RangeList
|
|
54
51
|
# @raise (see #add)
|
55
52
|
def remove(range)
|
56
53
|
validate_range!(range)
|
57
|
-
|
58
|
-
# Return when range is empty.
|
59
54
|
return self if empty_range?(range)
|
60
55
|
|
61
|
-
# Insert end lower
|
62
|
-
|
63
|
-
if !
|
64
|
-
|
56
|
+
# Insert end lower range, `-1` means not include.
|
57
|
+
end_lower_range = avl_tree.lower_entry(range[1] - 1)
|
58
|
+
if !end_lower_range.nil? && end_lower_range[1] > range[1]
|
59
|
+
avl_tree.put(range[1], end_lower_range[1])
|
65
60
|
end
|
66
61
|
|
67
|
-
# Relace start lower
|
68
|
-
|
69
|
-
if !
|
70
|
-
|
62
|
+
# Relace start lower range, `-1` means not include.
|
63
|
+
start_lower_range = avl_tree.lower_entry(range[0] - 1)
|
64
|
+
if !start_lower_range.nil? && start_lower_range[1] > range[0]
|
65
|
+
avl_tree.put(start_lower_range[0], range[0])
|
71
66
|
end
|
72
67
|
|
73
68
|
# Remove keys between range, include start, exclude end
|
74
|
-
|
75
|
-
|
69
|
+
sub_range = avl_tree.sub_map(range[0], range[1] - 1)
|
70
|
+
sub_range.each { |range_start, _range_end| avl_tree.remove(range_start) }
|
76
71
|
|
77
72
|
self
|
78
73
|
end
|
@@ -80,7 +75,8 @@ class RangeList
|
|
80
75
|
# Print current range list.
|
81
76
|
# @return [void]
|
82
77
|
def print
|
83
|
-
|
78
|
+
info = map { |k, v| "[#{k}, #{v})" }.join(" ")
|
79
|
+
puts info
|
84
80
|
end
|
85
81
|
|
86
82
|
# Returns true if current ranges contains all elements of the range.
|
@@ -90,12 +86,10 @@ class RangeList
|
|
90
86
|
# @raise (see #add)
|
91
87
|
def contains_all?(range)
|
92
88
|
validate_range!(range)
|
93
|
-
|
94
|
-
# Return false when range is empty.
|
95
89
|
return false if empty_range?(range)
|
96
90
|
|
97
|
-
|
98
|
-
!
|
91
|
+
start_lower_range = avl_tree.lower_entry(range[0])
|
92
|
+
!start_lower_range.nil? && start_lower_range[1] >= range[1]
|
99
93
|
end
|
100
94
|
|
101
95
|
# Returns true if current ranges contains any element of the range.
|
@@ -105,12 +99,11 @@ class RangeList
|
|
105
99
|
# @raise (see #add)
|
106
100
|
def contains_any?(range)
|
107
101
|
validate_range!(range)
|
108
|
-
|
109
|
-
# Return false when range is empty.
|
110
102
|
return false if empty_range?(range)
|
111
103
|
|
112
|
-
|
113
|
-
|
104
|
+
# `-1` means not include.
|
105
|
+
end_lower_range = avl_tree.lower_entry(range[1] - 1)
|
106
|
+
!end_lower_range.nil? && end_lower_range[1] > range[0]
|
114
107
|
end
|
115
108
|
|
116
109
|
# Returns true if current ranges contains the element.
|
@@ -118,19 +111,19 @@ class RangeList
|
|
118
111
|
# @return [Boolean]
|
119
112
|
# @raise (see #add)
|
120
113
|
def contains?(element)
|
121
|
-
|
114
|
+
validate_element!(element)
|
122
115
|
|
123
|
-
|
124
|
-
!
|
116
|
+
lower_entry = avl_tree.lower_entry(element)
|
117
|
+
!lower_entry.nil? && lower_entry[1] > element
|
125
118
|
end
|
126
119
|
|
127
120
|
# Give RangeList iterative ability.
|
121
|
+
# @return [RangeList, Enumerator]
|
128
122
|
# @yield [range_start, range_end] give the range element to the block
|
129
123
|
def each(&block)
|
130
124
|
if block
|
131
|
-
|
132
|
-
|
133
|
-
tree.empty? ? self : tree.each(&block)
|
125
|
+
avl_tree.each(&block)
|
126
|
+
self
|
134
127
|
else
|
135
128
|
enum_for(:each)
|
136
129
|
end
|
@@ -138,12 +131,16 @@ class RangeList
|
|
138
131
|
|
139
132
|
# @!visibility private
|
140
133
|
def inspect
|
141
|
-
|
134
|
+
data = map { |k, v| "[#{k}, #{v})" }.join(", ")
|
135
|
+
"[#{data}]"
|
142
136
|
end
|
143
137
|
|
138
|
+
# @!visibility private
|
139
|
+
alias_method :to_s, :inspect
|
140
|
+
|
144
141
|
private
|
145
142
|
|
146
|
-
attr_reader :
|
143
|
+
attr_reader :avl_tree
|
147
144
|
|
148
145
|
def validate_range!(range)
|
149
146
|
raise ArgumentError, "`range` should be `Array` type." unless range.is_a?(Array)
|
@@ -151,6 +148,10 @@ class RangeList
|
|
151
148
|
raise ArgumentError, "All elements of `range` should be `Integer`." unless range.all? { |item| item.is_a?(Integer) }
|
152
149
|
end
|
153
150
|
|
151
|
+
def validate_element!(element)
|
152
|
+
raise ArgumentError, "`element` should be `Integer` type." unless element.is_a?(Integer)
|
153
|
+
end
|
154
|
+
|
154
155
|
def empty_range?(range)
|
155
156
|
range[0] >= range[1]
|
156
157
|
end
|
data/range_list.gemspec
CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
# Uncomment to register a new dependency of your gem
|
36
36
|
# spec.add_dependency "example-gem", "~> 1.0"
|
37
|
-
spec.add_dependency "
|
37
|
+
spec.add_dependency "rbtree", "~> 0.4.5"
|
38
38
|
|
39
39
|
# For more information and examples about making a new gem, check out our
|
40
40
|
# guide at: https://bundler.io/guides/creating_gem.html
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: range_list
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Song Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rbtree
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.4.5
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.4.5
|
27
27
|
description:
|
28
28
|
email:
|
29
29
|
- songhuangcn@gmail.com
|
@@ -37,6 +37,8 @@ files:
|
|
37
37
|
- README.md
|
38
38
|
- Rakefile
|
39
39
|
- lib/range_list.rb
|
40
|
+
- lib/range_list/avl_tree/abstract_adapter.rb
|
41
|
+
- lib/range_list/avl_tree/rbtree_adapter.rb
|
40
42
|
- lib/range_list/errors.rb
|
41
43
|
- lib/range_list/version.rb
|
42
44
|
- range_list.gemspec
|