lite-containers 0.0.5
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 +7 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +72 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +127 -0
- data/README.md +145 -0
- data/bench/containers_bench.rb +122 -0
- data/lib/lite/containers/abstract/collection.rb +25 -0
- data/lib/lite/containers/abstract/deque.rb +23 -0
- data/lib/lite/containers/abstract/implicit_key.rb +23 -0
- data/lib/lite/containers/abstract/queue.rb +24 -0
- data/lib/lite/containers/abstract/sorted_map.rb +29 -0
- data/lib/lite/containers/avl_tree/balance.rb +74 -0
- data/lib/lite/containers/avl_tree/delete.rb +32 -0
- data/lib/lite/containers/avl_tree/find.rb +99 -0
- data/lib/lite/containers/avl_tree/implementation.rb +88 -0
- data/lib/lite/containers/avl_tree/insert.rb +27 -0
- data/lib/lite/containers/avl_tree/interfaces/bracket_assign.rb +33 -0
- data/lib/lite/containers/avl_tree/interfaces/key_extraction_strategy/abstract.rb +48 -0
- data/lib/lite/containers/avl_tree/interfaces/key_extraction_strategy/explicit.rb +34 -0
- data/lib/lite/containers/avl_tree/interfaces/key_extraction_strategy/implicit.rb +60 -0
- data/lib/lite/containers/avl_tree/node.rb +35 -0
- data/lib/lite/containers/avl_tree/traversal.rb +43 -0
- data/lib/lite/containers/avl_tree.rb +159 -0
- data/lib/lite/containers/error.rb +7 -0
- data/lib/lite/containers/heap.rb +169 -0
- data/lib/lite/containers/helpers/comparison.rb +106 -0
- data/lib/lite/containers/helpers/key_extractor.rb +29 -0
- data/lib/lite/containers/helpers/merge.rb +49 -0
- data/lib/lite/containers/sorted_array/binary_search.rb +42 -0
- data/lib/lite/containers/sorted_array.rb +188 -0
- data/lib/lite/containers/top_n/abstract.rb +56 -0
- data/lib/lite/containers/top_n/avl_tree.rb +25 -0
- data/lib/lite/containers/top_n/deque.rb +33 -0
- data/lib/lite/containers/top_n/error.rb +11 -0
- data/lib/lite/containers/top_n/heap.rb +32 -0
- data/lib/lite/containers/top_n.rb +31 -0
- data/lib/lite/containers/version.rb +7 -0
- data/lib/lite/containers.rb +3 -0
- data/lite_containers.gemspec +25 -0
- metadata +83 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Containers
|
5
|
+
class AvlTree
|
6
|
+
module Delete
|
7
|
+
def delete(key, node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
8
|
+
return [nil, nil] if node.nil?
|
9
|
+
|
10
|
+
case compare(key, node.key)
|
11
|
+
when -1
|
12
|
+
deleted, node.left = delete(key, node.left)
|
13
|
+
[deleted, rebalance(node)]
|
14
|
+
when 0
|
15
|
+
if node.left.nil? || node.right.nil?
|
16
|
+
new_root = node.left.nil? ? node.right : node.left
|
17
|
+
[node, new_root]
|
18
|
+
else
|
19
|
+
new_root = leftmost_child(node.right)
|
20
|
+
_, new_root.right = delete(new_root.key, node.right)
|
21
|
+
new_root.left = node.left
|
22
|
+
[node, rebalance(new_root)]
|
23
|
+
end
|
24
|
+
when 1
|
25
|
+
deleted, node.right = delete(key, node.right)
|
26
|
+
[deleted, rebalance(node)]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../helpers/comparison'
|
4
|
+
|
5
|
+
module Lite
|
6
|
+
module Containers
|
7
|
+
class AvlTree
|
8
|
+
module Find
|
9
|
+
def leftmost_child(node)
|
10
|
+
return node if node.left.nil?
|
11
|
+
|
12
|
+
leftmost_child(node.left)
|
13
|
+
end
|
14
|
+
|
15
|
+
def rightmost_child(node)
|
16
|
+
return node if node.right.nil?
|
17
|
+
|
18
|
+
rightmost_child(node.right)
|
19
|
+
end
|
20
|
+
|
21
|
+
module Exact
|
22
|
+
def find(key, node)
|
23
|
+
return nil unless node
|
24
|
+
|
25
|
+
case compare(key, node.key)
|
26
|
+
when -1
|
27
|
+
find(key, node.left)
|
28
|
+
when 0
|
29
|
+
node
|
30
|
+
when 1
|
31
|
+
find(key, node.right)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Inexact
|
37
|
+
def find(key, node)
|
38
|
+
exact, candidate = find_candidate(key, node)
|
39
|
+
exact || candidate
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_candidate(key, node)
|
43
|
+
return [nil, nil] unless node
|
44
|
+
|
45
|
+
case lookup_direction(key, node.key)
|
46
|
+
when -1
|
47
|
+
find_candidate(key, lookup_path(node, -1))
|
48
|
+
when 0
|
49
|
+
[node, nil]
|
50
|
+
when 1
|
51
|
+
exact, candidate = find_candidate(key, lookup_path(node, 1))
|
52
|
+
if exact
|
53
|
+
[exact, nil]
|
54
|
+
elsif candidate
|
55
|
+
[nil, candidate]
|
56
|
+
else
|
57
|
+
[nil, node]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module ExactOrNearestBackwards
|
64
|
+
include Inexact
|
65
|
+
|
66
|
+
def lookup_direction(search_key, node_key)
|
67
|
+
compare(search_key, node_key)
|
68
|
+
end
|
69
|
+
|
70
|
+
def lookup_path(node, comparison_result)
|
71
|
+
case comparison_result
|
72
|
+
when -1 then node.left
|
73
|
+
when 1 then node.right
|
74
|
+
else
|
75
|
+
raise Helpers::Comparison::Error, "Unexpected comparison result: #{comparison_result}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
module ExactOrNearestForwards
|
81
|
+
include Inexact
|
82
|
+
|
83
|
+
def lookup_direction(search_key, node_key)
|
84
|
+
compare(node_key, search_key)
|
85
|
+
end
|
86
|
+
|
87
|
+
def lookup_path(node, comparison_result)
|
88
|
+
case comparison_result
|
89
|
+
when -1 then node.right
|
90
|
+
when 1 then node.left
|
91
|
+
else
|
92
|
+
raise Helpers::Comparison::Error, "Unexpected comparison result: #{comparison_result}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../error'
|
4
|
+
require_relative '../helpers/comparison'
|
5
|
+
require_relative 'insert'
|
6
|
+
require_relative 'delete'
|
7
|
+
require_relative 'balance'
|
8
|
+
require_relative 'traversal'
|
9
|
+
require_relative 'find'
|
10
|
+
|
11
|
+
module Lite
|
12
|
+
module Containers
|
13
|
+
class AvlTree
|
14
|
+
class Error < Containers::Error; end
|
15
|
+
|
16
|
+
module Implementation
|
17
|
+
def self.instance(type)
|
18
|
+
type = type.to_sym
|
19
|
+
case type
|
20
|
+
when :max then Max
|
21
|
+
when :min then Min
|
22
|
+
else raise Error, Error, "Unexpected AVL tree type: '#{type}'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
include Balance
|
27
|
+
include Delete
|
28
|
+
include Insert
|
29
|
+
include Find
|
30
|
+
include Traversal
|
31
|
+
|
32
|
+
module Max
|
33
|
+
extend Implementation
|
34
|
+
|
35
|
+
module Compare
|
36
|
+
def compare(a, b)
|
37
|
+
Helpers::Comparison::Max.compare(a, b)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Exact
|
42
|
+
extend Find::Exact
|
43
|
+
extend Compare
|
44
|
+
end
|
45
|
+
|
46
|
+
module ExactOrNearestForwards
|
47
|
+
extend Find::ExactOrNearestForwards
|
48
|
+
extend Compare
|
49
|
+
end
|
50
|
+
|
51
|
+
module ExactOrNearestBackwards
|
52
|
+
extend Find::ExactOrNearestBackwards
|
53
|
+
extend Compare
|
54
|
+
end
|
55
|
+
|
56
|
+
extend Compare
|
57
|
+
end
|
58
|
+
|
59
|
+
module Min
|
60
|
+
extend Implementation
|
61
|
+
|
62
|
+
module Compare
|
63
|
+
def compare(a, b)
|
64
|
+
Helpers::Comparison::Min.compare(a, b)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module Exact
|
69
|
+
extend Find::Exact
|
70
|
+
extend Compare
|
71
|
+
end
|
72
|
+
|
73
|
+
module ExactOrNearestForwards
|
74
|
+
extend Find::ExactOrNearestForwards
|
75
|
+
extend Compare
|
76
|
+
end
|
77
|
+
|
78
|
+
module ExactOrNearestBackwards
|
79
|
+
extend Find::ExactOrNearestBackwards
|
80
|
+
extend Compare
|
81
|
+
end
|
82
|
+
|
83
|
+
extend Compare
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'node'
|
4
|
+
|
5
|
+
module Lite
|
6
|
+
module Containers
|
7
|
+
class AvlTree
|
8
|
+
module Insert
|
9
|
+
def insert(node, key, value, merge, factory)
|
10
|
+
return true, factory.instance(key, value) if node.nil?
|
11
|
+
|
12
|
+
case compare(key, node.key)
|
13
|
+
when -1
|
14
|
+
increment, node.left = insert(node.left, key, value, merge, factory)
|
15
|
+
[increment, rebalance(node)]
|
16
|
+
when 0
|
17
|
+
node.value = merge.merge(node.value, value)
|
18
|
+
[false, node]
|
19
|
+
when 1
|
20
|
+
increment, node.right = insert(node.right, key, value, merge, factory)
|
21
|
+
[increment, rebalance(node)]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'key_extraction_strategy/explicit'
|
4
|
+
require_relative '../../helpers/merge'
|
5
|
+
|
6
|
+
module Lite
|
7
|
+
module Containers
|
8
|
+
class AvlTree
|
9
|
+
module Interfaces
|
10
|
+
module BracketAssign
|
11
|
+
include KeyExtractionStrategy::Explicit
|
12
|
+
|
13
|
+
module Instance
|
14
|
+
def instance(type, **opts)
|
15
|
+
raise ArgumentError, 'Disallowed keyword argument: merge' if opts.key?(:merge)
|
16
|
+
|
17
|
+
super(type, merge: :replace, **opts)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
KeyExtractionStrategy::Abstract.enforce_exclusion!(base, KeyExtractionStrategy::Explicit)
|
23
|
+
base.extend Instance
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
insert_pair key, value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../error'
|
4
|
+
|
5
|
+
module Lite
|
6
|
+
module Containers
|
7
|
+
class AvlTree
|
8
|
+
module Interfaces
|
9
|
+
module KeyExtractionStrategy
|
10
|
+
module Abstract
|
11
|
+
def self.included(base)
|
12
|
+
register(base)
|
13
|
+
enforce_exclusion(base, base)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.register(strategy)
|
17
|
+
registry << strategy
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.registry
|
21
|
+
@registry ||= Set.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.enforce_exclusion(mod, strategy)
|
25
|
+
mod.define_singleton_method :included do |base|
|
26
|
+
Abstract.enforce_exclusion!(base, strategy)
|
27
|
+
super(base)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.enforce_exclusion!(base, strategy)
|
32
|
+
conflicts = Abstract
|
33
|
+
.registry
|
34
|
+
.select { |candidate| strategy != candidate && base < candidate }
|
35
|
+
.map { |conflict| conflict.name.split('::').last }
|
36
|
+
|
37
|
+
if !conflicts.empty?
|
38
|
+
raise Error, "Key extraction strategy conflict: #{conflicts.join(', ')}"
|
39
|
+
elsif base.is_a?(Module)
|
40
|
+
Abstract.enforce_exclusion(base, strategy)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'abstract'
|
4
|
+
require_relative '../../node'
|
5
|
+
|
6
|
+
module Lite
|
7
|
+
module Containers
|
8
|
+
class AvlTree
|
9
|
+
module Interfaces
|
10
|
+
module KeyExtractionStrategy
|
11
|
+
module Explicit
|
12
|
+
class Node < AvlTree::Node
|
13
|
+
def out
|
14
|
+
[key, value]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
include Abstract
|
19
|
+
|
20
|
+
def insert(key, value)
|
21
|
+
insert_pair(key, value)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def node_factory
|
27
|
+
Node
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../helpers/key_extractor'
|
4
|
+
require_relative '../../../abstract/implicit_key'
|
5
|
+
require_relative '../../node'
|
6
|
+
require_relative 'abstract'
|
7
|
+
|
8
|
+
module Lite
|
9
|
+
module Containers
|
10
|
+
class AvlTree
|
11
|
+
module Interfaces
|
12
|
+
module KeyExtractionStrategy
|
13
|
+
module Implicit
|
14
|
+
include Abstract
|
15
|
+
include Containers::Abstract::ImplicitKey
|
16
|
+
|
17
|
+
class Node < AvlTree::Node
|
18
|
+
def out
|
19
|
+
value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Instance
|
24
|
+
def instance(type, key_extractor: nil, **opts)
|
25
|
+
super(type, key_extractor: Helpers::KeyExtractor.instance(key_extractor), **opts)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.included(base)
|
30
|
+
Abstract.enforce_exclusion!(base, self)
|
31
|
+
base.extend Instance
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(*args, key_extractor:, **opts)
|
35
|
+
@key_extractor = key_extractor
|
36
|
+
super(*args, **opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
def push(value)
|
40
|
+
key = extract_key(value)
|
41
|
+
insert_pair key, value
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def extract_key(object)
|
47
|
+
return object if @key_extractor.nil?
|
48
|
+
|
49
|
+
@key_extractor.to_key(object)
|
50
|
+
end
|
51
|
+
|
52
|
+
def node_factory
|
53
|
+
Node
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Containers
|
5
|
+
class AvlTree
|
6
|
+
class Node
|
7
|
+
attr_reader :key
|
8
|
+
attr_accessor :value, :height, :left, :right
|
9
|
+
|
10
|
+
def self.instance(key, value)
|
11
|
+
new key, value
|
12
|
+
end
|
13
|
+
|
14
|
+
private_class_method :new
|
15
|
+
|
16
|
+
def initialize(key, value)
|
17
|
+
@key = key
|
18
|
+
@value = value
|
19
|
+
@height = 1
|
20
|
+
@left = nil
|
21
|
+
@right = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def out
|
25
|
+
raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
lr = "#{left.nil? ? 0 : :L}|#{right.nil? ? 0 : :R}"
|
30
|
+
"#<#{self.class.name} @key: #{key}, @value: #{value}, @height: #{height} #{lr}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Containers
|
5
|
+
class AvlTree
|
6
|
+
module Traversal
|
7
|
+
def traverse(node, yielder, from:, to:)
|
8
|
+
return unless node
|
9
|
+
|
10
|
+
after_start = after_back_guard?(node, from)
|
11
|
+
traverse(node.left, yielder, from: from, to: to) if after_start
|
12
|
+
return unless before_front_guard?(node, to)
|
13
|
+
|
14
|
+
yielder.yield node.out if after_start
|
15
|
+
traverse(node.right, yielder, from: from, to: to)
|
16
|
+
end
|
17
|
+
|
18
|
+
def reverse_traverse(node, yielder, from:, to:)
|
19
|
+
return unless node
|
20
|
+
|
21
|
+
after_start = before_front_guard?(node, from)
|
22
|
+
reverse_traverse(node.right, yielder, from: from, to: to) if after_start
|
23
|
+
return unless after_back_guard?(node, to)
|
24
|
+
|
25
|
+
yielder.yield node.out if after_start
|
26
|
+
reverse_traverse(node.left, yielder, from: from, to: to)
|
27
|
+
end
|
28
|
+
|
29
|
+
def after_back_guard?(node, guard)
|
30
|
+
return true if guard.nil?
|
31
|
+
|
32
|
+
compare(guard, node.key) < 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def before_front_guard?(node, guard)
|
36
|
+
return true if guard.nil?
|
37
|
+
|
38
|
+
compare(node.key, guard) < 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers/merge'
|
4
|
+
require_relative 'avl_tree/implementation'
|
5
|
+
require_relative 'avl_tree/interfaces/key_extraction_strategy/explicit'
|
6
|
+
require_relative 'avl_tree/interfaces/key_extraction_strategy/implicit'
|
7
|
+
require_relative 'abstract/collection'
|
8
|
+
require_relative 'abstract/deque'
|
9
|
+
require_relative 'abstract/sorted_map'
|
10
|
+
|
11
|
+
module Lite
|
12
|
+
module Containers
|
13
|
+
class AvlTree # rubocop:disable Metrics/ClassLength
|
14
|
+
include Abstract::Collection
|
15
|
+
include Abstract::Deque
|
16
|
+
include Abstract::SortedMap
|
17
|
+
include Enumerable
|
18
|
+
|
19
|
+
class ExplicitKey < AvlTree
|
20
|
+
include Interfaces::KeyExtractionStrategy::Explicit
|
21
|
+
end
|
22
|
+
|
23
|
+
class ImplicitKey < AvlTree
|
24
|
+
include Interfaces::KeyExtractionStrategy::Implicit
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :size
|
28
|
+
|
29
|
+
def self.instance(type, merge: nil, **opts)
|
30
|
+
impl = Implementation.instance(type)
|
31
|
+
merge = Helpers::Merge.instance(merge)
|
32
|
+
new(impl, merge, **opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
private_class_method :new
|
36
|
+
|
37
|
+
def initialize(impl, merge)
|
38
|
+
@impl = impl
|
39
|
+
@merge = merge
|
40
|
+
reset!
|
41
|
+
end
|
42
|
+
|
43
|
+
def reset!
|
44
|
+
@root = nil
|
45
|
+
@size = 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def key?(key)
|
49
|
+
!find_with_finder(key, @impl::Exact).nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
def [](key)
|
53
|
+
find_with_finder(key, @impl::Exact)&.value
|
54
|
+
end
|
55
|
+
|
56
|
+
def find(key)
|
57
|
+
find_with_finder(key, @impl::Exact)&.out
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_or_nearest_backwards(key)
|
61
|
+
find_with_finder(key, @impl::ExactOrNearestBackwards)&.out
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_or_nearest_forwards(key)
|
65
|
+
find_with_finder(key, @impl::ExactOrNearestForwards)&.out
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete(key)
|
69
|
+
deleted, @root = @impl.delete(key, @root)
|
70
|
+
@size -= 1 if deleted
|
71
|
+
deleted&.out
|
72
|
+
end
|
73
|
+
|
74
|
+
def each(&block)
|
75
|
+
if block
|
76
|
+
traverse.each(&block)
|
77
|
+
self
|
78
|
+
else
|
79
|
+
traverse
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def reverse_each(&block)
|
84
|
+
if block
|
85
|
+
reverse_traverse.each(&block)
|
86
|
+
self
|
87
|
+
else
|
88
|
+
reverse_traverse
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def traverse(from: nil, to: nil)
|
93
|
+
Enumerator.new do |yielder|
|
94
|
+
@impl.traverse @root, yielder, from: from, to: to
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def reverse_traverse(from: nil, to: nil)
|
99
|
+
Enumerator.new do |yielder|
|
100
|
+
@impl.reverse_traverse @root, yielder, from: from, to: to
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def front
|
105
|
+
fetch_front&.out
|
106
|
+
end
|
107
|
+
|
108
|
+
def pop_front
|
109
|
+
node = fetch_front
|
110
|
+
return unless node
|
111
|
+
|
112
|
+
delete(node.key)
|
113
|
+
node.out
|
114
|
+
end
|
115
|
+
|
116
|
+
def back
|
117
|
+
fetch_back&.out
|
118
|
+
end
|
119
|
+
|
120
|
+
def pop_back
|
121
|
+
node = fetch_back
|
122
|
+
return unless node
|
123
|
+
|
124
|
+
delete(node.key)
|
125
|
+
node.out
|
126
|
+
end
|
127
|
+
|
128
|
+
def drain!
|
129
|
+
array = reverse_traverse.to_a
|
130
|
+
reset!
|
131
|
+
array
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def fetch_front
|
137
|
+
return if @root.nil?
|
138
|
+
|
139
|
+
@impl.rightmost_child(@root)
|
140
|
+
end
|
141
|
+
|
142
|
+
def fetch_back
|
143
|
+
return if @root.nil?
|
144
|
+
|
145
|
+
@impl.leftmost_child(@root)
|
146
|
+
end
|
147
|
+
|
148
|
+
def insert_pair(key, value)
|
149
|
+
increment, @root = @impl.insert(@root, key, value, @merge, node_factory)
|
150
|
+
@size += 1 if increment
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
def find_with_finder(key, finder)
|
155
|
+
finder.find(key, @root)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|