native_btree 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dbf5cc77f1056fc6f84cf49496c233b9a3ecd9c62a0d82149cce9804a80edd7
4
- data.tar.gz: eb1f55db08e767f443b02751258fb749ae991eb98e5426a8d5c81714c66ebd49
3
+ metadata.gz: '05598705616620516787d5fd639f883270684c2d3981b1c04056bffd8f2b1849'
4
+ data.tar.gz: 1dcd3be4d1838e5b01bf7e38b2ca746004903550366f93e91922821feb3229ad
5
5
  SHA512:
6
- metadata.gz: 7753f72aa3babc2151d74ae4bad29fb7c43e41cd7cf8b3bc9348e4b6e9be3c156d2ecc78fd2e689ca099e27df8bdee376550cbbc16b97ef15f15c431e8c5c093
7
- data.tar.gz: d1992054500ad7207aea7186a0aa9bd3099cf013983c2596f5c2b5289ca5c8129f4ceeea4bf9ddf0777eb019b4dfc70be3b0feb571d741bb148af1f68de6e754
6
+ metadata.gz: 98aa96b9820e879f94cc1f6682f9eb82f2139c7a81dd92f955db24167f9f8b384a80221b10ade4de7718c5fb56f94eea1f19fbb4360dc25c639bf1b4fd682230
7
+ data.tar.gz: f9410012b8ce525b4816377b8c8998e4ded903fca874e268a1a613a4759a5bf62051e4b55dec4259c15be5a301b1bb23978b0198b0e66d28c83e4f5f7954af1f
data/CHANGELOG.md CHANGED
@@ -10,6 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  * delete_if()
11
11
  * each method refactoring for Enumerator return type
12
12
 
13
+ ## [0.4.0] - 2022-09-16
14
+
15
+ ### Added
16
+
17
+ * Native integer comparator
18
+ * search_before()
19
+ * search_after()
20
+ * empty?()
21
+
22
+ ### Changed
23
+
24
+ * Bugfixes
25
+
13
26
  ## [0.3.0] - 2022-09-11
14
27
 
15
28
  ### 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.3.0)
5
+ VERSION 0.4.0)
6
6
 
7
7
  include(CheckSymbolExists)
8
8
 
@@ -12,8 +12,8 @@ set(CMAKE_C_STANDARD 11)
12
12
  set(CMAKE_C_EXTENSIONS ON)
13
13
  set(CMAKE_C_STANDARD_REQUIRED ON)
14
14
 
15
- set(CMAKE_C_FLAGS_DEBUG " -O0 -ggdb3 -Wall -Wextra -Wpedantic -Wno-unused-parameter")
16
- set(CMAKE_C_FLAGS_RELEASE "-O3")
15
+ set(CMAKE_C_FLAGS_DEBUG " -O0 -ggdb3 -Wall -Wextra -Wno-unused-parameter")
16
+ set(CMAKE_C_FLAGS_RELEASE "-O3 -fomit-frame-pointer")
17
17
  set(CMAKE_C_FLAGS "-pipe -march=native")
18
18
 
19
19
  # Force -fPIC
data/README.md CHANGED
@@ -11,7 +11,7 @@ In most cases it will behave same as Hash, but keys will be ordered by passed co
11
11
 
12
12
  ## Requirements
13
13
 
14
- * **CMake** build tool version **>= 3.14.0**
14
+ * **CMake** build tool version **>= 3.5.0**, >= 3.14.0 will be cool.
15
15
  * `pkg-config` tool
16
16
  * **GLib** library
17
17
  * On Ubuntu run:
@@ -29,6 +29,7 @@ In most cases it will behave same as Hash, but keys will be ordered by passed co
29
29
 
30
30
  ## Basic usage
31
31
 
32
+ ### Example
32
33
  ```ruby
33
34
  require 'native_btree'
34
35
 
@@ -53,6 +54,39 @@ tree.height
53
54
  # 2
54
55
  ```
55
56
 
57
+ ### Native int comparator
58
+ Will behave like an array with negative indexes)
59
+ ```ruby
60
+ # Pass comparator for keys as block
61
+ tree = NativeBtree::Btree.new(NativeBtree::Btree::INT_COMPARATOR)
62
+
63
+ tree[-2] = 22
64
+ tree[-1] = 1
65
+ tree[0] = 100
66
+ tree[5] = 55
67
+
68
+ tree.to_a
69
+
70
+ #[
71
+ # [0] [
72
+ # [0] -2,
73
+ # [1] 22
74
+ # ],
75
+ # [1] [
76
+ # [0] -1,
77
+ # [1] 1
78
+ # ],
79
+ # [2] [
80
+ # [0] 0,
81
+ # [1] 100
82
+ # ],
83
+ # [3] [
84
+ # [0] 5,
85
+ # [1] 55
86
+ # ]
87
+ #]
88
+ ```
89
+
56
90
  ## API ref
57
91
 
58
92
  You must provide your own comparator for keys in `new` class method block.
@@ -68,7 +102,7 @@ Implemented methods:
68
102
  * `delete`
69
103
  * `size`
70
104
  * `height`
71
- * `each` (NB! block is required)
105
+ * `each` (NB! block is required) (NB! block is required)
72
106
  * `include?`
73
107
  * `clear`
74
108
  * `to_h`
@@ -76,5 +110,10 @@ Implemented methods:
76
110
  * `to_proc`
77
111
  * `filter` (alias: select)
78
112
  * `filter!` (alias: select!)
113
+ * `each_value`
114
+ * `each_key`
115
+ * `search_before` (GLib version >= 2.68) - Select keys <= first arg, ret new Btree
116
+ * `search_after` (GLib version >= 2.68) - Select keys >= first arg, ret new Btree
117
+ * `empty?`
79
118
 
80
119
  You can mix in the `Enumerable` module if additional methods are needed.
@@ -9,12 +9,22 @@ include_directories(include ${GLIB2_INCLUDE_DIRS})
9
9
 
10
10
  list(APPEND CMAKE_REQUIRED_LIBRARIES ${GLIB2_LDFLAGS})
11
11
  list(APPEND CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS})
12
- check_symbol_exists(g_tree_remove_all "glib.h" HAVE_GTREE_REMOVE_ALL)
12
+ check_symbol_exists(g_tree_remove_all "glib.h" HAS_GTREE_REMOVE_ALL)
13
+ check_symbol_exists(g_tree_lookup_node "glib.h" HAS_GTREE_NODE)
13
14
 
14
- if(HAVE_GTREE_REMOVE_ALL)
15
- add_compile_definitions(HAVE_GTREE_REMOVE_ALL)
15
+ if(HAS_GTREE_REMOVE_ALL)
16
+ add_compile_definitions(HAS_GTREE_REMOVE_ALL)
16
17
  endif()
17
18
 
19
+ if(HAS_GTREE_NODE)
20
+ add_compile_definitions(HAS_GTREE_NODE)
21
+ add_subdirectory("glib2_68")
22
+ else()
23
+ message(WARNING
24
+ "Available GLib is not support direct node access.
25
+ Version < 2.68.
26
+ Additional iterators will not compile.")
27
+ endif()
18
28
 
19
29
  add_library(${EXT_NAME}
20
30
  SHARED
@@ -27,19 +37,29 @@ add_library(comparator OBJECT comparator.c)
27
37
  add_library(iterators OBJECT iterators.c)
28
38
  add_library(conversion OBJECT conversion.c)
29
39
  add_library(search OBJECT search.c)
40
+ add_library(glib_module OBJECT glib_module.c)
30
41
 
31
- add_library(native_btree_interface
32
- STATIC
42
+
43
+ set(LIB_OBJECTS)
44
+ list(APPEND LIB_OBJECTS
33
45
  $<TARGET_OBJECTS:conversion>
34
46
  $<TARGET_OBJECTS:iterators>
35
47
  $<TARGET_OBJECTS:comparator>
36
48
  $<TARGET_OBJECTS:instance>
37
49
  $<TARGET_OBJECTS:constructor>
38
50
  $<TARGET_OBJECTS:rbtree_type>
39
- $<TARGET_OBJECTS:search>)
51
+ $<TARGET_OBJECTS:search>
52
+ $<TARGET_OBJECTS:glib_module>)
53
+
54
+ if(HAS_GTREE_NODE)
55
+ list(APPEND LIB_OBJECTS $<TARGET_OBJECTS:additional_iterators>)
56
+ endif()
57
+
58
+ add_library(native_btree_interface
59
+ STATIC
60
+ ${LIB_OBJECTS})
40
61
 
41
62
  target_link_libraries(${EXT_NAME}
42
63
  PRIVATE
43
64
  native_btree_interface
44
65
  ${GLIB2_LDFLAGS})
45
-
@@ -11,3 +11,12 @@ rbtree_native_comparator(gconstpointer a, gconstpointer b, gpointer data)
11
11
 
12
12
  return compare_result;
13
13
  }
14
+
15
+ gint
16
+ rbtree_int_comparator(gconstpointer ra, gconstpointer rb, gpointer data)
17
+ {
18
+ gint a = NUM2INT((VALUE) ra);
19
+ gint b = NUM2INT((VALUE) rb);
20
+
21
+ return a - b;
22
+ }
@@ -1,18 +1,46 @@
1
1
  #include <comparator.h>
2
2
  #include <rbtree_type.h>
3
+ #include <stdbool.h>
3
4
 
4
- VALUE
5
- rbtree_initialize(VALUE self)
5
+ inline static void
6
+ init_rbtree(RBTree *rbtree, gushort flags)
6
7
  {
7
- EXTRACT_RBTREE_SELF(rbtree);
8
+ bool flag_int_comparator = flags & RBTREE_FLAG_INT_COMPARATOR;
9
+ VALUE comparator = Qnil;
10
+ // NOTE: Possible segfault
11
+ GCompareDataFunc native_comparator = NULL;
12
+
13
+ if (flag_int_comparator) {
14
+ native_comparator = rbtree_int_comparator;
15
+ }
16
+ else {
17
+ rb_need_block();
18
+ comparator = rb_block_proc();
19
+ native_comparator = rbtree_native_comparator;
20
+ }
8
21
 
9
22
  rbtree->gtree = g_tree_new_with_data(
10
- rbtree_native_comparator,
23
+ native_comparator,
11
24
  rbtree
12
25
  );
26
+ rbtree->comparator = comparator;
27
+ rbtree->flags = flags;
28
+ }
29
+
30
+ VALUE
31
+ rbtree_initialize(int argc, VALUE* argv, VALUE self)
32
+ {
33
+ rb_check_arity(argc, 0, 1);
34
+
35
+ EXTRACT_RBTREE_SELF(rbtree);
36
+
37
+ gushort flags = 0;
38
+
39
+ if (argc > 0) {
40
+ flags = NUM2USHORT(argv[0]);
41
+ }
13
42
 
14
- rb_need_block();
15
- rbtree->comparator = rb_block_proc();
43
+ init_rbtree((RBTree *) rbtree, flags);
16
44
 
17
45
  return self;
18
46
  }
@@ -0,0 +1,3 @@
1
+ # set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
2
+
3
+ add_library(additional_iterators OBJECT additional_iterators.c)
@@ -0,0 +1,84 @@
1
+ #include <native_btree.h>
2
+ #include <iterators.h>
3
+
4
+ static void
5
+ rbtree_gtree_foreach(GTreeNode *node, RBTreeStepFunction step_func, GTraverseFunc callback, gpointer data)
6
+ {
7
+ while (node) {
8
+ callback(
9
+ g_tree_node_key(node),
10
+ g_tree_node_value(node),
11
+ data
12
+ );
13
+
14
+ node = step_func(node);
15
+ }
16
+ }
17
+
18
+
19
+ static int
20
+ rbtree_traverse_insert(gpointer key, gpointer value, gpointer tree)
21
+ {
22
+ g_tree_insert(tree, key, value);
23
+
24
+ return FALSE;
25
+ }
26
+
27
+
28
+ VALUE
29
+ rbtree_select_before(VALUE self, VALUE target)
30
+ {
31
+ EXTRACT_RBTREE_SELF(rbtree);
32
+
33
+ VALUE new_tree = rbtree_clone_wrap(rbtree);
34
+
35
+ EXTRACT_RBTREE(new_tree, new_rbtree);
36
+
37
+ GTreeNode *target_node = g_tree_upper_bound(
38
+ rbtree->gtree,
39
+ (gconstpointer) target
40
+ );
41
+
42
+ target_node = g_tree_node_previous(target_node);
43
+
44
+ if (!target_node) {
45
+ return new_tree;
46
+ }
47
+
48
+ rbtree_gtree_foreach(
49
+ target_node,
50
+ g_tree_node_previous,
51
+ rbtree_traverse_insert,
52
+ (gpointer) new_rbtree->gtree
53
+ );
54
+
55
+ return new_tree;
56
+ }
57
+
58
+
59
+ VALUE
60
+ rbtree_select_after(VALUE self, VALUE target)
61
+ {
62
+ EXTRACT_RBTREE_SELF(rbtree);
63
+
64
+ VALUE new_tree = rbtree_clone_wrap(rbtree);
65
+ EXTRACT_RBTREE(new_tree, new_rbtree);
66
+
67
+ GTreeNode *target_node = g_tree_lower_bound(
68
+ rbtree->gtree,
69
+ (gconstpointer) target
70
+ );
71
+
72
+ if (!target_node) {
73
+ return new_tree;
74
+ }
75
+
76
+ rbtree_gtree_foreach(
77
+ target_node,
78
+ g_tree_node_next,
79
+ rbtree_traverse_insert,
80
+ (gpointer) new_rbtree->gtree
81
+ );
82
+
83
+ return new_tree;
84
+ }
@@ -0,0 +1,45 @@
1
+ #include <stdbool.h>
2
+ #include <common.h>
3
+ #include <glib_module.h>
4
+
5
+ #define NATIVE_BTREE_GLIB_SUBMODULE "Glib"
6
+ #define GLIB_MODULE_MAJOR_VERSION "MAJOR_VERSION"
7
+ #define GLIB_MODULE_MINOR_VERSION "MINOR_VERSION"
8
+ #define GLIB_MODULE_MICRO_VERSION "MICRO_VERSION"
9
+
10
+ VALUE rbtree_glib_module;
11
+
12
+ void
13
+ rbtree_attach_module_glib()
14
+ {
15
+ static bool initialized = FALSE;
16
+
17
+ if (initialized) {
18
+ return;
19
+ }
20
+
21
+ rbtree_glib_module = rb_define_module_under(
22
+ native_btree_module,
23
+ NATIVE_BTREE_GLIB_SUBMODULE
24
+ );
25
+
26
+ rb_define_const(
27
+ rbtree_glib_module,
28
+ GLIB_MODULE_MAJOR_VERSION,
29
+ INT2NUM(GLIB_MAJOR_VERSION)
30
+ );
31
+
32
+ rb_define_const(
33
+ rbtree_glib_module,
34
+ GLIB_MODULE_MINOR_VERSION,
35
+ INT2NUM(GLIB_MINOR_VERSION)
36
+ );
37
+
38
+ rb_define_const(
39
+ rbtree_glib_module,
40
+ GLIB_MODULE_MICRO_VERSION,
41
+ INT2NUM(GLIB_MICRO_VERSION)
42
+ );
43
+
44
+ initialized = TRUE;
45
+ }
@@ -8,7 +8,7 @@
8
8
  #define _NATIVE_BTREE_COMMON_
9
9
 
10
10
  #define EXTRACT_RBTREE(from, to) \
11
- RBTree *to; \
11
+ const RBTree *to; \
12
12
  TypedData_Get_Struct(from, RBTree, &rbtree_type, to)
13
13
 
14
14
  #define EXTRACT_RBTREE_SELF(to) EXTRACT_RBTREE(self, to)
@@ -2,3 +2,6 @@
2
2
 
3
3
  gint
4
4
  rbtree_native_comparator(gconstpointer a, gconstpointer b, gpointer data);
5
+
6
+ gint
7
+ rbtree_int_comparator(gconstpointer a, gconstpointer b, gpointer data);
@@ -0,0 +1,6 @@
1
+ #include <ruby.h>
2
+
3
+ extern VALUE rbtree_glib_module;
4
+
5
+ void
6
+ rbtree_attach_module_glib();
@@ -1,7 +1,13 @@
1
1
  #include <common.h>
2
2
 
3
3
  typedef struct {
4
- VALUE block;
5
- RBTree *tree;
4
+ const VALUE block;
5
+ const RBTree *tree;
6
6
  gconstpointer something;
7
7
  } RBTreeSearchData;
8
+
9
+ #ifdef HAS_GTREE_NODE
10
+
11
+ typedef GTreeNode *(RBTreeStepFunction) (GTreeNode *node);
12
+
13
+ #endif
@@ -3,7 +3,7 @@
3
3
  #include <ruby.h>
4
4
 
5
5
  VALUE
6
- rbtree_initialize(VALUE self);
6
+ rbtree_initialize(int argc, VALUE *argv, VALUE self);
7
7
 
8
8
  VALUE
9
9
  rbtree_set(VALUE self, VALUE key, VALUE value);
@@ -29,6 +29,12 @@ rbtree_is_include(VALUE self, VALUE key);
29
29
  VALUE
30
30
  rbtree_each(VALUE self);
31
31
 
32
+ VALUE
33
+ rbtree_each_key(VALUE self);
34
+
35
+ VALUE
36
+ rbtree_each_value(VALUE self);
37
+
32
38
  VALUE
33
39
  rbtree_to_h(VALUE self);
34
40
 
@@ -47,4 +53,34 @@ rbtree_filter_bang(VALUE self);
47
53
  VALUE
48
54
  rbtree_is_empty(VALUE self);
49
55
 
56
+ VALUE
57
+ rbtree_select_before(VALUE self, VALUE target);
58
+
59
+ VALUE
60
+ rbtree_select_after(VALUE self, VALUE target);
61
+
62
+ VALUE
63
+ rbtree_select_between(VALUE self, VALUE from, VALUE to);
64
+
65
+ VALUE
66
+ rbtree_flatten(VALUE self);
67
+
68
+ VALUE
69
+ rbtree_delete_if(VALUE self);
70
+
71
+ VALUE
72
+ rbtree_has_key(VALUE self, VALUE key);
73
+
74
+ VALUE
75
+ rbtree_has_value(VALUE self, VALUE value);
76
+
77
+ VALUE
78
+ rbtree_eql(VALUE self, VALUE tree);
79
+
80
+ VALUE
81
+ rbtree_keys(VALUE self);
82
+
83
+ VALUE
84
+ rbtree_values(VALUE self);
85
+
50
86
  #endif // _NATIVE_BTREE_
@@ -4,19 +4,26 @@
4
4
  #include <common.h>
5
5
 
6
6
  #define RBTREE_NATIVE_TYPE_NAME "native_btree"
7
+ #define RBTREE_FLAG_INT_COMPARATOR 0b10000000
7
8
 
8
9
  extern const rb_data_type_t rbtree_type;
9
10
 
11
+ typedef struct _RBTree RBTree;
12
+
10
13
  VALUE
11
14
  rbtree_alloc(VALUE self);
12
15
 
16
+ VALUE
17
+ rbtree_clone_wrap(const RBTree *orig);
18
+
13
19
  /**
14
20
  * Internal native instance
15
21
  */
16
- typedef struct _RBTree
22
+ struct _RBTree
17
23
  {
18
24
  GTree *gtree;
19
25
  VALUE comparator;
20
- } RBTree;
26
+ gushort flags;
27
+ };
21
28
 
22
29
  #endif //_RBTREE_TYPE_
@@ -1,7 +1,7 @@
1
1
  #include <common.h>
2
2
 
3
3
 
4
- #ifndef HAVE_GTREE_REMOVE_ALL
4
+ #ifndef HAS_GTREE_REMOVE_ALL
5
5
 
6
6
  static gboolean
7
7
  rbtree_remove_node(gpointer key, gpointer val, gpointer data) {
@@ -102,7 +102,7 @@ rbtree_clear(VALUE self)
102
102
  {
103
103
  EXTRACT_RBTREE_SELF(rbtree);
104
104
 
105
- #ifdef HAVE_GTREE_REMOVE_ALL
105
+ #ifdef HAS_GTREE_REMOVE_ALL
106
106
  g_tree_remove_all(rbtree->gtree);
107
107
  #else
108
108
  g_tree_foreach(rbtree->gtree, rbtree_remove_node, (gpointer) rbtree);
@@ -1,5 +1,6 @@
1
1
  #include <common.h>
2
2
 
3
+
3
4
  static gboolean
4
5
  foraech_callbac(gpointer a, gpointer b, gpointer data)
5
6
  {
@@ -12,6 +13,31 @@ foraech_callbac(gpointer a, gpointer b, gpointer data)
12
13
  return FALSE;
13
14
  }
14
15
 
16
+
17
+ static gboolean
18
+ foraech_key_callbac(gpointer a, gpointer b, gpointer data)
19
+ {
20
+ VALUE key = (VALUE) a;
21
+ VALUE block = (VALUE) data;
22
+
23
+ rb_funcall(block, rb_intern("call"), 1, key);
24
+
25
+ return FALSE;
26
+ }
27
+
28
+
29
+ static gboolean
30
+ foraech_value_callbac(gpointer a, gpointer b, gpointer data)
31
+ {
32
+ VALUE value = (VALUE) b;
33
+ VALUE block = (VALUE) data;
34
+
35
+ rb_funcall(block, rb_intern("call"), 1, value);
36
+
37
+ return FALSE;
38
+ }
39
+
40
+
15
41
  VALUE
16
42
  rbtree_each(VALUE self)
17
43
  {
@@ -24,3 +50,31 @@ rbtree_each(VALUE self)
24
50
 
25
51
  return self;
26
52
  }
53
+
54
+
55
+ VALUE
56
+ rbtree_each_key(VALUE self)
57
+ {
58
+ rb_need_block();
59
+ VALUE block = rb_block_proc();
60
+
61
+ EXTRACT_RBTREE_SELF(rbtree);
62
+
63
+ g_tree_foreach(rbtree->gtree, foraech_key_callbac, (gpointer) block);
64
+
65
+ return self;
66
+ }
67
+
68
+
69
+ VALUE
70
+ rbtree_each_value(VALUE self)
71
+ {
72
+ rb_need_block();
73
+ VALUE block = rb_block_proc();
74
+
75
+ EXTRACT_RBTREE_SELF(rbtree);
76
+
77
+ g_tree_foreach(rbtree->gtree, foraech_value_callbac, (gpointer) block);
78
+
79
+ return self;
80
+ }
@@ -1,14 +1,15 @@
1
1
  #include <native_btree.h>
2
2
  #include <rbtree_type.h>
3
+ #include <glib_module.h>
3
4
 
4
5
  #define NATIVE_BTREE_MODULE "NativeBtree"
5
6
  #define NATIVE_BTREE_CLASS "Btree"
7
+ #define NATIVE_BTREE_CONST_INT_COMPARATOR "INT_COMPARATOR"
6
8
 
7
9
 
8
10
  VALUE native_btree_class;
9
11
  VALUE native_btree_module;
10
12
 
11
-
12
13
  void
13
14
  Init_native_btree()
14
15
  {
@@ -19,10 +20,20 @@ Init_native_btree()
19
20
  rb_cObject
20
21
  );
21
22
 
23
+ VALUE int_comparator = USHORT2NUM(RBTREE_FLAG_INT_COMPARATOR);
24
+ OBJ_FREEZE(int_comparator);
25
+ rb_define_const(
26
+ native_btree_class,
27
+ NATIVE_BTREE_CONST_INT_COMPARATOR,
28
+ int_comparator
29
+ );
30
+
31
+ rbtree_attach_module_glib();
32
+
22
33
  // rb_include_module(native_btree_class, rb_mEnumerable);
23
34
 
24
35
  rb_define_alloc_func(native_btree_class, rbtree_alloc);
25
- rb_define_method(native_btree_class, "initialize", rbtree_initialize, 0);
36
+ rb_define_method(native_btree_class, "initialize", rbtree_initialize, -1);
26
37
 
27
38
  rb_define_method(native_btree_class, "[]=", rbtree_set, 2);
28
39
  rb_define_alias(native_btree_class, "set", "[]=");
@@ -30,6 +41,8 @@ Init_native_btree()
30
41
  rb_define_alias(native_btree_class, "get", "[]");
31
42
  rb_define_method(native_btree_class, "delete", rbtree_delete, 1);
32
43
  rb_define_method(native_btree_class, "each", rbtree_each, 0);
44
+ rb_define_method(native_btree_class, "each_key", rbtree_each_key, 0);
45
+ rb_define_method(native_btree_class, "each_value", rbtree_each_value, 0);
33
46
  rb_define_method(native_btree_class, "size", rbtree_size, 0);
34
47
  rb_define_method(native_btree_class, "height", rbtree_height, 0);
35
48
  rb_define_method(native_btree_class, "clear", rbtree_clear, 0);
@@ -42,4 +55,9 @@ Init_native_btree()
42
55
  rb_define_method(native_btree_class, "filter!", rbtree_filter_bang, 0);
43
56
  rb_define_alias(native_btree_class, "select!", "filter!");
44
57
  rb_define_method(native_btree_class, "empty?", rbtree_is_empty, 0);
58
+
59
+ #ifdef HAS_GTREE_NODE
60
+ rb_define_method(native_btree_class, "select_before", rbtree_select_before, 1);
61
+ rb_define_method(native_btree_class, "select_after", rbtree_select_after, 1);
62
+ #endif
45
63
  }
@@ -8,7 +8,10 @@ rbtree_type_free(gpointer data)
8
8
  {
9
9
  RBTree *rbtree = (RBTree *) data;
10
10
 
11
- g_tree_destroy(rbtree->gtree);
11
+ if (rbtree->gtree) {
12
+ g_tree_destroy(rbtree->gtree);
13
+ }
14
+
12
15
  g_free(data);
13
16
  }
14
17
 
@@ -26,9 +29,11 @@ rbtree_mark_callback(gpointer key, gpointer value, gpointer data)
26
29
  static void
27
30
  rbtree_type_mark(gpointer data)
28
31
  {
29
- RBTree *rbtree = (RBTree *)data;
32
+ RBTree *rbtree = (RBTree *) data;
30
33
 
31
- rb_gc_mark(rbtree->comparator);
34
+ if (!NIL_P(rbtree->comparator)) {
35
+ rb_gc_mark(rbtree->comparator);
36
+ }
32
37
 
33
38
  g_tree_foreach(rbtree->gtree, rbtree_mark_callback, NULL);
34
39
  }
@@ -98,5 +103,26 @@ rbtree_alloc(VALUE self)
98
103
  {
99
104
  RBTree *rbtree = g_new(RBTree, 1);
100
105
 
106
+ rbtree->gtree = NULL;
107
+ rbtree->comparator = Qnil;
108
+ rbtree->flags = 0;
109
+
101
110
  return TypedData_Wrap_Struct(self, &rbtree_type, rbtree);
102
111
  }
112
+
113
+
114
+ VALUE
115
+ rbtree_clone_wrap(const RBTree *orig)
116
+ {
117
+ const VALUE rflags = USHORT2NUM(orig->flags);
118
+
119
+ VALUE new_tree = rb_funcall_with_block(
120
+ native_btree_class,
121
+ rb_intern("new"),
122
+ orig->flags ? 1 : 0,
123
+ orig->flags ? &rflags : NULL,
124
+ orig->comparator
125
+ );
126
+
127
+ return new_tree;
128
+ }
@@ -1,6 +1,5 @@
1
1
  #include <iterators.h>
2
2
 
3
- VALUE native_btree_class;
4
3
 
5
4
  static gboolean
6
5
  filter_callback(gpointer a, gpointer b, gpointer data)
@@ -52,13 +51,7 @@ rbtree_filter(VALUE self)
52
51
 
53
52
  VALUE block = rb_block_proc();
54
53
 
55
- VALUE new_tree = rb_funcall_with_block(
56
- native_btree_class,
57
- rb_intern("new"),
58
- 0,
59
- NULL,
60
- rbtree->comparator
61
- );
54
+ VALUE new_tree = rbtree_clone_wrap(rbtree);
62
55
 
63
56
  EXTRACT_RBTREE(new_tree, new_rbtree);
64
57
 
Binary file
@@ -1,3 +1,3 @@
1
1
  module NativeBtree
2
- VERSION = "0.3.0".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
data/spec/debug.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative "../lib/native_btree/native_btree"
4
4
 
5
- tree = NativeBtree::Btree.new { |a, b| a - b }
5
+ tree = NativeBtree::Btree.new() {|a, b| a - b }
6
6
 
7
7
  GC.start
8
8
 
@@ -24,10 +24,19 @@ puts tree.to_h
24
24
  pr = tree.to_proc
25
25
 
26
26
  puts pr
27
- puts pr.call(10)
28
- puts pr.call(16)
29
27
 
30
28
 
29
+ tree.clear
30
+ tree[1] = 15
31
+ tree[2] = 22
32
+ tree[3] = 33
33
+ tree[4] = 44
34
+ tree[5] = 55
35
+ tree[6] = 66
36
+ tree[7] = 77
37
+
38
+ puts tree.select_after(4).to_h
39
+
31
40
  GC.start
32
41
 
33
42
  puts "exit 0"
@@ -19,6 +19,22 @@ RSpec.describe NativeBtree do
19
19
  it "raise error if block is not given" do
20
20
  expect { described_class.new() }.to raise_error(LocalJumpError)
21
21
  end
22
+
23
+ it 'return new btree with int comparator' do
24
+ expect(described_class.new(described_class::INT_COMPARATOR))
25
+ .to be_kind_of(described_class)
26
+ end
27
+
28
+ end
29
+
30
+ describe "constants" do
31
+ it 'has const INT_COMPARATOR' do
32
+ expect(described_class.const_defined?(:INT_COMPARATOR)).to be true
33
+ end
34
+
35
+ it 'const INT_COMPARATOR is 1' do
36
+ expect(described_class::INT_COMPARATOR).to be 128
37
+ end
22
38
  end
23
39
  end
24
40
  end
@@ -0,0 +1,188 @@
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(described_class::INT_COMPARATOR)
8
+ end
9
+
10
+ describe "#[]= method" do
11
+
12
+ it "respond to" do
13
+ expect(tree).to respond_to('[]=')
14
+ end
15
+
16
+ it 'set key/value pair' do
17
+ tree[2] = 22
18
+ expect(tree[2]).to be 22
19
+ end
20
+
21
+ it "pass key arg and value" do
22
+ expect(tree[:key] = 10).to be 10
23
+ end
24
+
25
+ it "Raise ArgumentError if key was not passed" do
26
+ expect { tree[] = 1 }.to raise_error(ArgumentError)
27
+ end
28
+
29
+ it 'Call comparator while set value' do
30
+ comparator = spy('comparator')
31
+ def comparator.to_proc
32
+ proc do |a, b|
33
+ comparator.call()
34
+ a - b
35
+ end
36
+ end
37
+
38
+ btree = described_class.new(&comparator)
39
+ btree[1] = 1
40
+ btree[2] = 2
41
+ expect(comparator).to have_received(:call)
42
+ end
43
+
44
+ it 'has a set alias' do
45
+ expect(tree).to respond_to('set')
46
+ end
47
+ end
48
+
49
+ describe "#[] method" do
50
+ it "respond to" do
51
+ expect(tree).to respond_to('[]')
52
+ end
53
+
54
+ it 'return expected value if found' do
55
+ tree[3] = 'a'
56
+ tree[4] = 'b'
57
+ expect(tree[3]).to be 'a'
58
+ end
59
+
60
+ it 'return nil if not found' do
61
+ tree[1] = '1'
62
+ tree[5] = '5'
63
+ expect(tree[2]).to be_nil
64
+ end
65
+
66
+ it 'has a get alias' do
67
+ expect(tree).to respond_to('get')
68
+ end
69
+ end
70
+
71
+ describe "#height method" do
72
+ it "respond to" do
73
+ expect(tree).to respond_to(:height)
74
+ end
75
+
76
+ it 'return tree height with items' do
77
+ tree[1] = 11
78
+ tree[2] = 22
79
+ tree[3] = 33
80
+ tree[4] = 44
81
+ expect(tree.height).to be 3
82
+ end
83
+
84
+ it 'return 0 if empty tree' do
85
+ expect(tree.height).to be 0
86
+ end
87
+ end
88
+
89
+ describe "#size method" do
90
+ it "respond to" do
91
+ expect(tree).to respond_to(:size)
92
+ end
93
+
94
+ it 'return count of nodes' do
95
+ tree[1] = 1
96
+ tree[2] = 2
97
+ tree[3] = 3
98
+ expect(tree.size).to be 3
99
+ end
100
+
101
+ it 'return 0 if empty tree' do
102
+ expect(tree.size).to be 0
103
+ end
104
+
105
+ end
106
+
107
+ describe "#delete method" do
108
+ it "respond to" do
109
+ expect(tree).to respond_to(:delete)
110
+ end
111
+
112
+ it 'delete key value pair' do
113
+ tree[2] = 22
114
+ tree[3] = 33
115
+ tree.delete(3)
116
+ expect(tree[3]).to be_nil
117
+ end
118
+
119
+ it "return nil if not found" do
120
+ tree[3] = 33
121
+ expect(tree.delete(4)).to be_nil
122
+ end
123
+
124
+ it "return value if key is found" do
125
+ tree[2] = 22
126
+ tree[3] = 33
127
+ expect(tree.delete(2)).to be 22
128
+ end
129
+
130
+ it "call block with key if not found" do
131
+ tree[2] = 22
132
+ block = ->(key) { "#{key} is not found" }
133
+ expect(tree.delete(7, &block)).to be == "7 is not found"
134
+ end
135
+ end
136
+
137
+ describe "#clear method" do
138
+ it "respond to" do
139
+ expect(tree).to respond_to(:clear)
140
+ end
141
+
142
+ it 'clear tree' do
143
+ tree[1] = 11
144
+ tree[2] = 22
145
+ tree[3] = 33
146
+ expect(tree.size).to be 3
147
+ tree.clear()
148
+ expect(tree.size).to be 0
149
+ end
150
+
151
+ it 'return self' do
152
+ tree[1] = 11
153
+ expect(tree.clear()).to be tree
154
+ end
155
+ end
156
+
157
+ describe "#include? method" do
158
+ it "respond to" do
159
+ expect(tree).to respond_to(:include?)
160
+ end
161
+
162
+ it 'return true is key exists' do
163
+ tree[3] = 33
164
+ expect(tree.include?(3)).to be true
165
+ end
166
+
167
+ it 'return false if key not exists' do
168
+ tree[3] = 33
169
+ expect(tree.include?(4)).to be false
170
+ end
171
+ end
172
+
173
+ describe "#empty? method" do
174
+ it 'respond to' do
175
+ expect(tree).to respond_to(:empty?)
176
+ end
177
+
178
+ it 'return false if nodes exists' do
179
+ tree[3] = 33
180
+ expect(tree.empty?).to be false
181
+ end
182
+
183
+ it 'return true if nodes not exists' do
184
+ expect(tree.empty?).to be true
185
+ end
186
+ end
187
+ end
188
+ end
@@ -48,14 +48,42 @@ RSpec.describe NativeBtree do
48
48
  end
49
49
 
50
50
  describe "#each_key method" do
51
- xit "respond to" do
52
- expect(described_cless.respond_to?(:each_key)).to be true
51
+ it "respond to" do
52
+ expect(tree).to respond_to(:each_key)
53
+ end
54
+
55
+ it 'yield ordered keys' do
56
+ tree[16] = 160
57
+ tree[0] = 0
58
+ tree[5] = 50
59
+ tree[-4] = -40
60
+ tree[7] = 70
61
+
62
+ check = [-4, 0, 5, 7, 16]
63
+ result = []
64
+ tree.each_key { |key| result << key }
65
+
66
+ expect(result).to eq(check)
53
67
  end
54
68
  end
55
69
 
56
70
  describe "#each_value method" do
57
- xit "respond to" do
58
- expect(described_cless.respond_to?(:each_value)).to be true
71
+ it "respond to" do
72
+ expect(tree).to respond_to(:each_value)
73
+ end
74
+
75
+ it 'yield values by ordered keys' do
76
+ tree[16] = 160
77
+ tree[0] = 0
78
+ tree[5] = 50
79
+ tree[-4] = -40
80
+ tree[7] = 70
81
+
82
+ check = [-40, 0, 50, 70, 160]
83
+ result = []
84
+ tree.each_value { |value| result << value }
85
+
86
+ expect(result).to eq(check)
59
87
  end
60
88
  end
61
89
  end
@@ -12,4 +12,24 @@ RSpec.describe NativeBtree do
12
12
  it "Btree is class" do
13
13
  expect(described_class::Btree.class).to be Class
14
14
  end
15
+
16
+ it "Has Glib contstant" do
17
+ expect(described_class.const_defined?(:Glib)).to be true
18
+ end
19
+
20
+ it "Glib is module" do
21
+ expect(described_class::Glib.class).to be Module
22
+ end
23
+
24
+ it "Has MAJOR_VERSION contstant" do
25
+ expect(described_class::Glib.const_defined?(:MAJOR_VERSION)).to be true
26
+ end
27
+
28
+ it "Has MINOR_VERSION contstant" do
29
+ expect(described_class::Glib.const_defined?(:MINOR_VERSION)).to be true
30
+ end
31
+
32
+ it "Has MICRO_VERSION contstant" do
33
+ expect(described_class::Glib.const_defined?(:MICRO_VERSION)).to be true
34
+ end
15
35
  end
@@ -54,6 +54,17 @@ RSpec.describe NativeBtree do
54
54
  expect(tree.equal?(result)).to be false
55
55
  end
56
56
 
57
+ it 'construct correct tree with int comparator' do
58
+ tree = described_class.new(described_class::INT_COMPARATOR)
59
+
60
+ tree[1] = 11
61
+ tree[5] = 90
62
+ tree[2] = 32
63
+ tree[100] = 15
64
+ tree[46] = 8
65
+
66
+ expect(tree.filter { |v| v > 20 }.to_a).to match_array([[2, 32], [5, 90]])
67
+ end
57
68
  end
58
69
 
59
70
  describe "#filter! method" do
@@ -88,7 +99,8 @@ RSpec.describe NativeBtree do
88
99
  tree[100] = 15
89
100
  tree[46] = 8
90
101
 
91
- expect(tree.filter! { |v| v > 20 }.to_a).to match_array([[2, 32], [5, 90]])
102
+ expect(tree.filter! { |v| v > 20 }.to_a)
103
+ .to match_array([[2, 32], [5, 90]])
92
104
  end
93
105
 
94
106
  it 'filter tree by keys' do
@@ -98,7 +110,8 @@ RSpec.describe NativeBtree do
98
110
  tree[100] = 15
99
111
  tree[46] = 8
100
112
 
101
- expect(tree.filter! { |_v, k| k > 20 }.to_a).to match_array([[46, 8], [100, 15]])
113
+ expect(tree.filter! { |_v, k| k > 20 }.to_a)
114
+ .to match_array([[46, 8], [100, 15]])
102
115
  end
103
116
 
104
117
  end
@@ -114,5 +127,84 @@ RSpec.describe NativeBtree do
114
127
  expect(tree).to respond_to(:select!)
115
128
  end
116
129
  end
130
+
131
+ if NativeBtree::Glib::MAJOR_VERSION == 2 &&
132
+ NativeBtree::Glib::MINOR_VERSION >= 68
133
+
134
+ describe "select_before method" do
135
+ it 'respond_to' do
136
+ expect(tree).to respond_to(:select_before)
137
+ end
138
+
139
+ it 'return expected collection' do
140
+ tree[1] = 11
141
+ tree[2] = 32
142
+ tree[5] = 90
143
+ tree[46] = 8
144
+ tree[100] = 15
145
+
146
+ expect(tree.select_before(5).to_a)
147
+ .to match_array([[1, 11], [2, 32], [5, 90]])
148
+ end
149
+
150
+ it 'return correct tree if one target' do
151
+ tree[100] = 15
152
+ tree[46] = 8
153
+ tree[5] = 90
154
+
155
+ expect(tree.select_before(5).to_a)
156
+ .to match_array([[5, 90]])
157
+ end
158
+
159
+ it 'return empty tree if no targets' do
160
+ tree[100] = 15
161
+ tree[46] = 8
162
+
163
+ expect(tree.select_before(5).to_a)
164
+ .to match_array([])
165
+ end
166
+ end
167
+
168
+ describe "select_after" do
169
+ it "respond to" do
170
+ expect(tree).to respond_to(:select_after)
171
+ end
172
+
173
+ it 'return expected collection' do
174
+ tree[1] = 11
175
+ tree[5] = 90
176
+ tree[2] = 32
177
+ tree[100] = 15
178
+ tree[46] = 8
179
+
180
+ expect(tree.select_after(5).to_a)
181
+ .to match_array([[5, 90], [46, 8], [100, 15]])
182
+ end
183
+
184
+ it 'return correct tree if one target' do
185
+ tree[3] = 15
186
+ tree[4] = 8
187
+ tree[5] = 90
188
+
189
+ expect(tree.select_after(5).to_a)
190
+ .to match_array([[5, 90]])
191
+ end
192
+
193
+ it 'return empty tree if no targets' do
194
+ tree[1] = 11
195
+ tree[2] = 32
196
+
197
+ expect(tree.select_after(5).to_a)
198
+ .to match_array([])
199
+ end
200
+ end
201
+
202
+ describe "select_between" do
203
+ xit "respond to" do
204
+ expect(tree).to respond_to(:select_between)
205
+ end
206
+ end
207
+
208
+ end
117
209
  end
118
210
  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.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Feodorov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-11 00:00:00.000000000 Z
11
+ date: 2022-09-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby bindings to GTree balanced binary tree from GLib library.
14
14
  email:
@@ -29,8 +29,12 @@ files:
29
29
  - ext/native_btree/constructor.c
30
30
  - ext/native_btree/conversion.c
31
31
  - ext/native_btree/extconf_cmake.rb
32
+ - ext/native_btree/glib2_68/CMakeLists.txt
33
+ - ext/native_btree/glib2_68/additional_iterators.c
34
+ - ext/native_btree/glib_module.c
32
35
  - ext/native_btree/include/common.h
33
36
  - ext/native_btree/include/comparator.h
37
+ - ext/native_btree/include/glib_module.h
34
38
  - ext/native_btree/include/iterators.h
35
39
  - ext/native_btree/include/native_btree.h
36
40
  - ext/native_btree/include/rbtree_type.h
@@ -47,6 +51,7 @@ files:
47
51
  - spec/native_btree_class_spec.rb
48
52
  - spec/native_btree_conversion_spec.rb
49
53
  - spec/native_btree_instance_spec.rb
54
+ - spec/native_btree_int_instance_spec.rb
50
55
  - spec/native_btree_iterators_spec.rb
51
56
  - spec/native_btree_module_spec.rb
52
57
  - spec/native_btree_search_spec.rb