native_btree 0.5.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
2
  SHA256:
3
- metadata.gz: '08e62bb88bd973ac257570f1b769323dea7ccedf9c0c2d80f5e99ba7eb2f33ff'
4
- data.tar.gz: d8d2cfac5c388216c45b1c17e225a2982871dd94c871414623f73222cd8e6f81
3
+ metadata.gz: 4744529a22fe3d5cd3eb53cf258fa5440346df593e6d268d7af3d2e4b197addf
4
+ data.tar.gz: 887db38cf3c3c23cd72984f6ec2bbdfce1ebce57e547c5cc2d96c81184a36833
5
5
  SHA512:
6
- metadata.gz: 5ef4b7687b447e1b36c32e0252bb71f90005e0cfa729a1ddfd6f62f0b4e6b0c11ef29e3703563459de551fa3ae0577c537cd8d09f1a04fa34745d2abf53ab541
7
- data.tar.gz: 99d89673be28500e83030d0d300f758ff0857d0be0d9026dd39d72fe7b35ac58bdc44ba5fd567145ace04676ada29dd6a4afe895e47c99b23de530f53cf72951
6
+ metadata.gz: f46367c894c10a0ca5db645470228f08edafabe9010a5115d9c92008688eec29f9a0973ba462138483912a2bebe52660eb17828298ea69ebd1709d4811cfb470
7
+ data.tar.gz: 9a342ae22e6ced29b02aa24917f1307fc0a0721885667185266eaa1b23f73fd37c90918126dd1ac6aa24cee08a3c838c25a951e3a84ea5f23cb93e2532d9549d
data/CHANGELOG.md CHANGED
@@ -7,10 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- * delete_if()
10
+ * #compact
11
+ * #compact!
12
+ * #>
13
+ * #>=
14
+ * #<
15
+ * #<=
16
+
17
+ ## [0.6.0] - 2022-10-28
18
+
19
+ ### Added
20
+
21
+ * inspect
22
+ * to_s
23
+ * delete_if
11
24
  * first, min
12
25
  * last, max
13
26
 
27
+ ### Changed
28
+
29
+ * Refactoring
30
+ * Performance improvements for #==
31
+
14
32
  ## [0.5.0] - 2022-10-04
15
33
 
16
34
  ### Added
data/CMakeLists.txt CHANGED
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.5)
2
2
 
3
3
  project(ruby-native-btree
4
4
  LANGUAGES C
5
- VERSION 0.5.0)
5
+ VERSION 0.6.0)
6
6
 
7
7
  include(CheckSymbolExists)
8
8
  include(CheckCCompilerFlag)
data/README.md CHANGED
@@ -103,12 +103,14 @@ Implemented methods:
103
103
  * `delete`
104
104
  * `size`
105
105
  * `height`
106
- * `each` (NB! block is required) (NB! block is required)
106
+ * `each`
107
107
  * `include?`
108
108
  * `clear`
109
109
  * `to_h`
110
110
  * `to_a`
111
111
  * `to_proc`
112
+ * `to_s`
113
+ * `inspect`
112
114
  * `filter` (alias: select)
113
115
  * `filter!` (alias: select!)
114
116
  * `each_value`
@@ -117,5 +119,6 @@ Implemented methods:
117
119
  * `search_after` (GLib version >= 2.68) - Select keys >= first arg, ret new Btree
118
120
  * `empty?`
119
121
  * `reverse_each`
122
+ * `delete_if`
120
123
 
121
124
  You can mix in the `Enumerable` module if additional methods are needed.
@@ -76,3 +76,14 @@ rbtree_to_proc(VALUE self)
76
76
  {
77
77
  return rb_proc_new(to_proc_proc, self);
78
78
  }
79
+
80
+
81
+ VALUE
82
+ rbtree_to_s(VALUE self)
83
+ {
84
+ VALUE h = rbtree_to_h(self);
85
+
86
+ VALUE str = rb_sprintf("#<NativeBtree::Btree:%"PRIsVALUE">", h);
87
+
88
+ return str;
89
+ }
@@ -1,13 +1,20 @@
1
1
  #include <common.h>
2
2
 
3
+ #ifndef _NATIVE_BTREE_ITERATORS_
4
+ #define _NATIVE_BTREE_ITERATORS_
5
+
3
6
  typedef struct {
4
7
  const VALUE block;
5
8
  const RBTree *tree;
9
+ glong counter;
10
+ gushort flags;
6
11
  gconstpointer something;
7
- } RBTreeSearchData;
12
+ } RBTreeSearchContext;
8
13
 
9
14
  #ifdef HAS_GTREE_NODE
10
15
 
11
16
  typedef GTreeNode *(RBTreeStepFunction) (GTreeNode *node);
12
17
 
13
18
  #endif
19
+
20
+ #endif // _NATIVE_BTREE_ITERATORS_
@@ -89,4 +89,13 @@ rbtree_equal(VALUE self, VALUE btree);
89
89
  VALUE
90
90
  rbtree_reverse_each(VALUE self);
91
91
 
92
+ VALUE
93
+ rbtree_first(VALUE self);
94
+
95
+ VALUE
96
+ rbtree_last(VALUE self);
97
+
98
+ VALUE
99
+ rbtree_to_s(VALUE self);
100
+
92
101
  #endif // _NATIVE_BTREE_
@@ -4,6 +4,7 @@
4
4
  #include <compare_trees.h>
5
5
  #else
6
6
  #include <utils.h>
7
+ #include <iterators.h>
7
8
  #endif
8
9
 
9
10
  #ifndef HAS_GTREE_REMOVE_ALL
@@ -20,6 +21,96 @@ rbtree_remove_node(gpointer key, gpointer val, gpointer data) {
20
21
  #endif
21
22
 
22
23
 
24
+ #ifndef HAS_GTREE_NODE
25
+
26
+ static gint
27
+ rbtree_first_cb(gpointer a, gpointer b, gpointer data)
28
+ {
29
+ RBTreeSearchContext *context = (RBTreeSearchContext *) data;
30
+
31
+ context->something = (gconstpointer) b;
32
+ context->counter = 0;
33
+
34
+ return TRUE;
35
+ }
36
+
37
+
38
+ static gint
39
+ rbtree_last_cb(gpointer a, gpointer b, gpointer data)
40
+ {
41
+ RBTreeSearchContext *context = (RBTreeSearchContext *) data;
42
+
43
+ context->something = (gconstpointer) b;
44
+ context->counter += 1;
45
+
46
+ return FALSE;
47
+ }
48
+
49
+
50
+ static gint
51
+ legacy_compare_visitor(gpointer a, gpointer b, gpointer data)
52
+ {
53
+ RBTreeSearchContext *context = (RBTreeSearchContext *) data;
54
+
55
+ GPtrArray *flat_tree = (GPtrArray *) context->something;
56
+ VALUE key = (VALUE) a;
57
+ VALUE val = (VALUE) b;
58
+ VALUE is_eq = Qfalse;
59
+
60
+ VALUE key2 = (VALUE) g_ptr_array_index(flat_tree, context->counter);
61
+ VALUE val2 = (VALUE) g_ptr_array_index(flat_tree, context->counter + 1);
62
+
63
+ is_eq = rb_funcall(key, rb_intern("=="), 1, key2);
64
+
65
+ if (!RTEST(is_eq)) {
66
+ context->flags = 1;
67
+ return TRUE;
68
+ }
69
+
70
+ is_eq = rb_funcall(val, rb_intern("=="), 1, val2);
71
+
72
+ if (!RTEST(is_eq)) {
73
+ context->flags = 1;
74
+ return TRUE;
75
+ }
76
+
77
+ (context->counter) += 2;
78
+
79
+ return FALSE;
80
+ }
81
+
82
+
83
+ static inline gboolean
84
+ legacy_rbtree_compare(const RBTree *a, const RBTree *b)
85
+ {
86
+ gboolean result = TRUE;
87
+
88
+ GPtrArray *second = rbtree_to_ptr_array(b);
89
+
90
+ // assumes that the size of arrays is same (checked before)
91
+
92
+ RBTreeSearchContext context = {
93
+ Qnil,
94
+ NULL,
95
+ 0,
96
+ 0,
97
+ (gconstpointer) second
98
+ };
99
+
100
+ g_tree_foreach(a->gtree, legacy_compare_visitor, &context);
101
+
102
+ if (context.flags) {
103
+ result = FALSE;
104
+ }
105
+
106
+ g_ptr_array_free(second, TRUE);
107
+
108
+ return result;
109
+ }
110
+
111
+ #endif
112
+
113
+
23
114
  VALUE
24
115
  rbtree_set(VALUE self, VALUE key, VALUE value)
25
116
  {
@@ -141,53 +232,6 @@ rbtree_is_empty(VALUE self)
141
232
  }
142
233
 
143
234
 
144
- #ifndef HAS_GTREE_NODE
145
-
146
- static inline gboolean
147
- legacy_rbtree_compare(const RBTree *a, const RBTree *b)
148
- {
149
- gboolean result = FALSE;
150
-
151
- GPtrArray *first = rbtree_to_ptr_array(a);
152
- GPtrArray *second = rbtree_to_ptr_array(b);
153
-
154
- // assumes that the size of arrays is same (checked before)
155
-
156
- VALUE key, val, key2, val2, is_eq;
157
-
158
- for (guint i = 0; i < first->len; i += 2) {
159
- key = (VALUE) g_ptr_array_index(first, i);
160
- val = (VALUE) g_ptr_array_index(first, i + 1);
161
-
162
- key2 = (VALUE) g_ptr_array_index(second, i);
163
- val2 = (VALUE) g_ptr_array_index(second, i + 1);
164
-
165
- is_eq = rb_funcall(key, rb_intern("=="), 1, key2);
166
-
167
- if (!RTEST(is_eq)) {
168
- goto fail;
169
- }
170
-
171
- is_eq = rb_funcall(val, rb_intern("=="), 1, val2);
172
-
173
- if (!RTEST(is_eq)) {
174
- goto fail;
175
- }
176
- }
177
-
178
- result = TRUE;
179
-
180
- fail:
181
-
182
- g_ptr_array_free(first, TRUE);
183
- g_ptr_array_free(second, TRUE);
184
-
185
- return result;
186
- }
187
-
188
- #endif
189
-
190
-
191
235
  VALUE
192
236
  rbtree_equal(VALUE self, VALUE second)
193
237
  {
@@ -221,3 +265,69 @@ rbtree_equal(VALUE self, VALUE second)
221
265
  ret:
222
266
  return result;
223
267
  }
268
+
269
+
270
+ VALUE
271
+ rbtree_first(VALUE self)
272
+ {
273
+ EXTRACT_RBTREE_SELF(rbtree);
274
+
275
+ #ifdef HAS_GTREE_NODE
276
+ GTreeNode *node = g_tree_node_first(rbtree->gtree);
277
+
278
+ if (!node) {
279
+ return Qnil;
280
+ }
281
+
282
+ return (VALUE) g_tree_node_value(node);
283
+ #else
284
+ RBTreeSearchContext context = {
285
+ Qnil,
286
+ NULL,
287
+ 1,
288
+ 0,
289
+ NULL
290
+ };
291
+
292
+ g_tree_foreach(rbtree->gtree, rbtree_first_cb, &context);
293
+
294
+ if (context.counter) {
295
+ return Qnil;
296
+ }
297
+
298
+ return (VALUE) context.something;
299
+ #endif
300
+ }
301
+
302
+
303
+ VALUE
304
+ rbtree_last(VALUE self)
305
+ {
306
+ EXTRACT_RBTREE_SELF(rbtree);
307
+
308
+ #ifdef HAS_GTREE_NODE
309
+ GTreeNode *node = g_tree_node_last(rbtree->gtree);
310
+
311
+ if (!node) {
312
+ return Qnil;
313
+ }
314
+
315
+ return (VALUE) g_tree_node_value(node);
316
+ #else
317
+ RBTreeSearchContext context = {
318
+ Qnil,
319
+ NULL,
320
+ 0,
321
+ 0,
322
+ NULL
323
+ };
324
+
325
+ g_tree_foreach(rbtree->gtree, rbtree_last_cb, &context);
326
+
327
+ if (!context.counter) {
328
+ return Qnil;
329
+ }
330
+
331
+ return (VALUE) context.something;
332
+ #endif
333
+ }
@@ -1,4 +1,5 @@
1
1
  #include <common.h>
2
+ #include <iterators.h>
2
3
 
3
4
  #ifndef HAS_GTREE_NODE
4
5
  #include <utils.h>
@@ -128,3 +129,53 @@ rbtree_reverse_each(VALUE self)
128
129
 
129
130
  return self;
130
131
  }
132
+
133
+
134
+ static gint
135
+ rbtree_delete_if_cb(gpointer k, gpointer v, gpointer data)
136
+ {
137
+ VALUE key = (VALUE) k;
138
+ VALUE value = (VALUE) v;
139
+ RBTreeSearchContext *context = (RBTreeSearchContext *) data;
140
+ VALUE block = (VALUE) context->block;
141
+ GPtrArray *result = (GPtrArray *) context->something;
142
+
143
+ VALUE to_delete = rb_funcall(block, rb_intern("call"), 2, key, value);
144
+
145
+ if (RTEST(to_delete)) {
146
+ g_ptr_array_add(result, (gpointer) key);
147
+ }
148
+
149
+ return FALSE;
150
+ }
151
+
152
+
153
+ VALUE
154
+ rbtree_delete_if(VALUE self)
155
+ {
156
+ EXTRACT_RBTREE_SELF(rbtree);
157
+
158
+ GPtrArray *to_delete = g_ptr_array_new();
159
+
160
+ RETURN_SIZED_ENUMERATOR(self, 0, 0, rbtree_enum_length);
161
+
162
+ VALUE block = rb_block_proc();
163
+
164
+ RBTreeSearchContext context = {
165
+ block,
166
+ NULL,
167
+ 0,
168
+ 0,
169
+ to_delete
170
+ };
171
+
172
+ g_tree_foreach(rbtree->gtree, rbtree_delete_if_cb, &context);
173
+
174
+ for (guint i = 0; i < to_delete->len; i++) {
175
+ g_tree_remove(rbtree->gtree, g_ptr_array_index(to_delete, i));
176
+ }
177
+
178
+ g_ptr_array_free(to_delete, TRUE);
179
+
180
+ return self;
181
+ }
@@ -57,6 +57,13 @@ Init_native_btree()
57
57
  rb_define_method(native_btree_class, "empty?", rbtree_is_empty, 0);
58
58
  rb_define_method(native_btree_class, "==", rbtree_equal, 1);
59
59
  rb_define_method(native_btree_class, "reverse_each", rbtree_reverse_each, 0);
60
+ rb_define_method(native_btree_class, "first", rbtree_first, 0);
61
+ rb_define_alias(native_btree_class, "min", "first");
62
+ rb_define_method(native_btree_class, "last", rbtree_last, 0);
63
+ rb_define_alias(native_btree_class, "max", "last");
64
+ rb_define_method(native_btree_class, "delete_if", rbtree_delete_if, 0);
65
+ rb_define_method(native_btree_class, "to_s", rbtree_to_s, 0);
66
+ rb_define_alias(native_btree_class, "inspect", "to_s");
60
67
 
61
68
  #ifdef HAS_GTREE_NODE
62
69
  rb_define_method(native_btree_class, "select_before", rbtree_select_before, 1);
@@ -4,7 +4,7 @@
4
4
  static gboolean
5
5
  filter_callback(gpointer a, gpointer b, gpointer data)
6
6
  {
7
- RBTreeSearchData *context = (RBTreeSearchData *) data;
7
+ RBTreeSearchContext *context = (RBTreeSearchContext *) data;
8
8
 
9
9
  VALUE compare_result = rb_funcall(
10
10
  context->block,
@@ -24,7 +24,7 @@ filter_callback(gpointer a, gpointer b, gpointer data)
24
24
  static gboolean
25
25
  filter_bang_callback(gpointer a, gpointer b, gpointer data)
26
26
  {
27
- RBTreeSearchData *context = (RBTreeSearchData *) data;
27
+ RBTreeSearchContext *context = (RBTreeSearchContext *) data;
28
28
  GPtrArray *to_remove = (GPtrArray *) context->something;
29
29
 
30
30
  VALUE compare_result = rb_funcall(
@@ -55,9 +55,11 @@ rbtree_filter(VALUE self)
55
55
 
56
56
  EXTRACT_RBTREE(new_tree, new_rbtree);
57
57
 
58
- RBTreeSearchData data = {
58
+ RBTreeSearchContext data = {
59
59
  block,
60
60
  new_rbtree,
61
+ 0,
62
+ 0,
61
63
  NULL
62
64
  };
63
65
 
@@ -76,9 +78,11 @@ rbtree_filter_bang(VALUE self)
76
78
 
77
79
  GPtrArray *to_remove = g_ptr_array_new();
78
80
 
79
- RBTreeSearchData data = {
81
+ RBTreeSearchContext data = {
80
82
  block,
81
83
  NULL,
84
+ 0,
85
+ 0,
82
86
  (gconstpointer) to_remove
83
87
  };
84
88
 
Binary file
@@ -1,3 +1,3 @@
1
1
  module NativeBtree
2
- VERSION = "0.5.0".freeze
2
+ VERSION = "0.6.0".freeze
3
3
  end
data/spec/debug.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # rubocop:disable all
2
2
 
3
3
  require_relative "../lib/native_btree/native_btree"
4
+ require 'benchmark'
4
5
 
5
6
  NativeBtree::Btree.include(Enumerable)
6
7
 
@@ -65,6 +65,37 @@ RSpec.describe NativeBtree do
65
65
  expect(pr.call(12)).to be_nil
66
66
  end
67
67
  end
68
+
69
+ describe "#to_s" do
70
+ it 'respond to' do
71
+ expect(tree).to respond_to(:to_s)
72
+ end
73
+
74
+ it 'return correct str for empty' do
75
+ expect(tree.to_s).to eq('#<NativeBtree::Btree:{}>')
76
+ end
77
+
78
+ it 'return correct str' do
79
+ tree[10] = "20"
80
+ expect(tree.to_s).to eq('#<NativeBtree::Btree:{10=>"20"}>')
81
+ end
82
+ end
83
+
84
+ describe "#inspect" do
85
+ it 'respond to' do
86
+ expect(tree).to respond_to(:inspect)
87
+ end
88
+
89
+ it 'return correct str for empty' do
90
+ expect(tree.to_s).to eq('#<NativeBtree::Btree:{}>')
91
+ end
92
+
93
+ it 'return correct str' do
94
+ tree[10] = "20"
95
+ tree[30] = "40"
96
+ expect(tree.to_s).to eq('#<NativeBtree::Btree:{10=>"20", 30=>"40"}>')
97
+ end
98
+ end
68
99
  end
69
100
  end
70
101
  end
@@ -258,5 +258,62 @@ RSpec.describe NativeBtree do
258
258
  expect(tree).not_to eq tree2
259
259
  end
260
260
  end
261
+
262
+ describe '#last method' do
263
+ it 'respond to' do
264
+ expect(tree).to respond_to(:last)
265
+ end
266
+
267
+ it 'return correct value' do
268
+ tree[1] = 10
269
+ tree[10] = 20
270
+ tree[20] = 30
271
+
272
+ expect(tree.last).to eq(30)
273
+ end
274
+
275
+ it 'return nil if empty' do
276
+ expect(tree.last).to be_nil
277
+ end
278
+ end
279
+
280
+ describe '#first method' do
281
+ it 'respond to' do
282
+ expect(tree).to respond_to(:first)
283
+ end
284
+
285
+ it 'return correct value' do
286
+ tree[1] = 10
287
+ tree[10] = 20
288
+ tree[20] = 30
289
+
290
+ expect(tree.first).to eq(10)
291
+ end
292
+
293
+ it 'return nil if empty' do
294
+ expect(tree.first).to be_nil
295
+ end
296
+ end
297
+
298
+ describe '#delete_if method' do
299
+ it 'respond to' do
300
+ expect(tree).to respond_to(:delete_if)
301
+ end
302
+
303
+ it 'return self' do
304
+ expect(tree.delete_if { |_, _| false }).to be tree
305
+ end
306
+
307
+ it 'return expected result' do
308
+ tree[1] = 10
309
+ tree[10] = 20
310
+ tree[20] = 30
311
+
312
+ tree.delete_if { |_, v| v < 30 }
313
+
314
+ expect(tree.to_a).to eq([[20, 30]])
315
+ end
316
+ end
317
+
261
318
  end
262
319
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: native_btree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Feodorov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-03 00:00:00.000000000 Z
11
+ date: 2022-10-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby bindings to GTree balanced binary tree from GLib library.
14
14
  email: