native_btree 0.1.0.alpha2 → 0.2.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.
@@ -0,0 +1,22 @@
1
+ #ifndef _RBTREE_TYPE_
2
+ #define _RBTREE_TYPE_
3
+
4
+ #include <common.h>
5
+
6
+ #define NATIVE_TYPE_NAME "native_btree"
7
+
8
+ extern const rb_data_type_t rbtree_type;
9
+
10
+ VALUE
11
+ rbtree_alloc(VALUE self);
12
+
13
+ /**
14
+ * Internal native instance
15
+ */
16
+ typedef struct _RBTree
17
+ {
18
+ GTree *gtree;
19
+ VALUE comparator;
20
+ } RBTree;
21
+
22
+ #endif //_RBTREE_TYPE_
@@ -0,0 +1,126 @@
1
+ #include <instance.h>
2
+
3
+ #ifndef HAVE_GTREE_REMOVE_ALL
4
+
5
+ static gboolean
6
+ rbtree_remove_node(gpointer key, gpointer val, gpointer data) {
7
+ RBTree *rbtree = (RBTree *) data;
8
+
9
+ g_tree_remove(rbtree->gtree, key);
10
+
11
+ return FALSE;
12
+ }
13
+
14
+ #endif
15
+
16
+
17
+ VALUE
18
+ rbtree_set(VALUE self, VALUE key, VALUE value)
19
+ {
20
+ EXTRACT_RBTREE_SELF(rbtree);
21
+
22
+ g_tree_replace(rbtree->gtree, (gpointer) key, (gpointer) value);
23
+
24
+ return self;
25
+ }
26
+
27
+
28
+ VALUE
29
+ rbtree_get(VALUE self, VALUE key)
30
+ {
31
+ EXTRACT_RBTREE_SELF(rbtree);
32
+
33
+ gpointer found = g_tree_lookup(rbtree->gtree, (gpointer) key);
34
+
35
+ if (found == NULL) {
36
+ return Qnil;
37
+ }
38
+
39
+ VALUE result = (VALUE) found;
40
+
41
+ return result;
42
+ }
43
+
44
+
45
+ VALUE
46
+ rbtree_delete(VALUE self, VALUE key)
47
+ {
48
+ EXTRACT_RBTREE_SELF(rbtree);
49
+
50
+ VALUE found_key, found_value;
51
+ gboolean found = g_tree_lookup_extended(
52
+ rbtree->gtree,
53
+ (gconstpointer) key,
54
+ (gpointer *) &found_key,
55
+ (gpointer *) &found_value
56
+ );
57
+
58
+ if (found) {
59
+ g_tree_remove(rbtree->gtree, (gconstpointer) key);
60
+
61
+ return found_value;
62
+ }
63
+ else {
64
+ if (rb_block_given_p()) {
65
+ VALUE block = rb_block_proc();
66
+
67
+ return rb_funcall(block, rb_intern("call"), 1, key);
68
+ }
69
+
70
+ return Qnil;
71
+ }
72
+ }
73
+
74
+
75
+ VALUE
76
+ rbtree_height(VALUE self)
77
+ {
78
+ EXTRACT_RBTREE_SELF(rbtree);
79
+
80
+ gint size = g_tree_height(rbtree->gtree);
81
+ VALUE result = INT2NUM(size);
82
+
83
+ return result;
84
+ }
85
+
86
+
87
+ VALUE
88
+ rbtree_size(VALUE self)
89
+ {
90
+ EXTRACT_RBTREE_SELF(rbtree);
91
+
92
+ gint size = g_tree_nnodes(rbtree->gtree);
93
+ VALUE result = INT2NUM(size);
94
+
95
+ return result;
96
+ }
97
+
98
+
99
+ VALUE
100
+ rbtree_clear(VALUE self)
101
+ {
102
+ EXTRACT_RBTREE_SELF(rbtree);
103
+
104
+ #ifdef HAVE_GTREE_REMOVE_ALL
105
+ g_tree_remove_all(rbtree->gtree);
106
+ #else
107
+ g_tree_foreach(rbtree->gtree, rbtree_remove_node, (gpointer) rbtree);
108
+ #endif
109
+
110
+ return self;
111
+ }
112
+
113
+
114
+ VALUE
115
+ rbtree_is_include(VALUE self, VALUE key)
116
+ {
117
+ EXTRACT_RBTREE_SELF(rbtree);
118
+
119
+ gpointer exists = g_tree_lookup(rbtree->gtree, (gconstpointer) key);
120
+
121
+ if (exists == NULL) {
122
+ return Qfalse;
123
+ }
124
+
125
+ return Qtrue;
126
+ }
@@ -0,0 +1,26 @@
1
+ #include <iterators.h>
2
+
3
+ static gboolean
4
+ foraech_callbac(gpointer a, gpointer b, gpointer data)
5
+ {
6
+ VALUE key = (VALUE) a;
7
+ VALUE value = (VALUE) b;
8
+ VALUE block = (VALUE) data;
9
+
10
+ rb_funcall(block, rb_intern("call"), 2, value, key);
11
+
12
+ return FALSE;
13
+ }
14
+
15
+ VALUE
16
+ rbtree_each(VALUE self)
17
+ {
18
+ rb_need_block();
19
+ VALUE block = rb_block_proc();
20
+
21
+ EXTRACT_RBTREE_SELF(rbtree);
22
+
23
+ g_tree_foreach(rbtree->gtree, foraech_callbac, (gpointer) block);
24
+
25
+ return self;
26
+ }
@@ -1,27 +1,28 @@
1
- #include <ruby.h>
2
-
3
1
  #include <native_btree.h>
4
2
 
5
- VALUE btree_class;
6
- VALUE btree_module;
7
- VALUE btree_class_from;
8
-
9
- VALUE
10
- btree_from(VALUE klass);
11
-
12
- VALUE
13
- btree_from(VALUE klass)
14
- {
15
- VALUE result = INT2NUM(10);
3
+ VALUE rbtree_class;
4
+ VALUE rbtree_module;
16
5
 
17
- return result;
18
- }
19
6
 
20
7
  void
21
8
  Init_native_btree()
22
9
  {
23
- btree_module = rb_define_module(NATIVE_BTREE);
24
- btree_class = rb_define_class_under(btree_module, NATIVE_BTREE_CLASS, rb_cObject);
25
- rb_define_singleton_method(btree_class, "from", btree_from, 0);
26
- }
10
+ rbtree_module = rb_define_module(NATIVE_BTREE_MODULE);
11
+ rbtree_class = rb_define_class_under(rbtree_module, NATIVE_BTREE_CLASS, rb_cObject);
27
12
 
13
+ rb_define_alloc_func(rbtree_class, rbtree_alloc);
14
+ rb_define_method(rbtree_class, "initialize", rbtree_initialize, 0);
15
+
16
+ rb_define_method(rbtree_class, "[]=", rbtree_set, 2);
17
+ rb_define_alias(rbtree_class, "set", "[]=");
18
+ rb_define_method(rbtree_class, "[]", rbtree_get, 1);
19
+ rb_define_alias(rbtree_class, "get", "[]");
20
+ rb_define_method(rbtree_class, "delete", rbtree_delete, 1);
21
+ rb_define_method(rbtree_class, "each", rbtree_each, 0);
22
+ rb_define_method(rbtree_class, "size", rbtree_size, 0);
23
+ rb_define_method(rbtree_class, "height", rbtree_height, 0);
24
+ rb_define_method(rbtree_class, "clear", rbtree_clear, 0);
25
+ rb_define_method(rbtree_class, "include?", rbtree_is_include, 1);
26
+ rb_define_method(rbtree_class, "to_h", rbtree_to_h, 0);
27
+ rb_define_method(rbtree_class, "to_a", rbtree_to_a, 0);
28
+ }
@@ -0,0 +1,102 @@
1
+ #include <rbtree_type.h>
2
+
3
+ const rb_data_type_t rbtree_type;
4
+
5
+
6
+ static void
7
+ rbtree_free(gpointer data)
8
+ {
9
+ RBTree *rbtree = (RBTree *) data;
10
+
11
+ g_tree_destroy(rbtree->gtree);
12
+ g_free(data);
13
+ }
14
+
15
+
16
+ static gboolean
17
+ rbtree_mark_callback(gpointer key, gpointer value, gpointer data)
18
+ {
19
+ rb_gc_mark((VALUE) key);
20
+ rb_gc_mark((VALUE) value);
21
+
22
+ return FALSE;
23
+ }
24
+
25
+
26
+ static void
27
+ rbtree_mark(gpointer data)
28
+ {
29
+ RBTree *rbtree = (RBTree *)data;
30
+
31
+ rb_gc_mark(rbtree->comparator);
32
+
33
+ g_tree_foreach(rbtree->gtree, rbtree_mark_callback, NULL);
34
+ }
35
+
36
+ /*
37
+
38
+ https://github.com/GNOME/glib/blob/main/glib/gtree.c#L80
39
+
40
+ struct _GTree
41
+ {
42
+ GTreeNode *root;
43
+ GCompareDataFunc key_compare;
44
+ GDestroyNotify key_destroy_func;
45
+ GDestroyNotify value_destroy_func;
46
+ gpointer key_compare_data;
47
+ guint nnodes;
48
+ gint ref_count;
49
+ };
50
+
51
+ struct _GTreeNode
52
+ {
53
+ gpointer key;
54
+ gpointer value;
55
+ GTreeNode *left;
56
+ GTreeNode *right;
57
+ gint8 balance;
58
+ guint8 left_child;
59
+ guint8 right_child;
60
+ };
61
+ */
62
+
63
+ static size_t
64
+ rbtree_size(gconstpointer data)
65
+ {
66
+ RBTree *rbtree = (RBTree *) data;
67
+
68
+ gint gtree_size = g_tree_nnodes(rbtree->gtree);
69
+
70
+ // struct _GTreeNode
71
+ size_t node_size = sizeof(gpointer) * 4 +
72
+ sizeof(gint8) +
73
+ sizeof(guint8) * 2;
74
+
75
+ // struct _GTree
76
+ size_t gtree_root_size = sizeof(gpointer) * 5 +
77
+ sizeof(gint8) +
78
+ sizeof(guint8) * 2;
79
+
80
+ return sizeof(RBTree) + node_size * gtree_size + gtree_root_size;
81
+ }
82
+
83
+
84
+ const rb_data_type_t rbtree_type = {
85
+ .wrap_struct_name = NATIVE_TYPE_NAME,
86
+ .function = {
87
+ .dmark = rbtree_mark,
88
+ .dfree = rbtree_free,
89
+ .dsize = rbtree_size,
90
+ },
91
+ .data = NULL,
92
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
93
+ };
94
+
95
+
96
+ VALUE
97
+ rbtree_alloc(VALUE self)
98
+ {
99
+ RBTree *rbtree = g_new(RBTree, 1);
100
+
101
+ return TypedData_Wrap_Struct(self, &rbtree_type, rbtree);
102
+ }
Binary file
@@ -1,3 +1,3 @@
1
1
  module NativeBtree
2
- VERSION = "0.1.0.alpha2".freeze
2
+ VERSION = "0.2.1".freeze
3
3
  end
data/native_btree.gemspec CHANGED
@@ -27,20 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.files += Dir['*.{md}']
28
28
  s.files += %w[Rakefile Gemfile CMakeLists.txt native_btree.gemspec LICENSE]
29
29
 
30
- s.bindir = "bin"
31
30
  s.executables = s.files.grep(%r{\Abin/}) { |f| File.basename(f) }
32
31
  s.require_paths = ["lib"]
33
32
  s.required_ruby_version = '>= 2.6'
34
-
35
- s.add_dependency 'rubocop', '~> 1.35.0'
36
- s.add_dependency 'rubocop-rake', '~> 0.6.0'
37
- s.add_dependency 'rubocop-rspec', '~> 2.12.1'
38
- s.add_dependency 'rake', '~> 13.0.6'
39
- s.add_dependency 'rspec', '~> 3.11.0'
40
-
41
- s.add_development_dependency 'awesome_print', '~> 1.9'
42
- s.add_development_dependency 'debase', '~> 0.2'
43
- s.add_development_dependency 'pry', '~> 0.14'
44
- s.add_development_dependency 'ruby-debug-ide', '~> 0.7'
45
- s.add_development_dependency 'solargraph', '~> 0.46'
46
33
  end
data/spec/debug.rb ADDED
@@ -0,0 +1,24 @@
1
+ # rubocop:disable all
2
+
3
+ require_relative "../lib/native_btree/native_btree"
4
+
5
+ tree = NativeBtree::Btree.new
6
+
7
+ GC.start
8
+
9
+ tree[3] = {a: 'value 3'}
10
+ tree[1] = {a: 'value 1'}
11
+ tree[2] = {a: 'value 2'}
12
+ tree[16] = {a: 'value 16'}
13
+ tree[0] = {a: 'value 0'}
14
+
15
+ GC.start
16
+
17
+ block = ->(key) { "#{key} is not found" }
18
+ puts tree.delete(77, &block)
19
+
20
+ tree = null
21
+
22
+ GC.start
23
+
24
+ puts "exit 0"
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NativeBtree do
4
+ it "has a version number" do
5
+ expect(NativeBtree::VERSION).not_to be_nil
6
+ end
7
+
8
+ describe NativeBtree::Btree do
9
+
10
+ describe "initialize class method" do
11
+ it 'respond to new' do
12
+ expect(described_class).to respond_to('new').with(0).arguments
13
+ end
14
+
15
+ it "return new btree instance" do
16
+ expect(described_class.new { nil }).to be_kind_of(described_class)
17
+ end
18
+
19
+ it "raise error if block is not given" do
20
+ expect { described_class.new() }.to raise_error(LocalJumpError)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NativeBtree do
4
+
5
+ describe NativeBtree::Btree do
6
+ let(:tree) do
7
+ described_class.new do |a, b|
8
+ a - b
9
+ end
10
+ end
11
+
12
+ describe "#[]= method" do
13
+
14
+ it "respond to" do
15
+ expect(tree).to respond_to('[]=')
16
+ end
17
+
18
+ it 'set key/value pair' do
19
+ tree[2] = 22
20
+ expect(tree[2]).to be 22
21
+ end
22
+
23
+ it "pass key arg and value" do
24
+ expect(tree[:key] = 10).to be 10
25
+ end
26
+
27
+ it "Raise ArgumentError if key was not passed" do
28
+ expect { tree[] = 1 }.to raise_error(ArgumentError)
29
+ end
30
+
31
+ it 'Call comparator while set value' do
32
+ comparator = spy('comparator')
33
+ def comparator.to_proc
34
+ proc do |a, b|
35
+ comparator.call()
36
+ a - b
37
+ end
38
+ end
39
+
40
+ btree = described_class.new(&comparator)
41
+ btree[1] = 1
42
+ btree[2] = 2
43
+ expect(comparator).to have_received(:call)
44
+ end
45
+
46
+ it 'has a set alias' do
47
+ expect(tree).to respond_to('set')
48
+ end
49
+ end
50
+
51
+ describe "#[] method" do
52
+ it "respond to" do
53
+ expect(tree).to respond_to('[]')
54
+ end
55
+
56
+ it 'return expected value if found' do
57
+ tree[3] = 'a'
58
+ tree[4] = 'b'
59
+ expect(tree[3]).to be 'a'
60
+ end
61
+
62
+ it 'return nil if not found' do
63
+ tree[1] = '1'
64
+ tree[5] = '5'
65
+ expect(tree[2]).to be_nil
66
+ end
67
+
68
+ it 'has a get alias' do
69
+ expect(tree).to respond_to('get')
70
+ end
71
+ end
72
+
73
+ describe "#height method" do
74
+ it "respond to" do
75
+ expect(tree).to respond_to(:height)
76
+ end
77
+
78
+ it 'return tree height with items' do
79
+ tree[1] = 11
80
+ tree[2] = 22
81
+ tree[3] = 33
82
+ tree[4] = 44
83
+ expect(tree.height).to be 3
84
+ end
85
+
86
+ it 'return 0 if empty tree' do
87
+ expect(tree.height).to be 0
88
+ end
89
+ end
90
+
91
+ describe "#size method" do
92
+ it "respond to" do
93
+ expect(tree).to respond_to(:size)
94
+ end
95
+
96
+ it 'return count of nodes' do
97
+ tree[1] = 1
98
+ tree[2] = 2
99
+ tree[3] = 3
100
+ expect(tree.size).to be 3
101
+ end
102
+
103
+ it 'return 0 if empty tree' do
104
+ expect(tree.size).to be 0
105
+ end
106
+
107
+ end
108
+
109
+ describe "#delete method" do
110
+ it "respond to" do
111
+ expect(tree).to respond_to(:delete)
112
+ end
113
+
114
+ it 'delete key value pair' do
115
+ tree[2] = 22
116
+ tree[3] = 33
117
+ tree.delete(3)
118
+ expect(tree[3]).to be_nil
119
+ end
120
+
121
+ it "return nil if not found" do
122
+ tree[3] = 33
123
+ expect(tree.delete(4)).to be_nil
124
+ end
125
+
126
+ it "return value if key is found" do
127
+ tree[2] = 22
128
+ tree[3] = 33
129
+ expect(tree.delete(2)).to be 22
130
+ end
131
+
132
+ it "call block with key if not found" do
133
+ tree[2] = 22
134
+ block = ->(key) { "#{key} is not found" }
135
+ expect(tree.delete(7, &block)).to be == "7 is not found"
136
+ end
137
+ end
138
+
139
+ describe "#clear method" do
140
+ it "respond to" do
141
+ expect(tree).to respond_to(:clear)
142
+ end
143
+
144
+ it 'clear tree' do
145
+ tree[1] = 11
146
+ tree[2] = 22
147
+ tree[3] = 33
148
+ expect(tree.size).to be 3
149
+ tree.clear()
150
+ expect(tree.size).to be 0
151
+ end
152
+
153
+ it 'return self' do
154
+ tree[1] = 11
155
+ expect(tree.clear()).to be tree
156
+ end
157
+ end
158
+
159
+ describe "#filter method" do
160
+ xit "respond to" do
161
+ expect(described_cless.respond_to?(:filter)).to be true
162
+ end
163
+ end
164
+
165
+ describe "#filter! method" do
166
+ xit "respond to" do
167
+ expect(described_cless.respond_to?(:filter!)).to be true
168
+ end
169
+ end
170
+
171
+ describe "#include? method" do
172
+ it "respond to" do
173
+ expect(tree).to respond_to(:include?)
174
+ end
175
+
176
+ it 'return true is key exists' do
177
+ tree[3] = 33
178
+ expect(tree.include?(3)).to be true
179
+ end
180
+
181
+ it 'return false if key not exists' do
182
+ tree[3] = 33
183
+ expect(tree.include?(4)).to be false
184
+ end
185
+ end
186
+
187
+ describe "to_ methods" do
188
+ describe "#to_a" do
189
+ it "respond to" do
190
+ expect(tree).to respond_to(:to_a)
191
+ end
192
+
193
+ it 'return Array' do
194
+ expect(tree.to_a).to be_kind_of(Array)
195
+ end
196
+
197
+ it 'has similar items' do
198
+ tree[2] = 22
199
+ tree[1] = 11
200
+ expect(tree.to_a()[0][1]).to be 11
201
+ end
202
+ end
203
+
204
+ describe "#to_h" do
205
+ it "respond to" do
206
+ expect(tree).to respond_to(:to_h)
207
+ end
208
+
209
+ it "return Hash" do
210
+ expect(tree.to_h).to be_kind_of(Hash)
211
+ end
212
+
213
+ it 'has similar keys' do
214
+ tree[2] = 22
215
+ tree[1] = 11
216
+ expect(tree.to_h()[1]).to be 11
217
+ end
218
+ end
219
+ end
220
+
221
+ describe "#each method" do
222
+ it "respond to" do
223
+ expect(tree).to respond_to(:each)
224
+ end
225
+
226
+ it 'yield in to block value first' do
227
+ tree[2] = 22
228
+
229
+ value = nil
230
+ tree.each { |v| value = v }
231
+
232
+ expect(value).to be 22
233
+ end
234
+
235
+ it 'yield in to block key second' do
236
+ tree[2] = 22
237
+
238
+ key = nil
239
+ tree.each { |_v, k| key = k }
240
+
241
+ expect(key).to be 2
242
+ end
243
+
244
+ it 'yield ordered keys' do
245
+ tree[16] = 16
246
+ tree[0] = 0
247
+ tree[5] = 5
248
+ tree[-4] = -4
249
+ tree[7] = 7
250
+
251
+ check = [-4, 0, 5, 7, 16]
252
+ result = []
253
+ tree.each { |value| result << value }
254
+
255
+ expect(result).to eq(check)
256
+ end
257
+ end
258
+
259
+ describe "#each_key method" do
260
+ xit "respond to" do
261
+ expect(described_cless.respond_to?(:each_key)).to be true
262
+ end
263
+ end
264
+
265
+ describe "#each_value method" do
266
+ xit "respond to" do
267
+ expect(described_cless.respond_to?(:each_value)).to be true
268
+ end
269
+ end
270
+
271
+ describe "#select method" do
272
+ xit "respond to" do
273
+ expect(described_cless.respond_to?(:select)).to be true
274
+ end
275
+ end
276
+
277
+ describe "#select! method" do
278
+ xit "respond to" do
279
+ expect(described_cless.respond_to?(:select!)).to be true
280
+ end
281
+ end
282
+ end
283
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NativeBtree do
4
+ it "has a version number" do
5
+ expect(described_class.const_defined?(:VERSION)).to be true
6
+ end
7
+
8
+ it "Has Btree contstant" do
9
+ expect(described_class.const_defined?(:Btree)).to be true
10
+ end
11
+
12
+ it "Btree is class" do
13
+ expect(described_class::Btree.class).to be Class
14
+ end
15
+ end