native_btree 0.1.0.alpha1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/CMakeLists.txt +54 -0
  4. data/Gemfile +18 -0
  5. data/LICENSE +165 -0
  6. data/README.md +67 -0
  7. data/Rakefile +48 -0
  8. data/ext/native_btree/CMakeLists.txt +38 -0
  9. data/ext/native_btree/comparator.c +13 -0
  10. data/ext/native_btree/constructor.c +19 -0
  11. data/ext/native_btree/conversion.c +54 -0
  12. data/ext/native_btree/extconf_cmake.rb +15 -0
  13. data/ext/native_btree/include/common.h +21 -0
  14. data/ext/native_btree/include/comparator.h +4 -0
  15. data/ext/native_btree/include/constructor.h +11 -0
  16. data/ext/native_btree/include/conversion.h +8 -0
  17. data/ext/native_btree/include/instance.h +22 -0
  18. data/ext/native_btree/include/iterators.h +5 -0
  19. data/ext/native_btree/include/native_btree.h +5 -47
  20. data/ext/native_btree/include/rbtree_type.h +22 -0
  21. data/ext/native_btree/instance.c +126 -0
  22. data/ext/native_btree/iterators.c +26 -0
  23. data/ext/native_btree/native_btree.c +20 -22
  24. data/ext/native_btree/rbtree_type.c +102 -0
  25. data/lib/native_btree/native_btree.bundle +0 -0
  26. data/lib/native_btree/native_btree.so +0 -0
  27. data/lib/native_btree/version.rb +2 -2
  28. data/lib/native_btree.rb +2 -1
  29. data/native_btree.gemspec +33 -0
  30. data/spec/debug.rb +24 -0
  31. data/spec/native_btree_class_spec.rb +24 -0
  32. data/spec/native_btree_instance_spec.rb +283 -0
  33. data/spec/native_btree_module_spec.rb +15 -0
  34. data/spec/spec_helper.rb +15 -0
  35. metadata +50 -18
  36. data/ext/native_btree/btree.cc +0 -128
  37. data/ext/native_btree/extconf.h +0 -11
  38. data/ext/native_btree/extconf.rb +0 -35
  39. data/ext/native_btree/rb_methods.cc +0 -221
@@ -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,30 +1,28 @@
1
1
  #include <native_btree.h>
2
2
 
3
- VALUE btree_class;
4
- VALUE btree_module;
3
+ VALUE rbtree_class;
4
+ VALUE rbtree_module;
5
+
5
6
 
6
7
  void
7
8
  Init_native_btree()
8
9
  {
9
- btree_module = rb_define_module("NativeBTree");
10
- btree_class = rb_define_class_under(btree_module, "BTree", rb_cObject);
10
+ rbtree_module = rb_define_module(NATIVE_BTREE_MODULE);
11
+ rbtree_class = rb_define_class_under(rbtree_module, NATIVE_BTREE_CLASS, rb_cObject);
11
12
 
12
- rb_define_singleton_method(btree_class, "new", btree_new, 0);
13
- // rb_define_method(btree_class, "initialize", btree_init, 0);
14
- rb_define_method(btree_class, "size", btree_size, 0);
15
- rb_define_method(btree_class, "height", btree_height, 0);
16
- rb_define_method(btree_class, "set", btree_set, 2);
17
- rb_define_alias(btree_class, "[]=", "set");
18
- rb_define_method(btree_class, "get", btree_get, 1);
19
- rb_define_alias(btree_class, "[]", "get");
20
- rb_define_method(btree_class, "delete", btree_delete, 1);
21
- rb_define_method(btree_class, "clear", btree_clear, 0);
22
- rb_define_method(btree_class, "has", btree_has, 1);
23
- rb_define_method(btree_class, "each", btree_each, 0);
24
- rb_define_method(btree_class, "<=>", btree_cmp, 1);
25
- rb_define_method(btree_class, "eql?", btree_equal, 1);
26
- rb_define_alias(btree_class, "==", "eql?");
27
- // TODO: to_ary
28
- // TODO: to_hash
29
- }
13
+ rb_define_alloc_func(rbtree_class, rbtree_alloc);
14
+ rb_define_method(rbtree_class, "initialize", rbtree_initialize, 0);
30
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
- module NativeBTree
2
- VERSION = "0.1.0.alpha1".freeze
1
+ module NativeBtree
2
+ VERSION = "0.2.0".freeze
3
3
  end
data/lib/native_btree.rb CHANGED
@@ -1,4 +1,5 @@
1
- module NativeBTree
1
+ # Bindings to GLib-2.0 data structure BTree
2
+ module NativeBtree
2
3
  end
3
4
 
4
5
  require "native_btree/version"
@@ -0,0 +1,33 @@
1
+ require_relative "lib/native_btree/version"
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'native_btree'
5
+ s.version = NativeBtree::VERSION
6
+
7
+ s.metadata = {
8
+ "bug_tracker_uri" => "https://github.com/unixs/ruby-native-btree/issues",
9
+ "changelog_uri" => "https://github.com/unixs/ruby-native-btree/blob/master/CHANGELOG.md",
10
+ "documentation_uri" => "https://github.com/unixs/ruby-native-btree/wiki",
11
+ "homepage_uri" => "https://github.com/unixs/ruby-native-btree",
12
+ "source_code_uri" => "https://github.com/unixs/ruby-native-btree",
13
+ "wiki_uri" => "https://github.com/unixs/ruby-native-btree/wiki",
14
+ "rubygems_mfa_required" => "true"
15
+ }
16
+
17
+ s.platform = Gem::Platform::RUBY
18
+ s.summary = 'Balanced binary tree from GLib.'
19
+ s.description = 'Ruby bindings to GTree balanced binary tree from GLib library.'
20
+ s.authors = ['Alexander Feodorov']
21
+ s.email = ['webmaster@unixcomp.org']
22
+ s.licenses = ['LGPL-3.0-or-later']
23
+ s.homepage = 'https://github.com/unixs/ruby-native-btree'
24
+ s.extensions = ["ext/#{s.name}/extconf_cmake.rb"]
25
+
26
+ s.files = Dir['{bin,ext,lib,spec}/**/*']
27
+ s.files += Dir['*.{md}']
28
+ s.files += %w[Rakefile Gemfile CMakeLists.txt native_btree.gemspec LICENSE]
29
+
30
+ s.executables = s.files.grep(%r{\Abin/}) { |f| File.basename(f) }
31
+ s.require_paths = ["lib"]
32
+ s.required_ruby_version = '>= 2.6'
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