veb_tree 0.1.0 → 0.1.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: e23be52707f931f14be4a781a5b3772bc222c23c3843c59313b074fd64eb2e9c
4
- data.tar.gz: 626f915e7d226ae97e08b6d8c448326716d3cbc12f88a2af37ba7e62c65b9d81
3
+ metadata.gz: b518aea4b85123bdda532a06f561bcd24af252f724f64ded4e4089451f9273f7
4
+ data.tar.gz: 3527c4ebc1ebc586b90fabc57c3bcefc0650df20c53b399c21613229cd3a2fec
5
5
  SHA512:
6
- metadata.gz: b90a39d5c9480a9b1ac3174b1d078421634cd70e361154c00599edf6906370c4250d2491ee69e166f1c149a45847ad910484e4b2fe9537c6d4f26cf9c74afe05
7
- data.tar.gz: d8b9ee66e04ababef90de5f0cfe2f12c2d1da3bbc6146b97899219dfc592bcba95c47293026bc798cb74e505c19f67b409c7640cd64b9aeecf1e3fad5737ab46
6
+ metadata.gz: 85d0512562fb3c530b8d01ee6ca96ee1354ab7254ae6ed539d9e8530cc8f00533ce20279c4bd0082bcdaaf4f94536a20c2aa3250f5d190816c6da2fb5315ffa4
7
+ data.tar.gz: 67962e7fa31d7c63ce8d4144a822e2ed642f041f1d689ce65fda357bf8cb28705eab62d81921e8bf80ac123de3df3e9409ab2697bf98b6f10e395ba03764f3ef
data/CHANGELOG.md CHANGED
@@ -5,7 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.1.0] - 2025-01-XX
8
+ ## [0.1.1] - 2025-10-03
9
+
10
+ ### Added
11
+ - Fix compatibility issues for ruby 2.7 and macos
12
+
13
+ ## [0.1.0] - 2025-10-03
9
14
 
10
15
  ### Added
11
16
  - Initial release of VebTree gem
data/README.md CHANGED
@@ -1,32 +1,39 @@
1
1
  # VebTree - Van Emde Boas Tree
2
2
 
3
- A high-performance Van Emde Boas (vEB) tree implementation for Ruby with a C++ core, providing **O(log log U)** time complexity for integer set operations.
3
+ [![Tests](https://github.com/abhinvv1/Van-Emde-Boas-tree/workflows/Tests/badge.svg)](https://github.com/abhinvv1/Van-Emde-Boas-tree/actions)
4
+ [![Gem Version](https://badge.fury.io/rb/veb_tree.svg)](https://badge.fury.io/rb/veb_tree)
4
5
 
5
- ## Features
6
+ A high-performance **Van Emde Boas (vEB) tree** implementation for Ruby with a C++17 core.
7
+ Provides **O(log log U)** time complexity for integer set operations, making it exponentially faster than balanced BSTs for many workloads.
6
8
 
7
- - **Blazing Fast**: O(log log U) operations for insert, delete, search, successor, and predecessor
8
- - **Native Performance**: Core algorithm implemented in C++17
9
- - **Simple API**: Clean, idiomatic Ruby interface
10
- - **Memory Efficient**: Lazy cluster allocation
11
- - **Battle Tested**: Comprehensive test suite
9
+ ---
12
10
 
13
- ## Installation
11
+ ## ✨ Features
14
12
 
15
- ### Requirements
13
+ - ⚡ **Blazing Fast** — `O(log log U)` operations for insert, delete, search, successor, and predecessor
14
+ - 🖥 **Native Performance** — core implemented in **C++17**
15
+ - 🧑‍💻 **Simple API** — clean, idiomatic Ruby interface
16
+ - 🧩 **Memory Efficient** — lazy cluster allocation to minimize space usage
17
+ - ✅ **Battle Tested** — comprehensive test suite included
18
+
19
+ ---
20
+
21
+ ## 📦 Installation
16
22
 
17
- - Ruby 2.7 or higher
18
- - C++17 compatible compiler:
19
- - **Linux**: GCC 7+ or Clang 5+
20
- - **macOS**: Xcode Command Line Tools
21
- - **Windows**: MinGW-w64 or MSVC 2017+
23
+ ### Requirements
24
+ - **Ruby**: 2.7 or higher
25
+ - **C++17** compatible compiler:
26
+ - **Linux**: GCC 7+ or Clang 5+
27
+ - **macOS**: Xcode Command Line Tools
28
+ - **Windows**: MinGW-w64 or MSVC 2017+
22
29
 
23
30
  ### Install via RubyGems
24
31
  ```bash
25
32
  gem install veb_tree
26
33
  ```
27
34
 
28
- ## Install from Source
29
- ```
35
+ ### Install from Source
36
+ ```bash
30
37
  git clone https://github.com/yourusername/veb_tree.git
31
38
  cd veb_tree
32
39
  bundle install
@@ -36,11 +43,14 @@ gem build veb_tree.gemspec
36
43
  gem install veb_tree-*.gem
37
44
  ```
38
45
 
39
- ### Quick Start
40
- ```
46
+ ---
47
+
48
+ ## 🚀 Quick Start
49
+
50
+ ```ruby
41
51
  require 'veb_tree'
42
52
 
43
- # Create a tree with universe size (will round to next power of 2)
53
+ # Create a tree with universe size (rounded to next power of 2)
44
54
  tree = VebTree::Tree.new(1000) # Actual size: 1024
45
55
 
46
56
  # Insert elements
@@ -49,21 +59,21 @@ tree.insert(100)
49
59
  tree.insert(7)
50
60
  tree.insert(500)
51
61
 
52
- # Check membership - O(log log U)
62
+ # Membership check
53
63
  tree.include?(42) # => true
54
64
  tree.include?(99) # => false
55
65
 
56
- # Min/Max - O(1)
66
+ # Min/Max
57
67
  tree.min # => 7
58
68
  tree.max # => 500
59
69
 
60
- # Successor/Predecessor - O(log log U)
70
+ # Successor / Predecessor
61
71
  tree.successor(42) # => 100
62
72
  tree.predecessor(100) # => 42
63
73
 
64
- # Size and empty check
65
- tree.size # => 4
66
- tree.empty? # => false
74
+ # Size & emptiness
75
+ tree.size # => 4
76
+ tree.empty? # => false
67
77
 
68
78
  # Iterate in sorted order
69
79
  tree.each { |key| puts key }
@@ -74,23 +84,244 @@ tree.to_a # => [7, 42, 100, 500]
74
84
 
75
85
  # Delete elements
76
86
  tree.delete(42) # => true
77
- tree.delete(42) # => false (not present)
87
+ tree.delete(42) # => false (already removed)
78
88
 
79
89
  # Clear all elements
80
90
  tree.clear
81
91
  ```
82
92
 
83
- ### API Reference
84
- ```VebTree::Tree.new(universe_size)```
93
+ ---
85
94
 
86
- Creates a new Van Emde Boas tree.
87
- - universe_size (Integer): Maximum value that can be stored (exclusive). Will be
88
- - rounded up to the next power of 2.
89
- - Returns: New VebTree::Tree instance
90
- - Raises: ArgumentError if universe_size is not positive
95
+ ## 📖 API Reference
91
96
 
92
- #### Example
97
+ ### Constructor
98
+ ```ruby
99
+ VebTree::Tree.new(universe_size)
93
100
  ```
94
- tree = VebTree::Tree.new(100) # Actual universe: 128
101
+
102
+ - **universe_size (Integer)** — maximum value that can be stored (exclusive).
103
+ Automatically rounded up to the next power of 2.
104
+ - **Returns**: `VebTree::Tree` instance
105
+ - **Raises**: `ArgumentError` if universe_size ≤ 0
106
+
107
+ **Example:**
108
+ ```ruby
109
+ tree = VebTree::Tree.new(100)
95
110
  tree.universe_size # => 128
96
111
  ```
112
+
113
+ ---
114
+
115
+ ### Core Operations
116
+
117
+ #### Insert
118
+ ```ruby
119
+ tree.insert(key) → Boolean
120
+ ```
121
+ - Inserts a key.
122
+ - **Time**: O(log log U)
123
+ - Returns `true` if inserted, `false` if already present.
124
+
125
+ #### Delete
126
+ ```ruby
127
+ tree.delete(key) → Boolean
128
+ ```
129
+ - Removes a key.
130
+ - **Time**: O(log log U)
131
+ - Returns `true` if deleted, `false` if not found.
132
+
133
+ #### Membership
134
+ ```ruby
135
+ tree.include?(key) → Boolean
136
+ tree.member?(key) # alias
137
+ ```
138
+ - Checks if key exists.
139
+ - **Time**: O(log log U)
140
+
141
+ #### Min / Max
142
+ ```ruby
143
+ tree.min → Integer or nil
144
+ tree.max → Integer or nil
145
+ ```
146
+ - Returns smallest or largest key.
147
+ - **Time**: O(1)
148
+
149
+ #### Successor / Predecessor
150
+ ```ruby
151
+ tree.successor(key) → Integer or nil
152
+ tree.predecessor(key) → Integer or nil
153
+ ```
154
+ - Finds next higher or next lower key.
155
+ - **Time**: O(log log U)
156
+
157
+ ---
158
+
159
+ ### Utility Methods
160
+
161
+ - `tree.size` → number of elements (**O(1)**)
162
+ - `tree.empty?` → true/false (**O(1)**)
163
+ - `tree.universe_size` → current universe size
164
+ - `tree.clear` → removes all elements
165
+
166
+ ---
167
+
168
+ ### Enumeration
169
+
170
+ The tree includes `Enumerable`, so all Ruby iteration helpers work:
171
+
172
+ ```ruby
173
+ tree.each { |key| puts key }
174
+ tree.to_a # => [7, 42, 100, 500]
175
+ tree.map { |x| x * 2 } # => [14, 84, 200, 1000]
176
+ tree.select { |x| x > 50 } # => [100, 500]
177
+ tree.count # => 4
178
+ ```
179
+
180
+ ---
181
+
182
+ ## 📊 Performance
183
+
184
+ | Operation | vEB Tree | Balanced BST |
185
+ |-------------|----------|--------------|
186
+ | Insert | O(log log U) | O(log n) |
187
+ | Delete | O(log log U) | O(log n) |
188
+ | Search | O(log log U) | O(log n) |
189
+ | Successor | O(log log U) | O(log n) |
190
+ | Predecessor | O(log log U) | O(log n) |
191
+ | Min/Max | O(1) | O(log n) |
192
+
193
+ - **U** = universe size (max key)
194
+ - **n** = number of stored elements
195
+
196
+ vEB trees are best for **bounded integer sets** with frequent `successor/predecessor/min/max` queries.
197
+
198
+ ⚠️ Avoid when:
199
+ - Universe size is **huge (> 2^24)**
200
+ - Need arbitrary objects (only integers supported)
201
+ - Extremely memory constrained
202
+
203
+ ---
204
+
205
+ ## 💾 Space Complexity
206
+
207
+ - **Theoretical**: O(U)
208
+ - **Optimized** with lazy allocation: only used clusters consume memory
209
+
210
+ **Practical Usage:**
211
+ - Universe `2^16` (65K): ~hundreds of KB
212
+ - Universe `2^20` (1M): ~few MB
213
+ - Universe `2^24` (16M): ~tens of MB
214
+
215
+ ---
216
+
217
+ ## ⚠️ Thread Safety
218
+
219
+ This implementation is **NOT thread-safe**.
220
+ For concurrency, wrap operations with a `Mutex`:
221
+
222
+ ```ruby
223
+ require 'thread'
224
+
225
+ tree = VebTree::Tree.new(1000)
226
+ mutex = Mutex.new
227
+
228
+ mutex.synchronize do
229
+ tree.insert(42)
230
+ end
231
+ ```
232
+
233
+ ---
234
+
235
+ ## 🛑 Error Handling
236
+
237
+ ```ruby
238
+ tree = VebTree::Tree.new(0) # ArgumentError: Universe size must be > 0
239
+ tree.insert(-1) # ArgumentError: Key must be non-negative
240
+ tree.insert(200) # ArgumentError: Key exceeds universe size
241
+
242
+ tree.include?(999) # => false
243
+ tree.successor(999) # => nil
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 🧪 Examples
249
+
250
+ ### Range Query Simulation
251
+ ```ruby
252
+ tree = VebTree::Tree.new(10000)
253
+
254
+ 100.times { tree.insert(rand(10000)) }
255
+
256
+ current = tree.successor(999) # first ≥ 1000
257
+ result = []
258
+ while current && current <= 2000
259
+ result << current
260
+ current = tree.successor(current)
261
+ end
262
+ ```
263
+
264
+ ### K-th Smallest Element
265
+ ```ruby
266
+ def kth_smallest(tree, k)
267
+ current = tree.min
268
+ (k - 1).times do
269
+ return nil unless current
270
+ current = tree.successor(current)
271
+ end
272
+ current
273
+ end
274
+
275
+ tree = VebTree::Tree.new(1000)
276
+ [5, 10, 3, 50].each { |x| tree.insert(x) }
277
+
278
+ kth_smallest(tree, 2) # => 5
279
+ ```
280
+
281
+ ---
282
+
283
+ ## 🔧 Development
284
+
285
+ ```bash
286
+ # Clone repo
287
+ git clone https://github.com/yourusername/veb_tree.git
288
+ cd veb_tree
289
+
290
+ # Install dependencies
291
+ bundle install
292
+
293
+ # Compile extension
294
+ rake compile
295
+
296
+ # Run tests
297
+ rake test
298
+
299
+ # Clean build
300
+ rake clean
301
+ ```
302
+
303
+ ---
304
+
305
+ ## 🤝 Contributing
306
+
307
+ Bug reports and pull requests are welcome at:
308
+ 👉 [https://github.com/abhinvv1/Van-Emde-Boas-tree](https://github.com/abhinvv1/Van-Emde-Boas-tree)
309
+
310
+ ---
311
+
312
+ ## 📜 License
313
+
314
+ This gem is available as open source under the **MIT License**.
315
+
316
+ ---
317
+
318
+ ## 📚 References & Credits
319
+
320
+ - Based on the **Van Emde Boas tree** described by *Peter van Emde Boas (1975)*
321
+ - *Cormen, T. H., et al. (2009). Introduction to Algorithms (3rd ed.), Chapter 20*
322
+
323
+ ---
324
+
325
+ ## 🗒️ Changelog
326
+
327
+ See [CHANGELOG.md](./CHANGELOG.md) for version history.
@@ -7,34 +7,38 @@ unless find_executable("g++") || find_executable("clang++")
7
7
  abort "C++ compiler not found. Please install a C++ compiler."
8
8
  end
9
9
 
10
- # Set C++ compiler
11
- RbConfig::MAKEFILE_CONFIG["CXX"] = ENV["CXX"] || "g++"
12
-
13
- # C++17 standard
14
- $CXXFLAGS << " -std=c++17 -Wall -Wextra -O3"
15
-
16
- # Enable optimizations
17
- $CXXFLAGS << " -march=native" if ENV["NATIVE_ARCH"] == "1"
18
-
19
- # Debug flags if requested
20
- if ENV["DEBUG"] == "1"
21
- $CXXFLAGS << " -g -O0 -DDEBUG"
10
+ # Determine the C++ compiler
11
+ if RUBY_PLATFORM =~ /darwin/
12
+ RbConfig::MAKEFILE_CONFIG["CXX"] = "clang++"
13
+ RbConfig::MAKEFILE_CONFIG["LDSHAREDXX"] = "clang++ -dynamic -bundle"
14
+
15
+ if RUBY_VERSION < "3.0"
16
+ $CXXFLAGS << " -D_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION"
17
+ $CXXFLAGS << " -Wno-error=implicit-function-declaration"
18
+ end
22
19
  else
23
- $CXXFLAGS << " -DNDEBUG"
20
+ RbConfig::MAKEFILE_CONFIG["CXX"] = ENV["CXX"] || "g++"
24
21
  end
25
22
 
23
+ # C++17 standard
24
+ $CXXFLAGS << " -std=c++17 -Wall -Wextra -O2"
25
+
26
26
  # Platform-specific settings
27
27
  case RUBY_PLATFORM
28
28
  when /darwin/
29
- # macOS specific flags
30
29
  $CXXFLAGS << " -stdlib=libc++"
30
+ $LDFLAGS << " -stdlib=libc++"
31
31
  when /linux/
32
- # Linux specific flags
33
32
  $LDFLAGS << " -lstdc++"
34
33
  when /mingw|mswin/
35
- # Windows specific flags
36
34
  $CXXFLAGS << " -static-libgcc -static-libstdc++"
37
35
  end
38
36
 
39
- # Create Makefile
37
+ # Debug flags if requested
38
+ if ENV["DEBUG"] == "1"
39
+ $CXXFLAGS << " -g -O0 -DDEBUG"
40
+ else
41
+ $CXXFLAGS << " -DNDEBUG"
42
+ end
43
+
40
44
  create_makefile("veb_tree/veb_tree")
@@ -1,6 +1,30 @@
1
- #include "veb_tree_ext.h"
1
+ #include <cstdint>
2
+ #include <memory>
3
+ #include <stdexcept>
4
+ #include <cmath>
5
+ #include <vector>
6
+ #include <limits>
2
7
  #include <algorithm>
3
8
 
9
+ #include <ruby.h>
10
+
11
+ #if defined(__APPLE__) && defined(RUBY_API_VERSION_CODE)
12
+ #if RUBY_API_VERSION_CODE < 30000
13
+ // Ruby 2.7's missing.h pollutes the global namespace
14
+ #ifdef finite
15
+ #undef finite
16
+ #endif
17
+ #ifdef isnan
18
+ #undef isnan
19
+ #endif
20
+ #ifdef isinf
21
+ #undef isinf
22
+ #endif
23
+ #endif
24
+ #endif
25
+
26
+ #include "veb_tree_ext.h"
27
+
4
28
  namespace VebTree {
5
29
 
6
30
  // ============================================================================
@@ -326,6 +350,9 @@ std::vector<uint64_t> VEBTree::to_vector() const {
326
350
  // Ruby Wrapper Implementation
327
351
  // ============================================================================
328
352
 
353
+ // Ruby 2.x vs 3.x compatibility
354
+ #if RUBY_API_VERSION_CODE >= 30000
355
+ // Ruby 3.0+
329
356
  static const rb_data_type_t veb_tree_type = {
330
357
  "VebTree::Tree",
331
358
  {
@@ -338,6 +365,24 @@ static const rb_data_type_t veb_tree_type = {
338
365
  nullptr, // data
339
366
  RUBY_TYPED_FREE_IMMEDIATELY
340
367
  };
368
+ #else
369
+ // Ruby 2.7
370
+ static void veb_tree_free(void* ptr) {
371
+ delete static_cast<VEBTree*>(ptr);
372
+ }
373
+
374
+ static const rb_data_type_t veb_tree_type = {
375
+ "VebTree::Tree",
376
+ {
377
+ nullptr, // dmark
378
+ veb_tree_free, // dfree
379
+ nullptr, // dsize
380
+ },
381
+ nullptr, // parent
382
+ nullptr, // data
383
+ RUBY_TYPED_FREE_IMMEDIATELY
384
+ };
385
+ #endif
341
386
 
342
387
  VEBTree* TreeWrapper::get_tree(VALUE self) {
343
388
  VEBTree* tree;
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VebTree
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: veb_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - pixelcaliber
@@ -58,7 +58,6 @@ files:
58
58
  - ext/veb_tree/veb_tree_ext.cpp
59
59
  - ext/veb_tree/veb_tree_ext.h
60
60
  - lib/veb_tree.rb
61
- - lib/veb_tree/pure_ruby.rb
62
61
  - lib/veb_tree/version.rb
63
62
  homepage: https://github.com/abhinvv1/Van-Emde-Boas-tree
64
63
  licenses:
@@ -1,277 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
-
5
- module VebTree
6
- class PureRuby
7
- attr_reader :universe_size, :size
8
-
9
- NIL_VALUE = -1
10
-
11
- def initialize(universe_size)
12
- raise ArgumentError, "Universe size must be positive" if universe_size <= 0
13
-
14
- @universe_size = next_power_of_2(universe_size)
15
- warn "Universe size #{universe_size} rounded up to #{@universe_size}" if @universe_size != universe_size
16
-
17
- @size = 0
18
- @min = NIL_VALUE
19
- @max = NIL_VALUE
20
-
21
- # Base case
22
- if @universe_size <= 2
23
- @base_case = true
24
- return
25
- end
26
-
27
- @base_case = false
28
-
29
- # Calculate sqrt
30
- log_u = Math.log2(@universe_size).to_i
31
- @sqrt_size = 1 << (log_u / 2)
32
- @num_clusters = @universe_size / @sqrt_size
33
-
34
- # Lazy allocation
35
- @clusters = Array.new(@num_clusters)
36
- @summary = nil
37
- end
38
-
39
- def insert(key)
40
- validate_key(key)
41
- return false if include?(key)
42
-
43
- # Empty tree
44
- if @min == NIL_VALUE
45
- @min = @max = key
46
- @size += 1
47
- return true
48
- end
49
-
50
- # Base case
51
- if @base_case
52
- @min = key if key < @min
53
- @max = key if key > @max
54
- @size += 1
55
- return true
56
- end
57
-
58
- # Ensure key is not min
59
- if key < @min
60
- key, @min = @min, key
61
- end
62
-
63
- @max = key if key > @max
64
-
65
- # Recursive insert
66
- h = high(key)
67
- l = low(key)
68
-
69
- # Lazy create cluster
70
- @clusters[h] ||= PureRuby.new(@sqrt_size)
71
-
72
- # If cluster was empty, update summary
73
- if @clusters[h].min == NIL_VALUE
74
- @summary ||= PureRuby.new(@num_clusters)
75
- @summary.insert(h)
76
- @clusters[h].instance_variable_set(:@min, l)
77
- @clusters[h].instance_variable_set(:@max, l)
78
- @clusters[h].instance_variable_set(:@size, 1)
79
- else
80
- @clusters[h].insert(l)
81
- end
82
-
83
- @size += 1
84
- true
85
- end
86
-
87
- def delete(key)
88
- return false unless include?(key)
89
-
90
- # Base case
91
- if @base_case
92
- if key == @min && key == @max
93
- @min = @max = NIL_VALUE
94
- elsif key == @min
95
- @min = @max
96
- else
97
- @max = @min
98
- end
99
- @size -= 1
100
- return true
101
- end
102
-
103
- # Only one element
104
- if @size == 1
105
- @min = @max = NIL_VALUE
106
- @size = 0
107
- return true
108
- end
109
-
110
- # Replace min with successor if deleting min
111
- if key == @min
112
- first_cluster = @summary.min
113
- key = index(first_cluster, @clusters[first_cluster].min)
114
- @min = key
115
- end
116
-
117
- # Recursive delete
118
- h = high(key)
119
- l = low(key)
120
-
121
- @clusters[h].delete(l) if @clusters[h]
122
-
123
- # If cluster is empty, remove from summary
124
- if @clusters[h] && @clusters[h].min == NIL_VALUE
125
- @summary.delete(h)
126
- @clusters[h] = nil
127
-
128
- # Update max if necessary
129
- if key == @max
130
- summary_max = @summary.max
131
- if summary_max == NIL_VALUE
132
- @max = @min
133
- else
134
- @max = index(summary_max, @clusters[summary_max].max)
135
- end
136
- end
137
- elsif key == @max && @clusters[h]
138
- @max = index(h, @clusters[h].max)
139
- end
140
-
141
- @size -= 1
142
- true
143
- end
144
-
145
- def include?(key)
146
- return false if key < 0 || key >= @universe_size
147
- return true if key == @min || key == @max
148
- return false if @base_case
149
-
150
- h = high(key)
151
- @clusters[h] && @clusters[h].include?(low(key))
152
- end
153
- alias member? include?
154
-
155
- def min
156
- @min == NIL_VALUE ? nil : @min
157
- end
158
-
159
- def max
160
- @max == NIL_VALUE ? nil : @max
161
- end
162
-
163
- def successor(key)
164
- return nil if @min == NIL_VALUE
165
-
166
- # Base case
167
- if @base_case
168
- return @min if key < @min
169
- return @max if key < @max
170
- return nil
171
- end
172
-
173
- return @min if key < @min
174
-
175
- h = high(key)
176
- l = low(key)
177
-
178
- # Check same cluster
179
- if @clusters[h] && l < @clusters[h].max
180
- offset = @clusters[h].successor(l)
181
- return index(h, offset)
182
- end
183
-
184
- # Next cluster
185
- succ_cluster = @summary.successor(h)
186
- return nil if succ_cluster == NIL_VALUE
187
-
188
- offset = @clusters[succ_cluster].min
189
- index(succ_cluster, offset)
190
- end
191
-
192
- def predecessor(key)
193
- return nil if @max == NIL_VALUE
194
-
195
- # Base case
196
- if @base_case
197
- return @max if key > @max
198
- return @min if key > @min
199
- return nil
200
- end
201
-
202
- return @max if key > @max
203
-
204
- h = high(key)
205
- l = low(key)
206
-
207
- # Check same cluster
208
- if @clusters[h] && l > @clusters[h].min
209
- offset = @clusters[h].predecessor(l)
210
- return index(h, offset)
211
- end
212
-
213
- # Previous cluster
214
- pred_cluster = @summary.predecessor(h)
215
- return @min if pred_cluster == NIL_VALUE && key > @min
216
- return nil if pred_cluster == NIL_VALUE
217
-
218
- offset = @clusters[pred_cluster].max
219
- index(pred_cluster, offset)
220
- end
221
-
222
- def empty?
223
- @size == 0
224
- end
225
-
226
- def clear
227
- @min = @max = NIL_VALUE
228
- @size = 0
229
- unless @base_case
230
- @summary&.clear
231
- @clusters.fill(nil)
232
- end
233
- self
234
- end
235
-
236
- def each
237
- return enum_for(:each) unless block_given?
238
-
239
- current = @min
240
- while current && current != NIL_VALUE
241
- yield current
242
- break if current == @max
243
- current = successor(current)
244
- end
245
-
246
- self
247
- end
248
-
249
- def to_a
250
- each.to_a
251
- end
252
-
253
- private
254
-
255
- def high(x)
256
- x / @sqrt_size
257
- end
258
-
259
- def low(x)
260
- x % @sqrt_size
261
- end
262
-
263
- def index(high, low)
264
- high * @sqrt_size + low
265
- end
266
-
267
- def validate_key(key)
268
- raise ArgumentError, "Key must be non-negative" if key < 0
269
- raise ArgumentError, "Key #{key} exceeds universe size #{@universe_size}" if key >= @universe_size
270
- end
271
-
272
- def next_power_of_2(n)
273
- return 1 if n <= 1
274
- 2 ** (Math.log2(n).ceil)
275
- end
276
- end
277
- end