[glib: 2/4] GTree: add an ability to iterate over a tree and a node-based API




commit 2e7931c760c0a6380ad566884dad464d217882d4
Author: Maciej S. Szmigiero <maciej szmigiero oracle com>
Date:   Tue Aug 4 21:31:36 2020 +0200

    GTree: add an ability to iterate over a tree and a node-based API
    
    The basic API that this commit adds allows in-order iterating over a GTree.
    
    For this the following API were implemented or exported:
    1) Returning the first or the last node in the tree,
    
    2) Taking a pointer to a node in the tree and returning the previous or the
    next in-order node,
    
    3) Allowing to do a binary search for a particular key value and returning
    the pointer to its node,
    
    4) Returning the newly inserted or set node from both insert and replace
    functions, so this node is immediately available and does not have to be
    looked up,
    
    5) Traversing the tree in-order providing a node pointer to the
    caller-provided traversal function.
    
    Most of the above functions were already present in the code, but they
    returned the value that is stored at a particular node instead of the
    pointer to the node itself.
    
    So most of the code for these new API calls is shared with these existing
    ones, just adapted to return the pointer to the node.
    
    Additionally, the so called "lower bound" and "upper bound" operations
    were implemented.
    
    The first one returns the first element that is greater than or equal to
    the searched key, while the second returns the first element that is
    strictly greater than the searched key.
    
    Signed-off-by: Maciej S. Szmigiero <maciej szmigiero oracle com>

 docs/reference/glib/glib-sections.txt |  15 ++
 glib/gtree.c                          | 451 ++++++++++++++++++++++++++++++----
 glib/gtree.h                          |  62 +++++
 3 files changed, 483 insertions(+), 45 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 39a4e1401..598b0366b 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2982,21 +2982,36 @@ g_bytes_get_type
 <TITLE>Balanced Binary Trees</TITLE>
 <FILE>trees-binary</FILE>
 GTree
+GTreeNode
 g_tree_new
 g_tree_ref
 g_tree_unref
 g_tree_new_with_data
 g_tree_new_full
+g_tree_node_first
+g_tree_node_last
+g_tree_node_previous
+g_tree_node_next
+g_tree_insert_node
 g_tree_insert
+g_tree_replace_node
 g_tree_replace
+g_tree_node_key
+g_tree_node_value
 g_tree_nnodes
 g_tree_height
+g_tree_lookup_node
 g_tree_lookup
 g_tree_lookup_extended
+g_tree_foreach_node
 g_tree_foreach
 g_tree_traverse
 GTraverseFunc
+GTraverseNodeFunc
+g_tree_search_node
 g_tree_search
+g_tree_lower_bound
+g_tree_upper_bound
 g_tree_remove
 g_tree_steal
 g_tree_destroy
diff --git a/glib/gtree.c b/glib/gtree.c
index 715863372..94842ac92 100644
--- a/glib/gtree.c
+++ b/glib/gtree.c
@@ -68,8 +68,6 @@
 
 #define MAX_GTREE_HEIGHT 40
 
-typedef struct _GTreeNode  GTreeNode;
-
 /**
  * GTree:
  *
@@ -102,10 +100,10 @@ struct _GTreeNode
 
 static GTreeNode* g_tree_node_new                   (gpointer       key,
                                                      gpointer       value);
-static void       g_tree_insert_internal            (GTree         *tree,
-                                                     gpointer       key,
-                                                     gpointer       value,
-                                                     gboolean       replace);
+static GTreeNode *g_tree_insert_internal (GTree *tree,
+                                          gpointer key,
+                                          gpointer value,
+                                          gboolean replace);
 static gboolean   g_tree_remove_internal            (GTree         *tree,
                                                      gconstpointer  key,
                                                      gboolean       steal);
@@ -121,9 +119,9 @@ static gint       g_tree_node_in_order              (GTreeNode     *node,
 static gint       g_tree_node_post_order            (GTreeNode     *node,
                                                      GTraverseFunc  traverse_func,
                                                      gpointer       data);
-static gpointer   g_tree_node_search                (GTreeNode     *node,
-                                                     GCompareFunc   search_func,
-                                                     gconstpointer  data);
+static GTreeNode *g_tree_node_search (GTreeNode *node,
+                                      GCompareFunc search_func,
+                                      gconstpointer data);
 static GTreeNode* g_tree_node_rotate_left           (GTreeNode     *node);
 static GTreeNode* g_tree_node_rotate_right          (GTreeNode     *node);
 #ifdef G_TREE_DEBUG
@@ -228,11 +226,24 @@ g_tree_new_full (GCompareDataFunc key_compare_func,
   return tree;
 }
 
-static inline GTreeNode *
-g_tree_first_node (GTree *tree)
+/**
+ * g_tree_node_first:
+ * @tree: a #GTree
+ *
+ * Returns the first in-order node of the tree, or %NULL
+ * for an empty tree.
+ *
+ * Returns: (nullable) (transfer none): the first node in the tree
+ *
+ * Since: 2.68
+ */
+GTreeNode *
+g_tree_node_first (GTree *tree)
 {
   GTreeNode *tmp;
 
+  g_return_val_if_fail (tree != NULL, NULL);
+
   if (!tree->root)
     return NULL;
 
@@ -242,13 +253,55 @@ g_tree_first_node (GTree *tree)
     tmp = tmp->left;
 
   return tmp;
-} 
+}
+
+/**
+ * g_tree_node_last:
+ * @tree: a #GTree
+ *
+ * Returns the last in-order node of the tree, or %NULL
+ * for an empty tree.
+ *
+ * Returns: (nullable) (transfer none): the last node in the tree
+ *
+ * Since: 2.68
+ */
+GTreeNode *
+g_tree_node_last (GTree *tree)
+{
+  GTreeNode *tmp;
+
+  g_return_val_if_fail (tree != NULL, NULL);
+
+  if (!tree->root)
+    return NULL;
+
+  tmp = tree->root;
+
+  while (tmp->right_child)
+    tmp = tmp->right;
+
+  return tmp;
+}
 
-static inline GTreeNode *
+/**
+ * g_tree_node_previous
+ * @node: a #GTree node
+ *
+ * Returns the previous in-order node of the tree, or %NULL
+ * if the passed node was already the first one.
+ *
+ * Returns: (nullable) (transfer none): the previous node in the tree
+ *
+ * Since: 2.68
+ */
+GTreeNode *
 g_tree_node_previous (GTreeNode *node)
 {
   GTreeNode *tmp;
 
+  g_return_val_if_fail (node != NULL, NULL);
+
   tmp = node->left;
 
   if (node->left_child)
@@ -258,11 +311,24 @@ g_tree_node_previous (GTreeNode *node)
   return tmp;
 }
 
-static inline GTreeNode *
+/**
+ * g_tree_node_next
+ * @node: a #GTree node
+ *
+ * Returns the next in-order node of the tree, or %NULL
+ * if the passed node was already the last one.
+ *
+ * Returns: (nullable) (transfer none): the next node in the tree
+ *
+ * Since: 2.68
+ */
+GTreeNode *
 g_tree_node_next (GTreeNode *node)
 {
   GTreeNode *tmp;
 
+  g_return_val_if_fail (node != NULL, NULL);
+
   tmp = node->right;
 
   if (node->right_child)
@@ -280,7 +346,7 @@ g_tree_remove_all (GTree *tree)
 
   g_return_if_fail (tree != NULL);
 
-  node = g_tree_first_node (tree);
+  node = g_tree_node_first (tree);
 
   while (node)
     {
@@ -378,7 +444,7 @@ g_tree_destroy (GTree *tree)
 }
 
 /**
- * g_tree_insert:
+ * g_tree_insert_node:
  * @tree: a #GTree
  * @key: the key to insert
  * @value: the value corresponding to the key
@@ -396,28 +462,55 @@ g_tree_destroy (GTree *tree)
  * The cost of maintaining a balanced tree while inserting new key/value
  * result in a O(n log(n)) operation where most of the other operations
  * are O(log(n)).
+ *
+ * Returns: (transfer none): the inserted (or set) node.
+ *
+ * Since: 2.68
  */
-void
-g_tree_insert (GTree    *tree,
-               gpointer  key,
-               gpointer  value)
+GTreeNode *
+g_tree_insert_node (GTree    *tree,
+                    gpointer  key,
+                    gpointer  value)
 {
-  g_return_if_fail (tree != NULL);
+  GTreeNode *node;
 
-  g_tree_insert_internal (tree, key, value, FALSE);
+  g_return_val_if_fail (tree != NULL, NULL);
+
+  node = g_tree_insert_internal (tree, key, value, FALSE);
 
 #ifdef G_TREE_DEBUG
   g_tree_node_check (tree->root);
 #endif
+
+  return node;
 }
 
 /**
- * g_tree_replace:
+ * g_tree_insert:
  * @tree: a #GTree
  * @key: the key to insert
  * @value: the value corresponding to the key
  * 
- * Inserts a new key and value into a #GTree similar to g_tree_insert().
+ * Inserts a key/value pair into a #GTree.
+ *
+ * Inserts a new key and value into a #GTree as g_tree_insert_node() does,
+ * only this function does not return the inserted or set node.
+ */
+void
+g_tree_insert (GTree    *tree,
+               gpointer  key,
+               gpointer  value)
+{
+  g_tree_insert_node (tree, key, value);
+}
+
+/**
+ * g_tree_replace_node:
+ * @tree: a #GTree
+ * @key: the key to insert
+ * @value: the value corresponding to the key
+ *
+ * Inserts a new key and value into a #GTree similar to g_tree_insert_node().
  * The difference is that if the key already exists in the #GTree, it gets 
  * replaced by the new key. If you supplied a @value_destroy_func when 
  * creating the #GTree, the old value is freed using that function. If you 
@@ -426,39 +519,64 @@ g_tree_insert (GTree    *tree,
  *
  * The tree is automatically 'balanced' as new key/value pairs are added,
  * so that the distance from the root to every leaf is as small as possible.
+ *
+ * Returns: (transfer none): the inserted (or set) node.
+ *
+ * Since: 2.68
  */
-void
-g_tree_replace (GTree    *tree,
-                gpointer  key,
-                gpointer  value)
+GTreeNode *
+g_tree_replace_node (GTree    *tree,
+                     gpointer  key,
+                     gpointer  value)
 {
-  g_return_if_fail (tree != NULL);
+  GTreeNode *node;
 
-  g_tree_insert_internal (tree, key, value, TRUE);
+  g_return_val_if_fail (tree != NULL, NULL);
+
+  node = g_tree_insert_internal (tree, key, value, TRUE);
 
 #ifdef G_TREE_DEBUG
   g_tree_node_check (tree->root);
 #endif
+
+  return node;
+}
+
+/**
+ * g_tree_replace:
+ * @tree: a #GTree
+ * @key: the key to insert
+ * @value: the value corresponding to the key
+ *
+ * Inserts a new key and value into a #GTree as g_tree_replace_node() does,
+ * only this function does not return the inserted or set node.
+ */
+void
+g_tree_replace (GTree    *tree,
+                gpointer  key,
+                gpointer  value)
+{
+  g_tree_replace_node (tree, key, value);
 }
 
 /* internal insert routine */
-static void
+static GTreeNode *
 g_tree_insert_internal (GTree    *tree,
                         gpointer  key,
                         gpointer  value,
                         gboolean  replace)
 {
-  GTreeNode *node;
+  GTreeNode *node, *retnode;
   GTreeNode *path[MAX_GTREE_HEIGHT];
   int idx;
 
-  g_return_if_fail (tree != NULL);
+  g_return_val_if_fail (tree != NULL, NULL);
 
   if (!tree->root)
     {
       tree->root = g_tree_node_new (key, value);
       tree->nnodes++;
-      return;
+      return tree->root;
     }
 
   idx = 0;
@@ -490,7 +608,7 @@ g_tree_insert_internal (GTree    *tree,
                 tree->key_destroy_func (key);
             }
 
-          return;
+          return node;
         }
       else if (cmp < 0)
         {
@@ -511,6 +629,7 @@ g_tree_insert_internal (GTree    *tree,
 
               tree->nnodes++;
 
+              retnode = child;
               break;
             }
         }
@@ -533,6 +652,7 @@ g_tree_insert_internal (GTree    *tree,
 
               tree->nnodes++;
 
+              retnode = child;
               break;
             }
         }
@@ -569,6 +689,8 @@ g_tree_insert_internal (GTree    *tree,
 
       node = bparent;
     }
+
+  return retnode;
 }
 
 /**
@@ -844,6 +966,65 @@ g_tree_remove_internal (GTree         *tree,
   return TRUE;
 }
 
+/**
+ * g_tree_node_key:
+ * @node: a #GTree node
+ *
+ * Gets the key stored at a particular tree node.
+ *
+ * Returns: (nullable) (transfer none): the key at the node.
+ *
+ * Since: 2.68
+ */
+gpointer
+g_tree_node_key (GTreeNode *node)
+{
+  g_return_val_if_fail (node != NULL, NULL);
+
+  return node->key;
+}
+
+/**
+ * g_tree_node_value:
+ * @node: a #GTree node
+ *
+ * Gets the value stored at a particular tree node.
+ *
+ * Returns: (nullable) (transfer none): the value at the node.
+ *
+ * Since: 2.68
+ */
+gpointer
+g_tree_node_value (GTreeNode *node)
+{
+  g_return_val_if_fail (node != NULL, NULL);
+
+  return node->value;
+}
+
+/**
+ * g_tree_lookup_node:
+ * @tree: a #GTree
+ * @key: the key to look up
+ *
+ * Gets the tree node corresponding to the given key. Since a #GTree is
+ * automatically balanced as key/value pairs are added, key lookup
+ * is O(log n) (where n is the number of key/value pairs in the tree).
+ *
+ * Returns: (nullable) (transfer none): the tree node corresponding to
+ *          the key, or %NULL if the key was not found
+ *
+ * Since: 2.68
+ */
+GTreeNode *
+g_tree_lookup_node (GTree         *tree,
+                    gconstpointer  key)
+{
+  g_return_val_if_fail (tree != NULL, NULL);
+
+  return g_tree_find_node (tree, key);
+}
+
 /**
  * g_tree_lookup:
  * @tree: a #GTree
@@ -862,10 +1043,8 @@ g_tree_lookup (GTree         *tree,
 {
   GTreeNode *node;
 
-  g_return_val_if_fail (tree != NULL, NULL);
+  node = g_tree_lookup_node (tree, key);
 
-  node = g_tree_find_node (tree, key);
-  
   return node ? node->value : NULL;
 }
 
@@ -935,8 +1114,8 @@ g_tree_foreach (GTree         *tree,
   if (!tree->root)
     return;
 
-  node = g_tree_first_node (tree);
-  
+  node = g_tree_node_first (tree);
+
   while (node)
     {
       if ((*func) (node->key, node->value, user_data))
@@ -946,6 +1125,47 @@ g_tree_foreach (GTree         *tree,
     }
 }
 
+/**
+ * g_tree_foreach_node:
+ * @tree: a #GTree
+ * @func: the function to call for each node visited.
+ *     If this function returns %TRUE, the traversal is stopped.
+ * @user_data: user data to pass to the function
+ *
+ * Calls the given function for each of the nodes in the #GTree.
+ * The function is passed the pointer to the particular node, and the given
+ * @data parameter. The tree traversal happens in-order.
+ *
+ * The tree may not be modified while iterating over it (you can't
+ * add/remove items). To remove all items matching a predicate, you need
+ * to add each item to a list in your #GTraverseFunc as you walk over
+ * the tree, then walk the list and remove each item.
+ *
+ * Since: 2.68
+ */
+void
+g_tree_foreach_node (GTree             *tree,
+                     GTraverseNodeFunc  func,
+                     gpointer           user_data)
+{
+  GTreeNode *node;
+
+  g_return_if_fail (tree != NULL);
+
+  if (!tree->root)
+    return;
+
+  node = g_tree_node_first (tree);
+
+  while (node)
+    {
+      if ((*func) (node, user_data))
+        break;
+
+      node = g_tree_node_next (node);
+    }
+}
+
 /**
  * g_tree_traverse:
  * @tree: a #GTree
@@ -1006,6 +1226,40 @@ g_tree_traverse (GTree         *tree,
     }
 }
 
+/**
+ * g_tree_search_node:
+ * @tree: a #GTree
+ * @search_func: a function used to search the #GTree
+ * @user_data: the data passed as the second argument to @search_func
+ *
+ * Searches a #GTree using @search_func.
+ *
+ * The @search_func is called with a pointer to the key of a key/value
+ * pair in the tree, and the passed in @user_data. If @search_func returns
+ * 0 for a key/value pair, then the corresponding node is returned as
+ * the result of g_tree_search(). If @search_func returns -1, searching
+ * will proceed among the key/value pairs that have a smaller key; if
+ * @search_func returns 1, searching will proceed among the key/value
+ * pairs that have a larger key.
+ *
+ * Returns: (nullable) (transfer none): the node corresponding to the
+ *          found key, or %NULL if the key was not found
+ *
+ * Since: 2.68
+ */
+GTreeNode *
+g_tree_search_node (GTree         *tree,
+                    GCompareFunc   search_func,
+                    gconstpointer  user_data)
+{
+  g_return_val_if_fail (tree != NULL, NULL);
+
+  if (!tree->root)
+    return NULL;
+
+  return g_tree_node_search (tree->root, search_func, user_data);
+}
+
 /**
  * g_tree_search:
  * @tree: a #GTree
@@ -1030,12 +1284,119 @@ g_tree_search (GTree         *tree,
                GCompareFunc   search_func,
                gconstpointer  user_data)
 {
+  GTreeNode *node;
+
+  node = g_tree_search_node (tree, search_func, user_data);
+
+  return node ? node->value : NULL;
+}
+
+/**
+ * g_tree_lower_bound:
+ * @tree: a #GTree
+ * @key: the key to calculate the lower bound for
+ *
+ * Gets the lower bound node corresponding to the given key,
+ * or %NULL if the tree is empty or all the nodes in the tree
+ * have keys that are strictly lower than the searched key.
+ *
+ * The lower bound is the first node that has its key greater
+ * than or equal to the searched key.
+ *
+ * Returns: (nullable) (transfer none): the tree node corresponding to
+ *          the lower bound, or %NULL if the tree is empty or has only
+ *          keys strictly lower than the searched key.
+ *
+ * Since: 2.68
+ */
+GTreeNode *
+g_tree_lower_bound (GTree         *tree,
+                    gconstpointer  key)
+{
+  GTreeNode *node, *result;
+  gint cmp;
+
   g_return_val_if_fail (tree != NULL, NULL);
 
-  if (tree->root)
-    return g_tree_node_search (tree->root, search_func, user_data);
-  else
+  node = tree->root;
+  if (!node)
     return NULL;
+
+  result = NULL;
+  while (1)
+    {
+      cmp = tree->key_compare (key, node->key, tree->key_compare_data);
+      if (cmp <= 0)
+        {
+          result = node;
+
+          if (!node->left_child)
+            return result;
+
+          node = node->left;
+        }
+      else
+        {
+          if (!node->right_child)
+            return result;
+
+          node = node->right;
+        }
+    }
+}
+
+/**
+ * g_tree_upper_bound:
+ * @tree: a #GTree
+ * @key: the key to calculate the upper bound for
+ *
+ * Gets the upper bound node corresponding to the given key,
+ * or %NULL if the tree is empty or all the nodes in the tree
+ * have keys that are lower than or equal to the searched key.
+ *
+ * The upper bound is the first node that has its key strictly greater
+ * than the searched key.
+ *
+ * Returns: (nullable) (transfer none): the tree node corresponding to the
+ *          upper bound, or %NULL if the tree is empty or has only keys
+ *          lower than or equal to the searched key.
+ *
+ * Since: 2.68
+ */
+GTreeNode *
+g_tree_upper_bound (GTree         *tree,
+                    gconstpointer  key)
+{
+  GTreeNode *node, *result;
+  gint cmp;
+
+  g_return_val_if_fail (tree != NULL, NULL);
+
+  node = tree->root;
+  if (!node)
+    return NULL;
+
+  result = NULL;
+  while (1)
+    {
+      cmp = tree->key_compare (key, node->key, tree->key_compare_data);
+      if (cmp < 0)
+        {
+          result = node;
+
+          if (!node->left_child)
+            return result;
+
+          node = node->left;
+        }
+      else
+        {
+          if (!node->right_child)
+            return result;
+
+          node = node->right;
+        }
+    }
 }
 
 /**
@@ -1212,7 +1573,7 @@ g_tree_node_post_order (GTreeNode     *node,
   return FALSE;
 }
 
-static gpointer
+static GTreeNode *
 g_tree_node_search (GTreeNode     *node,
                     GCompareFunc   search_func,
                     gconstpointer  data)
@@ -1226,7 +1587,7 @@ g_tree_node_search (GTreeNode     *node,
     {
       dir = (* search_func) (node->key, data);
       if (dir == 0)
-        return node->value;
+        return node;
       else if (dir < 0) 
         {
           if (!node->left_child)
diff --git a/glib/gtree.h b/glib/gtree.h
index bb5c53465..19f9f7ea1 100644
--- a/glib/gtree.h
+++ b/glib/gtree.h
@@ -37,10 +37,35 @@ G_BEGIN_DECLS
 
 typedef struct _GTree  GTree;
 
+/**
+ * GTreeNode:
+ *
+ * An opaque type which identifies a specific node in a #GTree.
+ *
+ * Since: 2.68
+ */
+typedef struct _GTreeNode GTreeNode;
+
 typedef gboolean (*GTraverseFunc) (gpointer  key,
                                    gpointer  value,
                                    gpointer  data);
 
+/**
+ * GTraverseNodeFunc:
+ * @node: a #GTreeNode
+ * @data: user data passed to g_tree_foreach_node()
+ *
+ * Specifies the type of function passed to g_tree_foreach_node(). It is
+ * passed each node, together with the @user_data parameter passed to
+ * g_tree_foreach_node(). If the function returns %TRUE, the traversal is
+ * stopped.
+ *
+ * Returns: %TRUE to stop the traversal
+ * Since: 2.68
+ */
+typedef gboolean (*GTraverseNodeFunc) (GTreeNode *node,
+                                       gpointer   data);
+
 /* Balanced binary trees
  */
 GLIB_AVAILABLE_IN_ALL
@@ -53,16 +78,32 @@ GTree*   g_tree_new_full        (GCompareDataFunc  key_compare_func,
                                  gpointer          key_compare_data,
                                  GDestroyNotify    key_destroy_func,
                                  GDestroyNotify    value_destroy_func);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_node_first (GTree *tree);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_node_last (GTree *tree);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_node_previous (GTreeNode *node);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_node_next (GTreeNode *node);
 GLIB_AVAILABLE_IN_ALL
 GTree*   g_tree_ref             (GTree            *tree);
 GLIB_AVAILABLE_IN_ALL
 void     g_tree_unref           (GTree            *tree);
 GLIB_AVAILABLE_IN_ALL
 void     g_tree_destroy         (GTree            *tree);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_insert_node (GTree *tree,
+                               gpointer key,
+                               gpointer value);
 GLIB_AVAILABLE_IN_ALL
 void     g_tree_insert          (GTree            *tree,
                                  gpointer          key,
                                  gpointer          value);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_replace_node (GTree *tree,
+                                gpointer key,
+                                gpointer value);
 GLIB_AVAILABLE_IN_ALL
 void     g_tree_replace         (GTree            *tree,
                                  gpointer          key,
@@ -73,6 +114,13 @@ gboolean g_tree_remove          (GTree            *tree,
 GLIB_AVAILABLE_IN_ALL
 gboolean g_tree_steal           (GTree            *tree,
                                  gconstpointer     key);
+GLIB_AVAILABLE_IN_2_68
+gpointer g_tree_node_key (GTreeNode *node);
+GLIB_AVAILABLE_IN_2_68
+gpointer g_tree_node_value (GTreeNode *node);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_lookup_node (GTree *tree,
+                               gconstpointer key);
 GLIB_AVAILABLE_IN_ALL
 gpointer g_tree_lookup          (GTree            *tree,
                                  gconstpointer     key);
@@ -85,6 +133,10 @@ GLIB_AVAILABLE_IN_ALL
 void     g_tree_foreach         (GTree            *tree,
                                  GTraverseFunc    func,
                                  gpointer         user_data);
+GLIB_AVAILABLE_IN_2_68
+void g_tree_foreach_node (GTree *tree,
+                          GTraverseNodeFunc func,
+                          gpointer user_data);
 
 GLIB_DEPRECATED
 void     g_tree_traverse        (GTree            *tree,
@@ -92,10 +144,20 @@ void     g_tree_traverse        (GTree            *tree,
                                  GTraverseType     traverse_type,
                                  gpointer          user_data);
 
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_search_node (GTree *tree,
+                               GCompareFunc search_func,
+                               gconstpointer user_data);
 GLIB_AVAILABLE_IN_ALL
 gpointer g_tree_search          (GTree            *tree,
                                  GCompareFunc      search_func,
                                  gconstpointer     user_data);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_lower_bound (GTree *tree,
+                               gconstpointer key);
+GLIB_AVAILABLE_IN_2_68
+GTreeNode *g_tree_upper_bound (GTree *tree,
+                               gconstpointer key);
 GLIB_AVAILABLE_IN_ALL
 gint     g_tree_height          (GTree            *tree);
 GLIB_AVAILABLE_IN_ALL


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]