native_btree 0.1.0.alpha2 → 0.2.1

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