ffi-radix_tree 0.2.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c2547ed89d9cbedb9bd340a86785aa16f0becd3c
4
- data.tar.gz: 737b4483c593146c8c9fef84330f9ed5eac149ee
2
+ SHA256:
3
+ metadata.gz: 63946ad680524b97f53dd06a3bb4514ce3ab4b12a2f2d5a23fef32e36941bfba
4
+ data.tar.gz: 4235440c2f4f348c3d9f9e496ba5dbf1b0c5c4645b674cd04086ce60f57da650
5
5
  SHA512:
6
- metadata.gz: 79474879d50035f089b2a04b60db2dee547e9aabf4aeffa43c33b430156bac7004e55da050e35bb71cda97eede7bcda077c9ca4a53dbc66809d040a06c04d277
7
- data.tar.gz: becb72bae362661101c75aed79d53c42f9d698c19116593b0180971026ba8e59eebcb712d8c65ea7e4e5ffbd71a9de6ef6dcf46b2a22141cc2e64288fdafddb9
6
+ metadata.gz: 7ac02fdf65f154c8c3746a565b2b6d3afe738643b9227f82313ddc7bc12cfce6f2f617ac535a876fa2b6da60588fe8564b9d24d86212f71f568fcf2d08ce9ff3
7
+ data.tar.gz: ee16b0514b5a1efef08d3a95c7646e78e9ab44d2f110a3b928aa5335964f63a86b1fb064847c9ba9ac417c4c951bc72259e8039a07556b8c0739806affe9bd37
data/README.md CHANGED
@@ -22,7 +22,41 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ ```ruby
26
+ # create a new tree
27
+ rtree = ::FFI::RadixTree::Tree.new
28
+
29
+ # add key/value pairs to the tree
30
+ rtree.push("key1", "value1")
31
+ rtree.push("key2", ["value2", "value3"])
32
+ rtree.push("key3", { :attr1 => "value4", :attr2 => "value5" })
33
+
34
+ # work with the collection
35
+ if rtree.has_key?("key1")
36
+ val = rtree.get("key2")
37
+ rtree.set("key3", "value6")
38
+ end
39
+
40
+ # search the tree using the keys
41
+
42
+ # keys based off the root word: "manage"
43
+ rtree.push("manage", "base verb")
44
+ rtree.push("managed", "past tense")
45
+ rtree.push("manager", "noun")
46
+ rtree.push("managers", "plural noun")
47
+ rtree.push("managing", "present tense")
48
+
49
+ # Find the key that matches the _most_ of the beggining of the search term
50
+ rtree.longest_prefix("managerial") # returns "manager"
51
+ rtree.longest_prefix_and_value("managerial") # returns ["manager", "noun"]
52
+ rtree.longest_prefix_value("managerial") # returns "noun"
53
+
54
+ # Find all values whose keys match the _most_ of the beginning of the search term
55
+ rtree.greedy_match("managerial") # returns ["noun", "plural noun"]
56
+
57
+ # Find all values whose keys are included _anywhere_ in the search term
58
+ rtree.greedy_substring_match("I managed to jump") # returns ["base verb", "past tense"]
59
+ ```
26
60
 
27
61
  ## Development
28
62
 
data/Rakefile CHANGED
@@ -7,6 +7,67 @@ namespace :radixtree do
7
7
  task :compile do
8
8
  Rake::Task[:compile_radixtree].invoke
9
9
  end
10
+
11
+ desc "run benchmarks for radixtree lib"
12
+ task :benchmark do
13
+ require "benchmark/ips"
14
+ require "./lib/ffi/radix_tree"
15
+
16
+ radix_tree = ::FFI::RadixTree::Tree.new
17
+
18
+ (1..1000).each do |number|
19
+ radix_tree.push(number.to_s, "DERP#{number}" * (number % 10))
20
+ radix_tree.push(number.to_s * 100, "DERP#{number}" * (number % 10))
21
+ radix_tree.push(number.to_s * 1000, "DERP#{number}" * (number % 10))
22
+ end
23
+
24
+ ::Benchmark.ips do |x|
25
+ x.config(:warmup => 10)
26
+
27
+ x.report("get") do
28
+ radix_tree.get(rand(1000).to_s * [1, 100, 100].sample)
29
+ end
30
+
31
+ x.report("longest prefix") do
32
+ radix_tree.longest_prefix(rand(1000).to_s * [1, 100, 100].sample)
33
+ end
34
+
35
+ x.report("get then value") do
36
+ val = rand(1000).to_s * [1, 100, 100].sample
37
+
38
+ radix_tree.longest_prefix(val)
39
+ radix_tree.longest_prefix_value(val)
40
+ end
41
+
42
+ x.report("prefix and value (combined)") do
43
+ radix_tree.longest_prefix_and_value(rand(1000).to_s * [1, 100, 100].sample)
44
+ end
45
+
46
+ x.report("longest prefix (miss)") do
47
+ radix_tree.longest_prefix("DERP DERPIE")
48
+ end
49
+
50
+ x.report("prefix and value (combined/miss)") do
51
+ radix_tree.longest_prefix_and_value("DERP DERPIE")
52
+ end
53
+
54
+ x.report("greedy match") do
55
+ radix_tree.greedy_match(rand(1000).to_s * [1, 100, 100].sample)
56
+ end
57
+
58
+ x.report("greedy match (miss)") do
59
+ radix_tree.greedy_match("DERP DERPIE")
60
+ end
61
+
62
+ x.report("greedy substring match") do
63
+ radix_tree.greedy_substring_match(rand(1000).to_s * [1, 100, 100].sample)
64
+ end
65
+
66
+ x.report("greedy substring match (miss)") do
67
+ radix_tree.greedy_substring_match("DERP DERPIE")
68
+ end
69
+ end
70
+ end
10
71
  end
11
72
 
12
73
  Rake::TestTask.new(:spec) do |t|
@@ -34,7 +34,8 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "msgpack"
35
35
  spec.add_dependency "ffi"
36
36
 
37
- spec.add_development_dependency "bundler", "~> 1.15"
37
+ spec.add_development_dependency "benchmark-ips"
38
+ spec.add_development_dependency "bundler"
38
39
  spec.add_development_dependency "rake", "~> 10.0"
39
40
  spec.add_development_dependency "mocha"
40
41
  spec.add_development_dependency "pry"
@@ -1,5 +1,5 @@
1
1
  module FFI
2
2
  module RadixTree
3
- VERSION = "0.2.0"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
@@ -77,30 +77,29 @@ module FFI
77
77
  attach_function :erase, [:pointer, :string], :void
78
78
  attach_function :fetch, [:pointer, :string, :pointer], :pointer
79
79
  attach_function :insert, [:pointer, :string, :pointer, :size_t], :void
80
+ attach_function :update, [:pointer, :string, :pointer, :size_t], :bool
80
81
  attach_function :longest_prefix, [:pointer, :string], :string
82
+ attach_function :longest_prefix_and_value, [:pointer, :string, :pointer, :pointer], :pointer
81
83
  attach_function :longest_prefix_value, [:pointer, :string, :pointer], :pointer
84
+ attach_function :greedy_match, [:pointer, :string, :pointer, :pointer], :int
85
+ attach_function :greedy_substring_match, [:pointer, :string, :pointer, :pointer], :int
82
86
  attach_function :match_free, [:pointer], :void
87
+ attach_function :match_sizes_free, [:pointer], :void
88
+ attach_function :multi_match_free, [:pointer, :int], :void
83
89
  attach_function :has_key, [:pointer, :string], :bool
84
90
 
85
91
  class Tree
86
- def self.destroy!(tree)
87
- tree.destroy! unless tree.nil?
88
- end
89
-
90
92
  def initialize
91
- @ptr = ::FFI::RadixTree.create
93
+ @ptr = ::FFI::AutoPointer.new(::FFI::RadixTree.create, ::FFI::RadixTree.method(:destroy))
92
94
  @first_character_present = {}
93
95
  end
94
96
 
95
- def destroy!
96
- ::FFI::RadixTree.destroy(@ptr) unless @ptr.nil?
97
- @ptr = nil
98
- end
99
-
100
97
  def has_key?(key)
101
98
  ::FFI::RadixTree.has_key(@ptr, key)
102
99
  end
103
100
 
101
+ alias_method :key?, :has_key?
102
+
104
103
  def push(key, value)
105
104
  push_response = nil
106
105
  @first_character_present[key[0]] = true
@@ -115,6 +114,25 @@ module FFI
115
114
  push_response
116
115
  end
117
116
 
117
+ def push_or_update(key, value)
118
+ response = nil
119
+ @first_character_present[key[0]] = true
120
+ storage_data = ::MessagePack.pack(value)
121
+ bytesize = storage_data.bytesize
122
+
123
+ ::FFI::MemoryPointer.new(:char, bytesize, true) do |memory_buffer|
124
+ memory_buffer.put_bytes(0, storage_data)
125
+ response = ::FFI::RadixTree.update(@ptr, key, memory_buffer, bytesize)
126
+ response ||= ::FFI::RadixTree.insert(@ptr, key, memory_buffer, bytesize)
127
+ end
128
+
129
+ response
130
+ end
131
+
132
+ def erase(key)
133
+ ::FFI::RadixTree.erase(@ptr, key)
134
+ end
135
+
118
136
  def get(key)
119
137
  return nil unless @first_character_present[key[0]]
120
138
  byte_pointer = get_response = nil
@@ -122,7 +140,11 @@ module FFI
122
140
  ::FFI::MemoryPointer.new(:int) do |byte_length|
123
141
  byte_pointer = ::FFI::RadixTree.fetch(@ptr, key, byte_length)
124
142
  bytesize = byte_length.read_int
125
- get_response = ::MessagePack.unpack(byte_pointer.get_bytes(0, bytesize)) if bytesize && bytesize > 0
143
+
144
+ if bytesize && bytesize > 0
145
+ bytes = byte_pointer.get_bytes(0, bytesize)
146
+ get_response = ::MessagePack.unpack(bytes)
147
+ end
126
148
  end
127
149
 
128
150
  get_response
@@ -139,6 +161,29 @@ module FFI
139
161
  ::FFI::RadixTree.match_free(p_out) if p_out
140
162
  end
141
163
 
164
+ def longest_prefix_and_value(string)
165
+ return [nil, nil] unless @first_character_present[string[0]]
166
+ byte_pointer = prefix_response = get_response = nil
167
+
168
+ ::FFI::MemoryPointer.new(:int) do |byte_length|
169
+ ::FFI::MemoryPointer.new(:int) do |prefix_length|
170
+ byte_pointer = ::FFI::RadixTree.longest_prefix_and_value(@ptr, string, byte_length, prefix_length)
171
+ bytesize = byte_length.read_int
172
+
173
+ if bytesize && bytesize > 0
174
+ prefix_size = prefix_length.read_int
175
+ get_response = byte_pointer.get_bytes(0, bytesize)
176
+ prefix_response = get_response[0..(prefix_size - 1)]
177
+ get_response = ::MessagePack.unpack(get_response[prefix_size..-1])
178
+ end
179
+ end
180
+ end
181
+
182
+ [prefix_response, get_response]
183
+ ensure
184
+ ::FFI::RadixTree.match_free(byte_pointer) if byte_pointer
185
+ end
186
+
142
187
  def longest_prefix_value(string)
143
188
  return nil unless @first_character_present[string[0]]
144
189
  byte_pointer = get_response = nil
@@ -153,6 +198,61 @@ module FFI
153
198
  ensure
154
199
  ::FFI::RadixTree.match_free(byte_pointer) if byte_pointer
155
200
  end
201
+
202
+ def greedy_match(string)
203
+ return [] unless @first_character_present[string[0]]
204
+ array_pointer = nil
205
+ match_sizes_pointer = nil
206
+ array_size = 0
207
+ get_response = []
208
+
209
+ ::FFI::MemoryPointer.new(:pointer) do |match_array|
210
+ ::FFI::MemoryPointer.new(:pointer) do |match_sizes_array|
211
+ array_size = ::FFI::RadixTree.greedy_match(@ptr, string, match_array, match_sizes_array)
212
+ if array_size > 0
213
+ match_sizes_pointer = match_sizes_array.read_pointer
214
+ match_sizes = match_sizes_pointer.get_array_of_int(0, array_size)
215
+ array_pointer = match_array.read_pointer
216
+ char_arrays = array_pointer.get_array_of_pointer(0, array_size)
217
+ char_arrays.each_with_index do |ptr, index|
218
+ get_response << ::MessagePack.unpack(ptr.get_bytes(0, match_sizes[index]))
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ get_response
225
+ ensure
226
+ ::FFI::RadixTree.multi_match_free(array_pointer, array_size) if array_pointer
227
+ ::FFI::RadixTree.match_sizes_free(match_sizes_pointer) if match_sizes_pointer
228
+ end
229
+
230
+ def greedy_substring_match(string)
231
+ array_pointer = nil
232
+ match_sizes_pointer = nil
233
+ array_size = 0
234
+ get_response = []
235
+
236
+ ::FFI::MemoryPointer.new(:pointer) do |match_array|
237
+ ::FFI::MemoryPointer.new(:pointer) do |match_sizes_array|
238
+ array_size = ::FFI::RadixTree.greedy_substring_match(@ptr, string, match_array, match_sizes_array)
239
+ if array_size > 0
240
+ match_sizes_pointer = match_sizes_array.read_pointer
241
+ match_sizes = match_sizes_pointer.get_array_of_int(0, array_size)
242
+ array_pointer = match_array.read_pointer
243
+ char_arrays = array_pointer.get_array_of_pointer(0, array_size)
244
+ char_arrays.each_with_index do |ptr, index|
245
+ get_response << ::MessagePack.unpack(ptr.get_bytes(0, match_sizes[index]))
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ get_response
252
+ ensure
253
+ ::FFI::RadixTree.multi_match_free(array_pointer, array_size) if array_pointer
254
+ ::FFI::RadixTree.match_sizes_free(match_sizes_pointer) if match_sizes_pointer
255
+ end
156
256
  end
157
257
  end
158
258
  end
@@ -32,9 +32,19 @@ bool has_key(radix_tree<std::string, std::vector<char>>* map_pointer, const char
32
32
  }
33
33
 
34
34
  void match_free(const char* match) {
35
+ delete[] match;
36
+ }
37
+
38
+ void match_sizes_free(const int* match_sizes) {
39
+ delete[] match_sizes;
40
+ }
41
+
42
+ void multi_match_free(const char** match, int length) {
35
43
  if (match != NULL) {
44
+ for (int i=0; i<length; ++i) {
45
+ delete[] match[i];
46
+ }
36
47
  delete[] match;
37
- match = NULL;
38
48
  }
39
49
  }
40
50
 
@@ -44,7 +54,6 @@ const char* longest_prefix(radix_tree<std::string, std::vector<char>>* map_point
44
54
 
45
55
  if (iter != map_pointer->end()) {
46
56
  char *val = new char[iter->first.size() + 1]{0};
47
- val[iter->first.size()] = '\0';
48
57
  memcpy(val, iter->first.c_str(), iter->first.size());
49
58
 
50
59
  return val;
@@ -53,6 +62,33 @@ const char* longest_prefix(radix_tree<std::string, std::vector<char>>* map_point
53
62
  return NULL;
54
63
  }
55
64
 
65
+ const char* longest_prefix_and_value(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, int* read_size, int* prefix_size) {
66
+ std::string string_key(key);
67
+ auto iter = map_pointer->longest_match(string_key);
68
+
69
+ if (iter != map_pointer->end()) {
70
+ long counter = 0;
71
+ int size_of_response = iter->second.size() + iter->first.size();
72
+ char *return_val = new char[size_of_response]{0};
73
+
74
+ strncpy(return_val, iter->first.c_str(), iter->first.size());
75
+ counter = iter->first.size();
76
+
77
+ for( auto& val3 : iter->second) {
78
+ return_val[counter] = val3;
79
+ counter++;
80
+ }
81
+
82
+ *prefix_size = iter->first.size();
83
+ *read_size = size_of_response;
84
+ return return_val;
85
+ }
86
+
87
+ *prefix_size = 0;
88
+ *read_size = 0;
89
+ return NULL;
90
+ }
91
+
56
92
  const char* longest_prefix_value(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, int* read_size) {
57
93
  std::string string_key(key);
58
94
  auto iter = map_pointer->longest_match(string_key);
@@ -73,7 +109,7 @@ const char* longest_prefix_value(radix_tree<std::string, std::vector<char>>* map
73
109
  return NULL;
74
110
  }
75
111
 
76
- const char* fetch(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, int* read_size) {
112
+ char* fetch(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, int* read_size) {
77
113
  auto iter = map_pointer->find(std::string(key));
78
114
  long counter = 0;
79
115
 
@@ -92,10 +128,64 @@ const char* fetch(radix_tree<std::string, std::vector<char>>* map_pointer, const
92
128
  return NULL;
93
129
  }
94
130
 
131
+ int greedy_match(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, const char*** matches, int** match_sizes) {
132
+ std::string string_key(key);
133
+ typedef radix_tree<std::string, std::vector<char>>::iterator iterator;
134
+ std::vector<iterator> vec;
135
+ map_pointer->greedy_match(string_key, vec);
136
+ long counter = 0;
137
+
138
+ if (vec.size() > 0) {
139
+ *matches = new const char* [vec.size()]{nullptr};
140
+ *match_sizes = new int [vec.size()]{0};
141
+ for (auto& iter : vec) {
142
+ auto ret_str = new char[iter->second.size()];
143
+ long char_index = 0;
144
+ for (auto& val : iter->second) {
145
+ ret_str[char_index] = val;
146
+ ++char_index;
147
+ }
148
+ (*matches)[counter] = ret_str;
149
+ (*match_sizes)[counter] = iter->second.size();
150
+ ++counter;
151
+ }
152
+ }
153
+ return counter;
154
+ }
155
+
156
+ int greedy_substring_match(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, const char*** matches, int** match_sizes) {
157
+ std::string string_key(key);
158
+ typedef radix_tree<std::string, std::vector<char>>::iterator iterator;
159
+ std::vector<iterator> vec;
160
+ map_pointer->greedy_substring_match(string_key, vec);
161
+ long counter = 0;
162
+
163
+ if (vec.size() > 0) {
164
+ *matches = new const char* [vec.size()]{nullptr};
165
+ *match_sizes = new int [vec.size()]{0};
166
+ for (auto& iter : vec) {
167
+ auto ret_str = new char[iter->second.size()];
168
+ long char_index = 0;
169
+ for (auto& val : iter->second) {
170
+ ret_str[char_index] = val;
171
+ ++char_index;
172
+ }
173
+ (*matches)[counter] = ret_str;
174
+ (*match_sizes)[counter] = iter->second.size();
175
+ ++counter;
176
+ }
177
+ }
178
+ return counter;
179
+ }
180
+
95
181
  void insert(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, char* value, size_t size) {
96
182
  map_pointer->insert({std::string(key), std::vector<char>(value, value + size)});
97
183
  }
98
184
 
185
+ bool update(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, char* value, size_t size) {
186
+ return map_pointer->update({std::string(key), std::vector<char>(value, value + size)});
187
+ }
188
+
99
189
  void destroy(radix_tree<std::string, std::vector<char>>* map_pointer) {
100
190
  delete map_pointer;
101
191
  map_pointer = NULL;
@@ -67,10 +67,12 @@ public:
67
67
  iterator end();
68
68
 
69
69
  std::pair<iterator, bool> insert(const value_type &val);
70
+ bool update(const value_type &val);
70
71
  bool erase(const K &key);
71
72
  void erase(iterator it);
72
73
  void prefix_match(const K &key, std::vector<iterator> &vec);
73
74
  void greedy_match(const K &key, std::vector<iterator> &vec);
75
+ void greedy_substring_match(const K &key, std::vector<iterator> &vec);
74
76
  iterator longest_match(const K &key);
75
77
 
76
78
  T& operator[] (const K &lhs);
@@ -81,9 +83,11 @@ private:
81
83
 
82
84
  radix_tree_node<K, T>* begin(radix_tree_node<K, T> *node);
83
85
  radix_tree_node<K, T>* find_node(const K &key, radix_tree_node<K, T> *node, int depth);
86
+ std::vector<radix_tree_node<K, T>*> find_leaf_nodes_with_substr(const K &key, radix_tree_node<K, T> *node, const K &ancestor_key);
84
87
  radix_tree_node<K, T>* append(radix_tree_node<K, T> *parent, const value_type &val);
85
88
  radix_tree_node<K, T>* prepend(radix_tree_node<K, T> *node, const value_type &val);
86
89
  void greedy_match(radix_tree_node<K, T> *node, std::vector<iterator> &vec);
90
+ void greedy_substring_match(radix_tree_node<K, T> *node, std::vector<iterator> &vec);
87
91
 
88
92
  radix_tree(const radix_tree& other); // delete
89
93
  radix_tree& operator =(const radix_tree other); // delete
@@ -232,6 +236,23 @@ void radix_tree<K, T>::greedy_match(radix_tree_node<K, T> *node, std::vector<ite
232
236
  }
233
237
  }
234
238
 
239
+ template <typename K, typename T>
240
+ void radix_tree<K, T>::greedy_substring_match(const K &key, std::vector<iterator> &vec)
241
+ {
242
+ std::vector<radix_tree_node<K, T>*> nodes;
243
+
244
+ vec.clear();
245
+
246
+ if (m_root == NULL)
247
+ return;
248
+
249
+ nodes = find_leaf_nodes_with_substr(key, m_root, "");
250
+
251
+ for (auto& node : nodes) {
252
+ vec.push_back(node);
253
+ }
254
+ }
255
+
235
256
  template <typename K, typename T>
236
257
  void radix_tree<K, T>::erase(iterator it)
237
258
  {
@@ -448,6 +469,22 @@ std::pair<typename radix_tree<K, T>::iterator, bool> radix_tree<K, T>::insert(co
448
469
  }
449
470
  }
450
471
 
472
+ template <typename K, typename T>
473
+ bool radix_tree<K, T>::update(const value_type &val)
474
+ {
475
+ if (m_root == NULL)
476
+ return false;
477
+
478
+ radix_tree_node<K, T> *node = find_node(val.first, m_root, 0);
479
+
480
+ // if the node is a internal node, return false
481
+ if (! node->m_is_leaf)
482
+ return false;
483
+
484
+ node->m_value = new value_type(val);
485
+ return true;
486
+ }
487
+
451
488
  template <typename K, typename T>
452
489
  typename radix_tree<K, T>::iterator radix_tree<K, T>::find(const K &key)
453
490
  {
@@ -495,6 +532,30 @@ radix_tree_node<K, T>* radix_tree<K, T>::find_node(const K &key, radix_tree_node
495
532
  return node;
496
533
  }
497
534
 
535
+ template <typename K, typename T>
536
+ std::vector<radix_tree_node<K, T>*> radix_tree<K, T>::find_leaf_nodes_with_substr(const K &key, radix_tree_node<K, T> *node, const K &ancestor_key)
537
+ {
538
+ std::vector<radix_tree_node<K, T>*> nodes;
539
+
540
+ if (node->m_children.empty())
541
+ return nodes;
542
+
543
+ typename radix_tree_node<K, T>::it_child it;
544
+ for (it = node->m_children.begin(); it != node->m_children.end(); ++it) {
545
+ if (it->second->m_is_leaf) {
546
+ nodes.push_back(it->second);
547
+ } else {
548
+ auto child_key = ancestor_key + it->first;
549
+ if (key.find(child_key) != std::string::npos ) {
550
+ auto found_nodes = find_leaf_nodes_with_substr(key, it->second, child_key);
551
+ nodes.insert(nodes.end(), found_nodes.begin(), found_nodes.end());
552
+ }
553
+ }
554
+ }
555
+
556
+ return nodes;
557
+ }
558
+
498
559
  /*
499
560
 
500
561
  (root)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-radix_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Dewitt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-23 00:00:00.000000000 Z
11
+ date: 2021-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -38,20 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: benchmark-ips
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - "~>"
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
- version: '1.15'
61
+ version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - "~>"
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '1.15'
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -138,7 +152,7 @@ licenses:
138
152
  - MIT
139
153
  metadata:
140
154
  allowed_push_host: https://rubygems.org
141
- post_install_message:
155
+ post_install_message:
142
156
  rdoc_options: []
143
157
  require_paths:
144
158
  - lib
@@ -153,9 +167,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
167
  - !ruby/object:Gem::Version
154
168
  version: '0'
155
169
  requirements: []
156
- rubyforge_project:
157
- rubygems_version: 2.6.13
158
- signing_key:
170
+ rubygems_version: 3.0.3
171
+ signing_key:
159
172
  specification_version: 4
160
173
  summary: radix tree implementation in c++ with FFI bindings
161
174
  test_files: []