range_list 1.2.0 → 1.3.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/Gemfile.lock +1 -1
- 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 +32 -30
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ea59292d297f5583f7a9ceddaf8194cbd33704180c3e43f15fe87358c8d02d5
|
4
|
+
data.tar.gz: f8ea601a80d2261c1b869aa57699bd0c71d048b4a94b25b978d67d1636d426b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52b7dd400bb94273b9e0ff1702db7d5bd328f88e425322ba3838cc859e4629f0f5f2776bcedec7f73ba90ca0936b8f661fd435bde89bf67bbfdede88c93f62b5
|
7
|
+
data.tar.gz: af2aee3e2b4c37cdffbe89518423ea037b3348db50c9bfeff3b27259f6ff54f055265c3cbfb7c5ec7a9bc7410baa475e1d2f59be0259a5061b2e5197bd8e7280
|
data/Gemfile.lock
CHANGED
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,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "rbtree"
|
4
3
|
require_relative "range_list/version"
|
5
4
|
require_relative "range_list/errors"
|
5
|
+
require_relative "range_list/avl_tree/rbtree_adapter"
|
6
6
|
|
7
7
|
class RangeList
|
8
8
|
include Enumerable
|
9
9
|
|
10
10
|
def initialize
|
11
|
-
@
|
11
|
+
@avl_tree = AvlTree::RBTreeAdapter.new
|
12
12
|
end
|
13
13
|
|
14
14
|
# Add range into current range list.
|
@@ -23,27 +23,27 @@ class RangeList
|
|
23
23
|
return self if empty_range?(range)
|
24
24
|
|
25
25
|
# Get real range start.
|
26
|
-
|
27
|
-
range_start = if !
|
28
|
-
|
26
|
+
start_lower_range = avl_tree.lower_entry(range[0])
|
27
|
+
range_start = if !start_lower_range.nil? && start_lower_range[1] >= range[0]
|
28
|
+
start_lower_range[0]
|
29
29
|
else
|
30
30
|
range[0]
|
31
31
|
end
|
32
32
|
|
33
33
|
# Get real range end.
|
34
|
-
|
35
|
-
range_end = if !
|
36
|
-
|
34
|
+
end_lower_range = avl_tree.lower_entry(range[1])
|
35
|
+
range_end = if !end_lower_range.nil? && end_lower_range[1] >= range[1]
|
36
|
+
end_lower_range[1]
|
37
37
|
else
|
38
38
|
range[1]
|
39
39
|
end
|
40
40
|
|
41
41
|
# Insert or replace new range.
|
42
|
-
|
42
|
+
avl_tree.put(range_start, range_end)
|
43
43
|
|
44
44
|
# Remove keys between range, exclude start, include end.
|
45
|
-
|
46
|
-
|
45
|
+
sub_range = avl_tree.sub_map(range[0] + 1, range[1])
|
46
|
+
sub_range.each { |range_start, _range_end| avl_tree.remove(range_start) }
|
47
47
|
|
48
48
|
self
|
49
49
|
end
|
@@ -58,21 +58,21 @@ class RangeList
|
|
58
58
|
# Return when range is empty.
|
59
59
|
return self if empty_range?(range)
|
60
60
|
|
61
|
-
# Insert end lower
|
62
|
-
|
63
|
-
if !
|
64
|
-
|
61
|
+
# Insert end lower range, `-1` means not include.
|
62
|
+
end_lower_range = avl_tree.lower_entry(range[1] - 1)
|
63
|
+
if !end_lower_range.nil? && end_lower_range[1] > range[1]
|
64
|
+
avl_tree.put(range[1], end_lower_range[1])
|
65
65
|
end
|
66
66
|
|
67
|
-
# Relace start lower
|
68
|
-
|
69
|
-
if !
|
70
|
-
|
67
|
+
# Relace start lower range, `-1` means not include.
|
68
|
+
start_lower_range = avl_tree.lower_entry(range[0] - 1)
|
69
|
+
if !start_lower_range.nil? && start_lower_range[1] > range[0]
|
70
|
+
avl_tree.put(start_lower_range[0], range[0])
|
71
71
|
end
|
72
72
|
|
73
73
|
# Remove keys between range, include start, exclude end
|
74
|
-
|
75
|
-
|
74
|
+
sub_range = avl_tree.sub_map(range[0], range[1] - 1)
|
75
|
+
sub_range.each { |range_start, _range_end| avl_tree.remove(range_start) }
|
76
76
|
|
77
77
|
self
|
78
78
|
end
|
@@ -80,7 +80,8 @@ class RangeList
|
|
80
80
|
# Print current range list.
|
81
81
|
# @return [void]
|
82
82
|
def print
|
83
|
-
|
83
|
+
info = map { |k, v| "[#{k}, #{v})" }.join(" ")
|
84
|
+
puts info
|
84
85
|
end
|
85
86
|
|
86
87
|
# Returns true if current ranges contains all elements of the range.
|
@@ -94,8 +95,8 @@ class RangeList
|
|
94
95
|
# Return false when range is empty.
|
95
96
|
return false if empty_range?(range)
|
96
97
|
|
97
|
-
|
98
|
-
!
|
98
|
+
start_lower_range = avl_tree.lower_entry(range[0])
|
99
|
+
!start_lower_range.nil? && start_lower_range[1] >= range[1]
|
99
100
|
end
|
100
101
|
|
101
102
|
# Returns true if current ranges contains any element of the range.
|
@@ -109,8 +110,9 @@ class RangeList
|
|
109
110
|
# Return false when range is empty.
|
110
111
|
return false if empty_range?(range)
|
111
112
|
|
112
|
-
|
113
|
-
|
113
|
+
# `-1` means not include.
|
114
|
+
end_lower_range = avl_tree.lower_entry(range[1] - 1)
|
115
|
+
!end_lower_range.nil? && end_lower_range[1] > range[0]
|
114
116
|
end
|
115
117
|
|
116
118
|
# Returns true if current ranges contains the element.
|
@@ -120,15 +122,15 @@ class RangeList
|
|
120
122
|
def contains?(element)
|
121
123
|
raise ArgumentError, "`element` should be `Integer` type." unless element.is_a?(Integer)
|
122
124
|
|
123
|
-
|
124
|
-
!
|
125
|
+
lower_entry = avl_tree.lower_entry(element)
|
126
|
+
!lower_entry.nil? && lower_entry[1] > element
|
125
127
|
end
|
126
128
|
|
127
129
|
# Give RangeList iterative ability.
|
128
130
|
# @yield [range_start, range_end] give the range element to the block
|
129
131
|
def each(&block)
|
130
132
|
if block
|
131
|
-
|
133
|
+
avl_tree.each(&block)
|
132
134
|
else
|
133
135
|
enum_for(:each)
|
134
136
|
end
|
@@ -141,7 +143,7 @@ class RangeList
|
|
141
143
|
|
142
144
|
private
|
143
145
|
|
144
|
-
attr_reader :
|
146
|
+
attr_reader :avl_tree
|
145
147
|
|
146
148
|
def validate_range!(range)
|
147
149
|
raise ArgumentError, "`range` should be `Array` type." unless range.is_a?(Array)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: range_list
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
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
14
|
name: rbtree
|
@@ -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
|