native_btree 0.5.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +25 -1
- data/CMakeLists.txt +2 -2
- data/README.md +5 -28
- data/Rakefile +1 -1
- data/ext/native_btree/constructor.c +8 -0
- data/ext/native_btree/conversion.c +34 -3
- data/ext/native_btree/include/iterators.h +8 -1
- data/ext/native_btree/include/native_btree.h +9 -0
- data/ext/native_btree/instance.c +229 -54
- data/ext/native_btree/iterators.c +78 -4
- data/ext/native_btree/native_btree.c +15 -12
- data/ext/native_btree/search.c +22 -4
- data/lib/native_btree/btree.rb +6 -0
- data/lib/native_btree/native_btree.bundle +0 -0
- data/lib/native_btree/version.rb +2 -1
- data/lib/native_btree.rb +3 -1
- data/spec/debug.rb +1 -0
- data/spec/native_btree_conversion_spec.rb +31 -0
- data/spec/native_btree_instance_spec.rb +57 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48b0e894826a65be636d9e13813c6d084c69a306d0778caf3fc709511dc5d2f5
|
|
4
|
+
data.tar.gz: 18f2f200813df0762181ebb4e7d3cc32c1cd8ae337ab9a35547d9265fa91eaeb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c574719cc0366f86f8459e5e17c59739dab7886ae2cfe56450ed8696906fe4c13be6e90265756a195d04548a627018540c8d119e143d19e0b5cab378c166448
|
|
7
|
+
data.tar.gz: 8239197687c68a713da92c7d108b41acfe83c30dcbee888e7363e0842b2f6bdc7af30e584e96a5438c08bb5bd306399f986cb31d0dad86d2cf17c9ee65820638
|
data/CHANGELOG.md
CHANGED
|
@@ -7,10 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
*
|
|
10
|
+
* #compact
|
|
11
|
+
* #compact!
|
|
12
|
+
* #>
|
|
13
|
+
* #>=
|
|
14
|
+
* #<
|
|
15
|
+
* #<=
|
|
16
|
+
|
|
17
|
+
## [0.6.1] - 2023-05-05
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
* api docs
|
|
22
|
+
|
|
23
|
+
## [0.6.0] - 2022-10-28
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
* inspect
|
|
28
|
+
* to_s
|
|
29
|
+
* delete_if
|
|
11
30
|
* first, min
|
|
12
31
|
* last, max
|
|
13
32
|
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
* Refactoring
|
|
36
|
+
* Performance improvements for #==
|
|
37
|
+
|
|
14
38
|
## [0.5.0] - 2022-10-04
|
|
15
39
|
|
|
16
40
|
### 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
|
+
VERSION 0.6.1)
|
|
6
6
|
|
|
7
7
|
include(CheckSymbolExists)
|
|
8
8
|
include(CheckCCompilerFlag)
|
|
@@ -22,7 +22,7 @@ if(HAVE_CC_MARCH_NATIVE)
|
|
|
22
22
|
string(APPEND CMAKE_C_FLAGS " -march=native")
|
|
23
23
|
endif()
|
|
24
24
|
|
|
25
|
-
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb3 -Wall -Wextra -Wno-unused-parameter")
|
|
25
|
+
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb3 -Wall -Wextra -Wno-unused-parameter --coverage")
|
|
26
26
|
set(CMAKE_C_FLAGS_RELEASE "-O3 -fomit-frame-pointer")
|
|
27
27
|
|
|
28
28
|
# Force -fPIC
|
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# GLib Balanced binary tree (GTree) bindings for Ruby
|
|
2
2
|
|
|
3
3
|
[](https://github.com/unixs/ruby-native-btree/actions/workflows/main.yml)
|
|
4
|
+
[](https://codecov.io/gh/unixs/ruby-native-btree)
|
|
4
5
|
[](https://badge.fury.io/rb/native_btree)
|
|
5
6
|
[](https://www.gnu.org/licenses/lgpl-3.0)
|
|
6
7
|
|
|
@@ -87,35 +88,11 @@ tree.to_a
|
|
|
87
88
|
#]
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
## API
|
|
91
|
+
## API
|
|
91
92
|
|
|
92
|
-
You must provide your own comparator for keys in `new` class method block.
|
|
93
|
+
* You must provide your own comparator for keys in `new` class method block.
|
|
94
|
+
* You can mix in the `Enumerable` module if additional methods are needed.
|
|
93
95
|
|
|
94
96
|
### API methods
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Implemented methods:
|
|
99
|
-
|
|
100
|
-
* `[]= (alias: set)`
|
|
101
|
-
* `[] (alias: get)`
|
|
102
|
-
* `==`
|
|
103
|
-
* `delete`
|
|
104
|
-
* `size`
|
|
105
|
-
* `height`
|
|
106
|
-
* `each` (NB! block is required) (NB! block is required)
|
|
107
|
-
* `include?`
|
|
108
|
-
* `clear`
|
|
109
|
-
* `to_h`
|
|
110
|
-
* `to_a`
|
|
111
|
-
* `to_proc`
|
|
112
|
-
* `filter` (alias: select)
|
|
113
|
-
* `filter!` (alias: select!)
|
|
114
|
-
* `each_value`
|
|
115
|
-
* `each_key`
|
|
116
|
-
* `search_before` (GLib version >= 2.68) - Select keys <= first arg, ret new Btree
|
|
117
|
-
* `search_after` (GLib version >= 2.68) - Select keys >= first arg, ret new Btree
|
|
118
|
-
* `empty?`
|
|
119
|
-
* `reverse_each`
|
|
120
|
-
|
|
121
|
-
You can mix in the `Enumerable` module if additional methods are needed.
|
|
98
|
+
[YARD documentation](https://rubydoc.info/gems/native_btree)
|
data/Rakefile
CHANGED
|
@@ -27,6 +27,14 @@ init_rbtree(RBTree *rbtree, gushort flags)
|
|
|
27
27
|
rbtree->flags = flags;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Constructor
|
|
32
|
+
*
|
|
33
|
+
* Accepts block as "comparator" function.
|
|
34
|
+
* This function will recive two keys for comparison.
|
|
35
|
+
*
|
|
36
|
+
* @return [Btree] new instance
|
|
37
|
+
*/
|
|
30
38
|
VALUE
|
|
31
39
|
rbtree_initialize(int argc, VALUE* argv, VALUE self)
|
|
32
40
|
{
|
|
@@ -26,7 +26,11 @@ rbtree_to_a_callback(gpointer key, gpointer value, gpointer data)
|
|
|
26
26
|
return FALSE;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Converts tree to Hash
|
|
31
|
+
*
|
|
32
|
+
* @return [Hash] result
|
|
33
|
+
*/
|
|
30
34
|
VALUE
|
|
31
35
|
rbtree_to_h(VALUE self)
|
|
32
36
|
{
|
|
@@ -39,7 +43,13 @@ rbtree_to_h(VALUE self)
|
|
|
39
43
|
return hash;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Converts tree to array
|
|
48
|
+
*
|
|
49
|
+
* Coverts tree to array of arrays with key and value
|
|
50
|
+
*
|
|
51
|
+
* @return [Array] result
|
|
52
|
+
*/
|
|
43
53
|
VALUE
|
|
44
54
|
rbtree_to_a(VALUE self)
|
|
45
55
|
{
|
|
@@ -70,9 +80,30 @@ to_proc_proc(RB_BLOCK_CALL_FUNC_ARGLIST(key, callback_arg))
|
|
|
70
80
|
return value;
|
|
71
81
|
}
|
|
72
82
|
|
|
73
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Returns a Proc object that maps a key to its value
|
|
85
|
+
*
|
|
86
|
+
* @return [Proc] block
|
|
87
|
+
*/
|
|
74
88
|
VALUE
|
|
75
89
|
rbtree_to_proc(VALUE self)
|
|
76
90
|
{
|
|
77
91
|
return rb_proc_new(to_proc_proc, self);
|
|
78
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Converts tree to string.
|
|
96
|
+
*
|
|
97
|
+
* Under hood will convert tree to Hash.
|
|
98
|
+
*
|
|
99
|
+
* @return [String] result
|
|
100
|
+
*/
|
|
101
|
+
VALUE
|
|
102
|
+
rbtree_to_s(VALUE self)
|
|
103
|
+
{
|
|
104
|
+
VALUE h = rbtree_to_h(self);
|
|
105
|
+
|
|
106
|
+
VALUE str = rb_sprintf("#<NativeBtree::Btree:%"PRIsVALUE">", h);
|
|
107
|
+
|
|
108
|
+
return str;
|
|
109
|
+
}
|
|
@@ -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_
|
data/ext/native_btree/instance.c
CHANGED
|
@@ -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,104 @@ 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
|
+
/**
|
|
114
|
+
* Adds key/value pair in to tree.
|
|
115
|
+
*
|
|
116
|
+
* Key/value will be replaced if key already exists.
|
|
117
|
+
*
|
|
118
|
+
* @param key [Object]
|
|
119
|
+
* @param value [Object]
|
|
120
|
+
* @return [Btree] self
|
|
121
|
+
*/
|
|
23
122
|
VALUE
|
|
24
123
|
rbtree_set(VALUE self, VALUE key, VALUE value)
|
|
25
124
|
{
|
|
@@ -30,7 +129,14 @@ rbtree_set(VALUE self, VALUE key, VALUE value)
|
|
|
30
129
|
return self;
|
|
31
130
|
}
|
|
32
131
|
|
|
33
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Gets value by key from tree.
|
|
134
|
+
*
|
|
135
|
+
* * Returns +nil+ if key does not exist.
|
|
136
|
+
*
|
|
137
|
+
* @param key [Object]
|
|
138
|
+
* @return [Object] result
|
|
139
|
+
*/
|
|
34
140
|
VALUE
|
|
35
141
|
rbtree_get(VALUE self, VALUE key)
|
|
36
142
|
{
|
|
@@ -47,7 +153,16 @@ rbtree_get(VALUE self, VALUE key)
|
|
|
47
153
|
return result;
|
|
48
154
|
}
|
|
49
155
|
|
|
50
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Deletes key/value pair from tree.
|
|
158
|
+
*
|
|
159
|
+
* * Returns value if key exists
|
|
160
|
+
* * Returns +nil+ if key does not exists
|
|
161
|
+
* * Returns result of block if block was given
|
|
162
|
+
*
|
|
163
|
+
* @param key [Object] Key
|
|
164
|
+
* @return [Object] result
|
|
165
|
+
*/
|
|
51
166
|
VALUE
|
|
52
167
|
rbtree_delete(VALUE self, VALUE key)
|
|
53
168
|
{
|
|
@@ -75,7 +190,11 @@ rbtree_delete(VALUE self, VALUE key)
|
|
|
75
190
|
}
|
|
76
191
|
}
|
|
77
192
|
|
|
78
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Returns tree height
|
|
195
|
+
*
|
|
196
|
+
* @return [Integer] maximum nodes in path from root to leaf
|
|
197
|
+
*/
|
|
79
198
|
VALUE
|
|
80
199
|
rbtree_height(VALUE self)
|
|
81
200
|
{
|
|
@@ -87,7 +206,11 @@ rbtree_height(VALUE self)
|
|
|
87
206
|
return result;
|
|
88
207
|
}
|
|
89
208
|
|
|
90
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Returns number of nodes
|
|
211
|
+
*
|
|
212
|
+
* @return [Integer] number of nodes
|
|
213
|
+
*/
|
|
91
214
|
VALUE
|
|
92
215
|
rbtree_size(VALUE self)
|
|
93
216
|
{
|
|
@@ -99,7 +222,11 @@ rbtree_size(VALUE self)
|
|
|
99
222
|
return result;
|
|
100
223
|
}
|
|
101
224
|
|
|
102
|
-
|
|
225
|
+
/**
|
|
226
|
+
* Remove all nodes from tree.
|
|
227
|
+
*
|
|
228
|
+
* @return [Btree] self
|
|
229
|
+
*/
|
|
103
230
|
VALUE
|
|
104
231
|
rbtree_clear(VALUE self)
|
|
105
232
|
{
|
|
@@ -115,6 +242,12 @@ rbtree_clear(VALUE self)
|
|
|
115
242
|
}
|
|
116
243
|
|
|
117
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Checks that the given key is in the tree.
|
|
247
|
+
*
|
|
248
|
+
* @param key [Object]
|
|
249
|
+
* @return [Boolean] result
|
|
250
|
+
*/
|
|
118
251
|
VALUE
|
|
119
252
|
rbtree_is_include(VALUE self, VALUE key)
|
|
120
253
|
{
|
|
@@ -129,7 +262,11 @@ rbtree_is_include(VALUE self, VALUE key)
|
|
|
129
262
|
return Qtrue;
|
|
130
263
|
}
|
|
131
264
|
|
|
132
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Checks that self tree is empty.
|
|
267
|
+
*
|
|
268
|
+
* @return [Boolean] result
|
|
269
|
+
*/
|
|
133
270
|
VALUE
|
|
134
271
|
rbtree_is_empty(VALUE self)
|
|
135
272
|
{
|
|
@@ -140,54 +277,18 @@ rbtree_is_empty(VALUE self)
|
|
|
140
277
|
return size > 0 ? Qfalse : Qtrue;
|
|
141
278
|
}
|
|
142
279
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
280
|
+
/**
|
|
281
|
+
* Checks if two trees are equal.
|
|
282
|
+
*
|
|
283
|
+
* Compares with +==+ method all keys and values from trees by order.
|
|
284
|
+
*
|
|
285
|
+
* * Returns +false+ if number of keys are not equal.
|
|
286
|
+
* * Returns +false+ if one keys or one values pair are not equal.
|
|
287
|
+
* * Returns +true+ if all keys and values are equal.
|
|
288
|
+
*
|
|
289
|
+
* @param second [Btree]
|
|
290
|
+
* @return [Boolean] result
|
|
291
|
+
*/
|
|
191
292
|
VALUE
|
|
192
293
|
rbtree_equal(VALUE self, VALUE second)
|
|
193
294
|
{
|
|
@@ -221,3 +322,77 @@ rbtree_equal(VALUE self, VALUE second)
|
|
|
221
322
|
ret:
|
|
222
323
|
return result;
|
|
223
324
|
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Returns value from smallest key
|
|
328
|
+
*
|
|
329
|
+
* @return [Object] result
|
|
330
|
+
*/
|
|
331
|
+
VALUE
|
|
332
|
+
rbtree_first(VALUE self)
|
|
333
|
+
{
|
|
334
|
+
EXTRACT_RBTREE_SELF(rbtree);
|
|
335
|
+
|
|
336
|
+
#ifdef HAS_GTREE_NODE
|
|
337
|
+
GTreeNode *node = g_tree_node_first(rbtree->gtree);
|
|
338
|
+
|
|
339
|
+
if (!node) {
|
|
340
|
+
return Qnil;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return (VALUE) g_tree_node_value(node);
|
|
344
|
+
#else
|
|
345
|
+
RBTreeSearchContext context = {
|
|
346
|
+
Qnil,
|
|
347
|
+
NULL,
|
|
348
|
+
1,
|
|
349
|
+
0,
|
|
350
|
+
NULL
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
g_tree_foreach(rbtree->gtree, rbtree_first_cb, &context);
|
|
354
|
+
|
|
355
|
+
if (context.counter) {
|
|
356
|
+
return Qnil;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return (VALUE) context.something;
|
|
360
|
+
#endif
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Returns value from largest key
|
|
365
|
+
*
|
|
366
|
+
* @return [Object] result
|
|
367
|
+
*/
|
|
368
|
+
VALUE
|
|
369
|
+
rbtree_last(VALUE self)
|
|
370
|
+
{
|
|
371
|
+
EXTRACT_RBTREE_SELF(rbtree);
|
|
372
|
+
|
|
373
|
+
#ifdef HAS_GTREE_NODE
|
|
374
|
+
GTreeNode *node = g_tree_node_last(rbtree->gtree);
|
|
375
|
+
|
|
376
|
+
if (!node) {
|
|
377
|
+
return Qnil;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return (VALUE) g_tree_node_value(node);
|
|
381
|
+
#else
|
|
382
|
+
RBTreeSearchContext context = {
|
|
383
|
+
Qnil,
|
|
384
|
+
NULL,
|
|
385
|
+
0,
|
|
386
|
+
0,
|
|
387
|
+
NULL
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
g_tree_foreach(rbtree->gtree, rbtree_last_cb, &context);
|
|
391
|
+
|
|
392
|
+
if (!context.counter) {
|
|
393
|
+
return Qnil;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return (VALUE) context.something;
|
|
397
|
+
#endif
|
|
398
|
+
}
|
|
@@ -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>
|
|
@@ -47,7 +48,11 @@ rbtree_enum_length(VALUE rbtree, VALUE args, VALUE eobj)
|
|
|
47
48
|
return rbtree_size(rbtree);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Execute block for each key/value pairs
|
|
53
|
+
*
|
|
54
|
+
* @return [Btree] self
|
|
55
|
+
*/
|
|
51
56
|
VALUE
|
|
52
57
|
rbtree_each(VALUE self)
|
|
53
58
|
{
|
|
@@ -62,7 +67,11 @@ rbtree_each(VALUE self)
|
|
|
62
67
|
return self;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Execute block for each key
|
|
72
|
+
*
|
|
73
|
+
* @return [Btree] self
|
|
74
|
+
*/
|
|
66
75
|
VALUE
|
|
67
76
|
rbtree_each_key(VALUE self)
|
|
68
77
|
{
|
|
@@ -77,7 +86,11 @@ rbtree_each_key(VALUE self)
|
|
|
77
86
|
return self;
|
|
78
87
|
}
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Execute block for each value
|
|
91
|
+
*
|
|
92
|
+
* @return [Btree] self
|
|
93
|
+
*/
|
|
81
94
|
VALUE
|
|
82
95
|
rbtree_each_value(VALUE self)
|
|
83
96
|
{
|
|
@@ -92,7 +105,11 @@ rbtree_each_value(VALUE self)
|
|
|
92
105
|
return self;
|
|
93
106
|
}
|
|
94
107
|
|
|
95
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Execute block for each key/value pairs in reverse order
|
|
110
|
+
*
|
|
111
|
+
* @return [Btree] self
|
|
112
|
+
*/
|
|
96
113
|
VALUE
|
|
97
114
|
rbtree_reverse_each(VALUE self)
|
|
98
115
|
{
|
|
@@ -128,3 +145,60 @@ rbtree_reverse_each(VALUE self)
|
|
|
128
145
|
|
|
129
146
|
return self;
|
|
130
147
|
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
static gint
|
|
151
|
+
rbtree_delete_if_cb(gpointer k, gpointer v, gpointer data)
|
|
152
|
+
{
|
|
153
|
+
VALUE key = (VALUE) k;
|
|
154
|
+
VALUE value = (VALUE) v;
|
|
155
|
+
RBTreeSearchContext *context = (RBTreeSearchContext *) data;
|
|
156
|
+
VALUE block = (VALUE) context->block;
|
|
157
|
+
GPtrArray *result = (GPtrArray *) context->something;
|
|
158
|
+
|
|
159
|
+
VALUE to_delete = rb_funcall(block, rb_intern("call"), 2, key, value);
|
|
160
|
+
|
|
161
|
+
if (RTEST(to_delete)) {
|
|
162
|
+
g_ptr_array_add(result, (gpointer) key);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return FALSE;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Deletes key/value pair from tree by result of block.
|
|
170
|
+
*
|
|
171
|
+
* Will execute block for each key/value pairs
|
|
172
|
+
* and delete them if block returns +true+
|
|
173
|
+
*
|
|
174
|
+
* @return [Btree] self
|
|
175
|
+
*/
|
|
176
|
+
VALUE
|
|
177
|
+
rbtree_delete_if(VALUE self)
|
|
178
|
+
{
|
|
179
|
+
EXTRACT_RBTREE_SELF(rbtree);
|
|
180
|
+
|
|
181
|
+
GPtrArray *to_delete = g_ptr_array_new();
|
|
182
|
+
|
|
183
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, rbtree_enum_length);
|
|
184
|
+
|
|
185
|
+
VALUE block = rb_block_proc();
|
|
186
|
+
|
|
187
|
+
RBTreeSearchContext context = {
|
|
188
|
+
block,
|
|
189
|
+
NULL,
|
|
190
|
+
0,
|
|
191
|
+
0,
|
|
192
|
+
to_delete
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
g_tree_foreach(rbtree->gtree, rbtree_delete_if_cb, &context);
|
|
196
|
+
|
|
197
|
+
for (guint i = 0; i < to_delete->len; i++) {
|
|
198
|
+
g_tree_remove(rbtree->gtree, g_ptr_array_index(to_delete, i));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
g_ptr_array_free(to_delete, TRUE);
|
|
202
|
+
|
|
203
|
+
return self;
|
|
204
|
+
}
|
|
@@ -2,29 +2,25 @@
|
|
|
2
2
|
#include <rbtree_type.h>
|
|
3
3
|
#include <glib_module.h>
|
|
4
4
|
|
|
5
|
-
#define NATIVE_BTREE_MODULE "NativeBtree"
|
|
6
|
-
#define NATIVE_BTREE_CLASS "Btree"
|
|
7
|
-
#define NATIVE_BTREE_CONST_INT_COMPARATOR "INT_COMPARATOR"
|
|
8
|
-
|
|
9
|
-
|
|
10
5
|
VALUE native_btree_class;
|
|
11
6
|
VALUE native_btree_module;
|
|
12
7
|
|
|
13
8
|
void
|
|
14
9
|
Init_native_btree()
|
|
15
10
|
{
|
|
16
|
-
native_btree_module = rb_define_module(
|
|
17
|
-
native_btree_class = rb_define_class_under(
|
|
18
|
-
native_btree_module,
|
|
19
|
-
NATIVE_BTREE_CLASS,
|
|
20
|
-
rb_cObject
|
|
21
|
-
);
|
|
11
|
+
native_btree_module = rb_define_module("NativeBtree");
|
|
12
|
+
native_btree_class = rb_define_class_under(native_btree_module, "Btree", rb_cObject);
|
|
22
13
|
|
|
23
14
|
VALUE int_comparator = USHORT2NUM(RBTREE_FLAG_INT_COMPARATOR);
|
|
24
15
|
OBJ_FREEZE(int_comparator);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Represents native comparator for integer keys
|
|
19
|
+
* @note Can be replaced with specific class in future releases
|
|
20
|
+
*/
|
|
25
21
|
rb_define_const(
|
|
26
22
|
native_btree_class,
|
|
27
|
-
|
|
23
|
+
"INT_COMPARATOR",
|
|
28
24
|
int_comparator
|
|
29
25
|
);
|
|
30
26
|
|
|
@@ -57,6 +53,13 @@ Init_native_btree()
|
|
|
57
53
|
rb_define_method(native_btree_class, "empty?", rbtree_is_empty, 0);
|
|
58
54
|
rb_define_method(native_btree_class, "==", rbtree_equal, 1);
|
|
59
55
|
rb_define_method(native_btree_class, "reverse_each", rbtree_reverse_each, 0);
|
|
56
|
+
rb_define_method(native_btree_class, "first", rbtree_first, 0);
|
|
57
|
+
rb_define_alias(native_btree_class, "min", "first");
|
|
58
|
+
rb_define_method(native_btree_class, "last", rbtree_last, 0);
|
|
59
|
+
rb_define_alias(native_btree_class, "max", "last");
|
|
60
|
+
rb_define_method(native_btree_class, "delete_if", rbtree_delete_if, 0);
|
|
61
|
+
rb_define_method(native_btree_class, "to_s", rbtree_to_s, 0);
|
|
62
|
+
rb_define_alias(native_btree_class, "inspect", "to_s");
|
|
60
63
|
|
|
61
64
|
#ifdef HAS_GTREE_NODE
|
|
62
65
|
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(
|
|
@@ -43,6 +43,13 @@ filter_bang_callback(gpointer a, gpointer b, gpointer data)
|
|
|
43
43
|
return FALSE;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Filters btree by block call
|
|
48
|
+
*
|
|
49
|
+
* If block returns true, key/value will include in result tree
|
|
50
|
+
*
|
|
51
|
+
* @return [Btree] result
|
|
52
|
+
*/
|
|
46
53
|
VALUE
|
|
47
54
|
rbtree_filter(VALUE self)
|
|
48
55
|
{
|
|
@@ -55,9 +62,11 @@ rbtree_filter(VALUE self)
|
|
|
55
62
|
|
|
56
63
|
EXTRACT_RBTREE(new_tree, new_rbtree);
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
RBTreeSearchContext data = {
|
|
59
66
|
block,
|
|
60
67
|
new_rbtree,
|
|
68
|
+
0,
|
|
69
|
+
0,
|
|
61
70
|
NULL
|
|
62
71
|
};
|
|
63
72
|
|
|
@@ -66,6 +75,13 @@ rbtree_filter(VALUE self)
|
|
|
66
75
|
return new_tree;
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Filters btree by block call
|
|
80
|
+
*
|
|
81
|
+
* Same as #filter but returns changed self.
|
|
82
|
+
*
|
|
83
|
+
* @return [Btree] result
|
|
84
|
+
*/
|
|
69
85
|
VALUE
|
|
70
86
|
rbtree_filter_bang(VALUE self)
|
|
71
87
|
{
|
|
@@ -76,9 +92,11 @@ rbtree_filter_bang(VALUE self)
|
|
|
76
92
|
|
|
77
93
|
GPtrArray *to_remove = g_ptr_array_new();
|
|
78
94
|
|
|
79
|
-
|
|
95
|
+
RBTreeSearchContext data = {
|
|
80
96
|
block,
|
|
81
97
|
NULL,
|
|
98
|
+
0,
|
|
99
|
+
0,
|
|
82
100
|
(gconstpointer) to_remove
|
|
83
101
|
};
|
|
84
102
|
|
|
Binary file
|
data/lib/native_btree/version.rb
CHANGED
data/lib/native_btree.rb
CHANGED
data/spec/debug.rb
CHANGED
|
@@ -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.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Feodorov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-05-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Ruby bindings to GTree balanced binary tree from GLib library.
|
|
14
14
|
email:
|
|
@@ -48,6 +48,7 @@ files:
|
|
|
48
48
|
- ext/native_btree/search.c
|
|
49
49
|
- ext/native_btree/utils.c
|
|
50
50
|
- lib/native_btree.rb
|
|
51
|
+
- lib/native_btree/btree.rb
|
|
51
52
|
- lib/native_btree/native_btree.bundle
|
|
52
53
|
- lib/native_btree/version.rb
|
|
53
54
|
- native_btree.gemspec
|