native_btree 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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: