native_btree 0.3.0 → 0.4.0

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