native_btree 0.1.0.alpha1 → 0.2.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.
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