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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbae62498893749767a5138f59caacd3de650bf62f566859d2ff16fc69e04a73
4
- data.tar.gz: b5317ec465420963e3d392f89f22e2bf3a7a662a569c82084b4cbe5383eaab32
3
+ metadata.gz: bac3ba3fced62c57e3d3fafa0f1999667172d7083defe6ec6404ca8ecfb83af0
4
+ data.tar.gz: 12708960354b2930dd49ff8ee80e8b809340c8b8447953baac65351a914ad73b
5
5
  SHA512:
6
- metadata.gz: 9f39a299e682ca947eeb1518cdba35eaad08b806433a849f1651ead445a7602fcb7c290611b8c3fa2601994003b74f3edbbe7909967d02064316db27d0d03a46
7
- data.tar.gz: 286f03c1ecc1de6b5d0b5d4d271b0fcb2d3ea2f56c5a146d26e66b68a0fe168e0a8d093e781bb7c4a4551501682e8ea4534495a86f669470b73db52aa48a2028
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.0)
5
- treemap (~> 1.0)
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
  [![Gem Version](https://badge.fury.io/rb/range_list.svg)](https://rubygems.org/gems/range_list)
11
11
  [![Documentation](https://img.shields.io/badge/docs-YARD-blue.svg)](https://rubydoc.info/gems/range_list)
12
12
  [![pipeline status](https://gitlab.com/songhuangcn/range_list/badges/main/pipeline.svg)](https://gitlab.com/songhuangcn/range_list/-/commits/main)
13
- [![coverage report](https://gitlab.com/songhuangcn/range_list/badges/main/coverage.svg)](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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class RangeList
4
- VERSION = "1.1.0"
4
+ VERSION = "1.3.1"
5
5
  end
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
- @tree = TreeMap.new
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
- start_floor_entry = tree.floor_entry(range[0])
27
- range_start = if !start_floor_entry.nil? && start_floor_entry.value >= range[0]
28
- start_floor_entry.key
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
- end_floor_entry = tree.floor_entry(range[1])
35
- range_end = if !end_floor_entry.nil? && end_floor_entry.value >= range[1]
36
- end_floor_entry.value
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
- tree.put(range_start, range_end)
39
+ avl_tree.put(range_start, range_end)
43
40
 
44
41
  # Remove keys between range, exclude start, include end.
45
- between_maps = tree.sub_map(range[0], false, range[1], true)
46
- between_maps.keys.each { |key| tree.remove(key) }
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 entry
62
- end_lower_entry = tree.lower_entry(range[1])
63
- if !end_lower_entry.nil? && end_lower_entry.value > range[1]
64
- tree.put(range[1], end_lower_entry.value)
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 entry
68
- start_lower_entry = tree.lower_entry(range[0])
69
- if !start_lower_entry.nil? && start_lower_entry.value > range[0]
70
- tree.put(start_lower_entry.key, range[0])
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
- between_maps = tree.sub_map(range[0], true, range[1], false)
75
- between_maps.keys.each { |key| tree.remove(key) }
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
- puts map { |k, v| "[#{k}, #{v})" }.join(" ")
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
- start_floor_entry = tree.floor_entry(range[0])
98
- !start_floor_entry.nil? && start_floor_entry.value >= range[1]
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
- end_lower_entry = tree.lower_entry(range[1])
113
- !end_lower_entry.nil? && end_lower_entry.value > range[0]
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
- raise ArgumentError, "`element` should be `Integer` type." unless element.is_a?(Integer)
114
+ validate_element!(element)
122
115
 
123
- floor_entry = tree.floor_entry(element)
124
- !floor_entry.nil? && floor_entry.value > element
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
- # Iterating an empty tree will raise an error,
132
- # see https://github.com/davidkellis/treemap/issues/1
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
- to_a.inspect
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 :tree
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 "treemap", "~> 1.0"
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.0
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-26 00:00:00.000000000 Z
11
+ date: 2022-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: treemap
14
+ name: rbtree
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
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: '1.0'
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