native_btree 0.4.1 → 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 +4 -4
- data/CHANGELOG.md +39 -2
- data/CMakeLists.txt +1 -1
- data/README.md +6 -1
- data/ext/native_btree/CMakeLists.txt +4 -0
- data/ext/native_btree/conversion.c +11 -0
- data/ext/native_btree/glib2_68/CMakeLists.txt +1 -0
- data/ext/native_btree/glib2_68/compare_trees.c +54 -0
- data/ext/native_btree/include/compare_trees.h +4 -0
- data/ext/native_btree/include/iterators.h +8 -1
- data/ext/native_btree/include/native_btree.h +15 -0
- data/ext/native_btree/include/utils.h +10 -0
- data/ext/native_btree/instance.c +198 -3
- data/ext/native_btree/iterators.c +107 -6
- data/ext/native_btree/native_btree.c +9 -0
- data/ext/native_btree/search.c +8 -4
- data/ext/native_btree/utils.c +26 -0
- data/lib/native_btree/native_btree.bundle +0 -0
- data/lib/native_btree/version.rb +1 -1
- data/spec/debug.rb +10 -11
- data/spec/native_btree_conversion_spec.rb +31 -0
- data/spec/native_btree_instance_spec.rb +129 -0
- data/spec/native_btree_iterators_spec.rb +60 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4744529a22fe3d5cd3eb53cf258fa5440346df593e6d268d7af3d2e4b197addf
|
4
|
+
data.tar.gz: 887db38cf3c3c23cd72984f6ec2bbdfce1ebce57e547c5cc2d96c81184a36833
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f46367c894c10a0ca5db645470228f08edafabe9010a5115d9c92008688eec29f9a0973ba462138483912a2bebe52660eb17828298ea69ebd1709d4811cfb470
|
7
|
+
data.tar.gz: 9a342ae22e6ced29b02aa24917f1307fc0a0721885667185266eaa1b23f73fd37c90918126dd1ac6aa24cee08a3c838c25a951e3a84ea5f23cb93e2532d9549d
|
data/CHANGELOG.md
CHANGED
@@ -7,8 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
-
*
|
11
|
-
*
|
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
|
24
|
+
* first, min
|
25
|
+
* last, max
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
* Refactoring
|
30
|
+
* Performance improvements for #==
|
31
|
+
|
32
|
+
## [0.5.0] - 2022-10-04
|
33
|
+
|
34
|
+
### Added
|
35
|
+
|
36
|
+
* ==()
|
37
|
+
* each like methods without a block returns Enumerator
|
38
|
+
* reverse_each
|
39
|
+
|
40
|
+
### Changed
|
41
|
+
|
42
|
+
* Refactoring
|
43
|
+
|
44
|
+
## [0.4.1] - 2022-09-30
|
45
|
+
|
46
|
+
### Changed
|
47
|
+
|
48
|
+
* Fix - Failed building on Apple M1 CPU
|
12
49
|
|
13
50
|
## [0.4.0] - 2022-09-16
|
14
51
|
|
data/CMakeLists.txt
CHANGED
data/README.md
CHANGED
@@ -99,15 +99,18 @@ Implemented methods:
|
|
99
99
|
|
100
100
|
* `[]= (alias: set)`
|
101
101
|
* `[] (alias: get)`
|
102
|
+
* `==`
|
102
103
|
* `delete`
|
103
104
|
* `size`
|
104
105
|
* `height`
|
105
|
-
* `each`
|
106
|
+
* `each`
|
106
107
|
* `include?`
|
107
108
|
* `clear`
|
108
109
|
* `to_h`
|
109
110
|
* `to_a`
|
110
111
|
* `to_proc`
|
112
|
+
* `to_s`
|
113
|
+
* `inspect`
|
111
114
|
* `filter` (alias: select)
|
112
115
|
* `filter!` (alias: select!)
|
113
116
|
* `each_value`
|
@@ -115,5 +118,7 @@ Implemented methods:
|
|
115
118
|
* `search_before` (GLib version >= 2.68) - Select keys <= first arg, ret new Btree
|
116
119
|
* `search_after` (GLib version >= 2.68) - Select keys >= first arg, ret new Btree
|
117
120
|
* `empty?`
|
121
|
+
* `reverse_each`
|
122
|
+
* `delete_if`
|
118
123
|
|
119
124
|
You can mix in the `Enumerable` module if additional methods are needed.
|
@@ -38,6 +38,7 @@ add_library(iterators OBJECT iterators.c)
|
|
38
38
|
add_library(conversion OBJECT conversion.c)
|
39
39
|
add_library(search OBJECT search.c)
|
40
40
|
add_library(glib_module OBJECT glib_module.c)
|
41
|
+
add_library(utils OBJECT utils.c)
|
41
42
|
|
42
43
|
|
43
44
|
set(LIB_OBJECTS)
|
@@ -53,6 +54,9 @@ list(APPEND LIB_OBJECTS
|
|
53
54
|
|
54
55
|
if(HAS_GTREE_NODE)
|
55
56
|
list(APPEND LIB_OBJECTS $<TARGET_OBJECTS:additional_iterators>)
|
57
|
+
list(APPEND LIB_OBJECTS $<TARGET_OBJECTS:compare_trees>)
|
58
|
+
else()
|
59
|
+
list(APPEND LIB_OBJECTS $<TARGET_OBJECTS:utils>)
|
56
60
|
endif()
|
57
61
|
|
58
62
|
add_library(native_btree_interface
|
@@ -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
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#include <compare_trees.h>
|
2
|
+
|
3
|
+
static inline gboolean
|
4
|
+
rbtree_compare_trees_nodes(GTreeNode *a, GTreeNode *b)
|
5
|
+
{
|
6
|
+
gboolean result = TRUE;
|
7
|
+
|
8
|
+
VALUE key_a = (VALUE) g_tree_node_key(a);
|
9
|
+
VALUE val_a = (VALUE) g_tree_node_value(a);
|
10
|
+
VALUE key_b = (VALUE) g_tree_node_key(b);
|
11
|
+
VALUE val_b = (VALUE) g_tree_node_value(b);
|
12
|
+
|
13
|
+
VALUE key_result = rb_funcall(key_a, rb_intern("=="), 1, key_b);
|
14
|
+
|
15
|
+
if (!RTEST(key_result)) {
|
16
|
+
return FALSE;
|
17
|
+
}
|
18
|
+
|
19
|
+
VALUE val_result = rb_funcall(val_a, rb_intern("=="), 1, val_b);
|
20
|
+
|
21
|
+
if (!RTEST(val_result)) {
|
22
|
+
return FALSE;
|
23
|
+
}
|
24
|
+
|
25
|
+
return result;
|
26
|
+
}
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Compare two trees
|
30
|
+
*
|
31
|
+
* This function assumes that the number of nodes is same (already checked)
|
32
|
+
*/
|
33
|
+
gboolean
|
34
|
+
rbtree_compare_trees(const RBTree *a, const RBTree *b)
|
35
|
+
{
|
36
|
+
|
37
|
+
GTreeNode *a_node = g_tree_node_first(a->gtree);
|
38
|
+
GTreeNode *b_node = g_tree_node_first(b->gtree);
|
39
|
+
|
40
|
+
gboolean result = FALSE;
|
41
|
+
|
42
|
+
while (a_node && b_node) {
|
43
|
+
result = rbtree_compare_trees_nodes(a_node, b_node);
|
44
|
+
|
45
|
+
if (!result) {
|
46
|
+
break;
|
47
|
+
}
|
48
|
+
|
49
|
+
a_node = g_tree_node_next(a_node);
|
50
|
+
b_node = g_tree_node_next(b_node);
|
51
|
+
}
|
52
|
+
|
53
|
+
return result;
|
54
|
+
}
|
@@ -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
|
-
}
|
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_
|
@@ -83,4 +83,19 @@ rbtree_keys(VALUE self);
|
|
83
83
|
VALUE
|
84
84
|
rbtree_values(VALUE self);
|
85
85
|
|
86
|
+
VALUE
|
87
|
+
rbtree_equal(VALUE self, VALUE btree);
|
88
|
+
|
89
|
+
VALUE
|
90
|
+
rbtree_reverse_each(VALUE self);
|
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
|
+
|
86
101
|
#endif // _NATIVE_BTREE_
|
data/ext/native_btree/instance.c
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
#include <common.h>
|
2
2
|
|
3
|
+
#ifdef HAS_GTREE_NODE
|
4
|
+
#include <compare_trees.h>
|
5
|
+
#else
|
6
|
+
#include <utils.h>
|
7
|
+
#include <iterators.h>
|
8
|
+
#endif
|
3
9
|
|
4
10
|
#ifndef HAS_GTREE_REMOVE_ALL
|
5
11
|
|
@@ -15,6 +21,96 @@ rbtree_remove_node(gpointer key, gpointer val, gpointer data) {
|
|
15
21
|
#endif
|
16
22
|
|
17
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
|
+
|
18
114
|
VALUE
|
19
115
|
rbtree_set(VALUE self, VALUE key, VALUE value)
|
20
116
|
{
|
@@ -63,9 +159,7 @@ rbtree_delete(VALUE self, VALUE key)
|
|
63
159
|
}
|
64
160
|
else {
|
65
161
|
if (rb_block_given_p()) {
|
66
|
-
|
67
|
-
|
68
|
-
return rb_funcall(block, rb_intern("call"), 1, key);
|
162
|
+
return rb_yield(key);
|
69
163
|
}
|
70
164
|
|
71
165
|
return Qnil;
|
@@ -136,3 +230,104 @@ rbtree_is_empty(VALUE self)
|
|
136
230
|
|
137
231
|
return size > 0 ? Qfalse : Qtrue;
|
138
232
|
}
|
233
|
+
|
234
|
+
|
235
|
+
VALUE
|
236
|
+
rbtree_equal(VALUE self, VALUE second)
|
237
|
+
{
|
238
|
+
EXTRACT_RBTREE_SELF(rbtree);
|
239
|
+
EXTRACT_RBTREE(second, rbtree2);
|
240
|
+
|
241
|
+
gint self_size = g_tree_nnodes(rbtree->gtree);
|
242
|
+
gint second_size = g_tree_nnodes(rbtree2->gtree);
|
243
|
+
|
244
|
+
VALUE result = Qfalse;
|
245
|
+
|
246
|
+
if (self_size != second_size) {
|
247
|
+
goto ret;
|
248
|
+
}
|
249
|
+
|
250
|
+
if (self_size == 0) {
|
251
|
+
result = Qtrue;
|
252
|
+
goto ret;
|
253
|
+
}
|
254
|
+
|
255
|
+
#ifdef HAS_GTREE_NODE
|
256
|
+
if (rbtree_compare_trees(rbtree, rbtree2)) {
|
257
|
+
result = Qtrue;
|
258
|
+
}
|
259
|
+
#else
|
260
|
+
if (legacy_rbtree_compare(rbtree, rbtree2)) {
|
261
|
+
result = Qtrue;
|
262
|
+
}
|
263
|
+
#endif
|
264
|
+
|
265
|
+
ret:
|
266
|
+
return result;
|
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,5 +1,9 @@
|
|
1
1
|
#include <common.h>
|
2
|
+
#include <iterators.h>
|
2
3
|
|
4
|
+
#ifndef HAS_GTREE_NODE
|
5
|
+
#include <utils.h>
|
6
|
+
#endif
|
3
7
|
|
4
8
|
static gboolean
|
5
9
|
foraech_callbac(gpointer a, gpointer b, gpointer data)
|
@@ -38,14 +42,22 @@ foraech_value_callbac(gpointer a, gpointer b, gpointer data)
|
|
38
42
|
}
|
39
43
|
|
40
44
|
|
45
|
+
static VALUE
|
46
|
+
rbtree_enum_length(VALUE rbtree, VALUE args, VALUE eobj)
|
47
|
+
{
|
48
|
+
return rbtree_size(rbtree);
|
49
|
+
}
|
50
|
+
|
51
|
+
|
41
52
|
VALUE
|
42
53
|
rbtree_each(VALUE self)
|
43
54
|
{
|
44
|
-
|
45
|
-
VALUE block = rb_block_proc();
|
55
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, rbtree_enum_length);
|
46
56
|
|
47
57
|
EXTRACT_RBTREE_SELF(rbtree);
|
48
58
|
|
59
|
+
VALUE block = rb_block_proc();
|
60
|
+
|
49
61
|
g_tree_foreach(rbtree->gtree, foraech_callbac, (gpointer) block);
|
50
62
|
|
51
63
|
return self;
|
@@ -55,11 +67,12 @@ rbtree_each(VALUE self)
|
|
55
67
|
VALUE
|
56
68
|
rbtree_each_key(VALUE self)
|
57
69
|
{
|
58
|
-
|
59
|
-
VALUE block = rb_block_proc();
|
70
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, rbtree_enum_length);
|
60
71
|
|
61
72
|
EXTRACT_RBTREE_SELF(rbtree);
|
62
73
|
|
74
|
+
VALUE block = rb_block_proc();
|
75
|
+
|
63
76
|
g_tree_foreach(rbtree->gtree, foraech_key_callbac, (gpointer) block);
|
64
77
|
|
65
78
|
return self;
|
@@ -69,12 +82,100 @@ rbtree_each_key(VALUE self)
|
|
69
82
|
VALUE
|
70
83
|
rbtree_each_value(VALUE self)
|
71
84
|
{
|
72
|
-
|
73
|
-
VALUE block = rb_block_proc();
|
85
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, rbtree_enum_length);
|
74
86
|
|
75
87
|
EXTRACT_RBTREE_SELF(rbtree);
|
76
88
|
|
89
|
+
VALUE block = rb_block_proc();
|
90
|
+
|
77
91
|
g_tree_foreach(rbtree->gtree, foraech_value_callbac, (gpointer) block);
|
78
92
|
|
79
93
|
return self;
|
80
94
|
}
|
95
|
+
|
96
|
+
|
97
|
+
VALUE
|
98
|
+
rbtree_reverse_each(VALUE self)
|
99
|
+
{
|
100
|
+
EXTRACT_RBTREE_SELF(rbtree);
|
101
|
+
|
102
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, rbtree_enum_length);
|
103
|
+
|
104
|
+
#ifdef HAS_GTREE_NODE
|
105
|
+
GTreeNode *current = g_tree_node_last(rbtree->gtree);
|
106
|
+
|
107
|
+
VALUE key, val;
|
108
|
+
while (current) {
|
109
|
+
key = (VALUE) g_tree_node_key(current);
|
110
|
+
val = (VALUE) g_tree_node_value(current);
|
111
|
+
|
112
|
+
rb_yield_values(2, val, key);
|
113
|
+
|
114
|
+
current = g_tree_node_previous(current);
|
115
|
+
}
|
116
|
+
#else
|
117
|
+
GPtrArray *buff = rbtree_to_ptr_array(rbtree);
|
118
|
+
|
119
|
+
VALUE key, val;
|
120
|
+
for (glong i = buff->len - 1; i > 0; i--) {
|
121
|
+
val = (VALUE) g_ptr_array_index(buff, i);
|
122
|
+
key = (VALUE) g_ptr_array_index(buff, --i);
|
123
|
+
|
124
|
+
rb_yield_values(2, val, key);
|
125
|
+
}
|
126
|
+
|
127
|
+
g_ptr_array_free(buff, TRUE);
|
128
|
+
#endif
|
129
|
+
|
130
|
+
return self;
|
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
|
+
}
|
@@ -55,6 +55,15 @@ Init_native_btree()
|
|
55
55
|
rb_define_method(native_btree_class, "filter!", rbtree_filter_bang, 0);
|
56
56
|
rb_define_alias(native_btree_class, "select!", "filter!");
|
57
57
|
rb_define_method(native_btree_class, "empty?", rbtree_is_empty, 0);
|
58
|
+
rb_define_method(native_btree_class, "==", rbtree_equal, 1);
|
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");
|
58
67
|
|
59
68
|
#ifdef HAS_GTREE_NODE
|
60
69
|
rb_define_method(native_btree_class, "select_before", rbtree_select_before, 1);
|
data/ext/native_btree/search.c
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
static gboolean
|
5
5
|
filter_callback(gpointer a, gpointer b, gpointer data)
|
6
6
|
{
|
7
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
81
|
+
RBTreeSearchContext data = {
|
80
82
|
block,
|
81
83
|
NULL,
|
84
|
+
0,
|
85
|
+
0,
|
82
86
|
(gconstpointer) to_remove
|
83
87
|
};
|
84
88
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#include <utils.h>
|
2
|
+
|
3
|
+
|
4
|
+
static gint
|
5
|
+
to_ptr_array_cb(gpointer a, gpointer b, gpointer data)
|
6
|
+
{
|
7
|
+
GPtrArray *buff = (GPtrArray *) data;
|
8
|
+
|
9
|
+
g_ptr_array_add(buff, a);
|
10
|
+
g_ptr_array_add(buff, b);
|
11
|
+
|
12
|
+
return FALSE;
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
GPtrArray*
|
17
|
+
rbtree_to_ptr_array(const RBTree *rbtree)
|
18
|
+
{
|
19
|
+
gint tree_size = g_tree_nnodes(rbtree->gtree);
|
20
|
+
|
21
|
+
GPtrArray *buff = g_ptr_array_sized_new(tree_size * 2);
|
22
|
+
|
23
|
+
g_tree_foreach(rbtree->gtree, to_ptr_array_cb, (gpointer) buff);
|
24
|
+
|
25
|
+
return buff;
|
26
|
+
}
|
Binary file
|
data/lib/native_btree/version.rb
CHANGED
data/spec/debug.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
# rubocop:disable all
|
2
2
|
|
3
3
|
require_relative "../lib/native_btree/native_btree"
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
NativeBtree::Btree.include(Enumerable)
|
4
7
|
|
5
8
|
tree = NativeBtree::Btree.new() {|a, b| a - b }
|
9
|
+
tree2 = NativeBtree::Btree.new() {|a, b| a - b }
|
6
10
|
|
7
11
|
GC.start
|
8
12
|
|
@@ -17,8 +21,6 @@ GC.start
|
|
17
21
|
block = ->(key) { "#{key} is not found" }
|
18
22
|
puts tree.delete(77, &block)
|
19
23
|
|
20
|
-
tree2 = tree.filter!() { true }
|
21
|
-
|
22
24
|
puts tree.to_h
|
23
25
|
|
24
26
|
pr = tree.to_proc
|
@@ -27,15 +29,12 @@ puts pr
|
|
27
29
|
|
28
30
|
|
29
31
|
tree.clear
|
30
|
-
|
31
|
-
tree[
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
tree
|
36
|
-
tree[7] = 77
|
37
|
-
|
38
|
-
puts tree.select_after(4).to_h
|
32
|
+
(1..1000000).each do |i|
|
33
|
+
tree[i] = i+2
|
34
|
+
tree2[i] = i+2
|
35
|
+
end
|
36
|
+
|
37
|
+
puts tree == tree2
|
39
38
|
|
40
39
|
GC.start
|
41
40
|
|
@@ -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
|
@@ -186,5 +186,134 @@ RSpec.describe NativeBtree do
|
|
186
186
|
expect(tree.empty?).to be true
|
187
187
|
end
|
188
188
|
end
|
189
|
+
|
190
|
+
describe '#== method' do
|
191
|
+
let(:tree2) do
|
192
|
+
described_class.new do |a, b|
|
193
|
+
a - b
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'respond to' do
|
198
|
+
expect(tree).to respond_to(:==)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'return true if eql' do
|
202
|
+
tree[1] = 11
|
203
|
+
tree[2] = 22
|
204
|
+
tree[7] = 77
|
205
|
+
|
206
|
+
tree2[7] = 77
|
207
|
+
tree2[2] = 22
|
208
|
+
tree2[1] = 11
|
209
|
+
|
210
|
+
expect(tree).to eq tree2
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'return false if not eql' do
|
214
|
+
tree[1] = 11
|
215
|
+
tree[2] = 22
|
216
|
+
tree[7] = 77
|
217
|
+
tree[8] = 88
|
218
|
+
|
219
|
+
tree2[7] = 77
|
220
|
+
tree2[2] = 22
|
221
|
+
tree2[1] = 11
|
222
|
+
|
223
|
+
expect(tree).not_to eq tree2
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'return true if are empty trees' do
|
227
|
+
expect(tree).to eq tree2
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'return false if one key is not eq' do
|
231
|
+
tree[5] = 11
|
232
|
+
tree[2] = 22
|
233
|
+
tree[7] = 77
|
234
|
+
|
235
|
+
tree2[7] = 77
|
236
|
+
tree2[2] = 22
|
237
|
+
tree2[1] = 11
|
238
|
+
|
239
|
+
expect(tree).not_to eq tree2
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'return false if one value is not eq' do
|
243
|
+
tree[1] = 11
|
244
|
+
tree[2] = 22
|
245
|
+
tree[7] = 7
|
246
|
+
|
247
|
+
tree2[7] = 77
|
248
|
+
tree2[2] = 22
|
249
|
+
tree2[1] = 11
|
250
|
+
|
251
|
+
expect(tree).not_to eq tree2
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'return false if any tree is empty' do
|
255
|
+
tree[1] = 11
|
256
|
+
tree[2] = 22
|
257
|
+
|
258
|
+
expect(tree).not_to eq tree2
|
259
|
+
end
|
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
|
+
|
189
318
|
end
|
190
319
|
end
|
@@ -45,6 +45,28 @@ RSpec.describe NativeBtree do
|
|
45
45
|
|
46
46
|
expect(result).to eq(check)
|
47
47
|
end
|
48
|
+
|
49
|
+
it 'return Enumerator without block' do
|
50
|
+
expect(tree.each).to be_kind_of(Enumerator)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'enumerator return correct values' do
|
54
|
+
tree[16] = 16
|
55
|
+
tree[0] = 0
|
56
|
+
tree[5] = 5
|
57
|
+
tree[-4] = -4
|
58
|
+
tree[7] = 7
|
59
|
+
|
60
|
+
check = [[-4, -4], [0, 0], [5, 5], [7, 7], [16, 16]]
|
61
|
+
result = []
|
62
|
+
enum = tree.each
|
63
|
+
|
64
|
+
loop do
|
65
|
+
result.push enum.next
|
66
|
+
end
|
67
|
+
|
68
|
+
expect(result).to eq(check)
|
69
|
+
end
|
48
70
|
end
|
49
71
|
|
50
72
|
describe "#each_key method" do
|
@@ -86,5 +108,43 @@ RSpec.describe NativeBtree do
|
|
86
108
|
expect(result).to eq(check)
|
87
109
|
end
|
88
110
|
end
|
111
|
+
|
112
|
+
describe "#reverse_each method" do
|
113
|
+
it "respond to" do
|
114
|
+
expect(tree).to respond_to(:reverse_each)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'yield in to block value first' do
|
118
|
+
tree[2] = 22
|
119
|
+
|
120
|
+
value = nil
|
121
|
+
tree.reverse_each { |v| value = v }
|
122
|
+
|
123
|
+
expect(value).to be 22
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'yield in to block key second' do
|
127
|
+
tree[2] = 22
|
128
|
+
|
129
|
+
key = nil
|
130
|
+
tree.reverse_each { |_v, k| key = k }
|
131
|
+
|
132
|
+
expect(key).to be 2
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'yield ordered keys in reverse order' do
|
136
|
+
tree[16] = 16
|
137
|
+
tree[0] = 0
|
138
|
+
tree[5] = 5
|
139
|
+
tree[-4] = -4
|
140
|
+
tree[7] = 7
|
141
|
+
|
142
|
+
check = [16, 7, 5, 0, -4]
|
143
|
+
result = []
|
144
|
+
tree.reverse_each { |value| result << value }
|
145
|
+
|
146
|
+
expect(result).to eq(check)
|
147
|
+
end
|
148
|
+
end
|
89
149
|
end
|
90
150
|
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.
|
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-
|
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:
|
@@ -31,18 +31,22 @@ files:
|
|
31
31
|
- ext/native_btree/extconf_cmake.rb
|
32
32
|
- ext/native_btree/glib2_68/CMakeLists.txt
|
33
33
|
- ext/native_btree/glib2_68/additional_iterators.c
|
34
|
+
- ext/native_btree/glib2_68/compare_trees.c
|
34
35
|
- ext/native_btree/glib_module.c
|
35
36
|
- ext/native_btree/include/common.h
|
36
37
|
- ext/native_btree/include/comparator.h
|
38
|
+
- ext/native_btree/include/compare_trees.h
|
37
39
|
- ext/native_btree/include/glib_module.h
|
38
40
|
- ext/native_btree/include/iterators.h
|
39
41
|
- ext/native_btree/include/native_btree.h
|
40
42
|
- ext/native_btree/include/rbtree_type.h
|
43
|
+
- ext/native_btree/include/utils.h
|
41
44
|
- ext/native_btree/instance.c
|
42
45
|
- ext/native_btree/iterators.c
|
43
46
|
- ext/native_btree/native_btree.c
|
44
47
|
- ext/native_btree/rbtree_type.c
|
45
48
|
- ext/native_btree/search.c
|
49
|
+
- ext/native_btree/utils.c
|
46
50
|
- lib/native_btree.rb
|
47
51
|
- lib/native_btree/native_btree.bundle
|
48
52
|
- lib/native_btree/version.rb
|