Add a search_atleast operation.
authorBruno Haible <bruno@clisp.org>
Wed, 4 Oct 2006 17:28:15 +0000 (17:28 +0000)
committerBruno Haible <bruno@clisp.org>
Wed, 4 Oct 2006 17:28:15 +0000 (17:28 +0000)
lib/ChangeLog
lib/gl_anytree_oset.h
lib/gl_array_oset.c
lib/gl_avltree_oset.c
lib/gl_oset.c
lib/gl_oset.h
lib/gl_rbtree_oset.c

index 6f39cdb..e8ab808 100644 (file)
@@ -1,3 +1,16 @@
+2006-10-03  Bruno Haible  <bruno@clisp.org>
+
+       * gl_oset.h (gl_setelement_threshold_fn): New type.
+       (gl_oset_search_atleast): New declaration.
+       (struct gl_oset_implementation): Add field 'search_atleast'.
+       (gl_oset_search_atleast): New inline function.
+       * gl_oset.c (gl_oset_search_atleast): New function.
+       * gl_array_oset.c (gl_array_search_atleast): New function.
+       (gl_array_oset_implementation): Update.
+       * gl_anytree_oset.h (gl_tree_search_atleast): New function.
+       * gl_avltree_oset.c (gl_avltree_oset_implementation): Update.
+       * gl_rbtree_oset.c (gl_rbtree_oset_implementation): Update.
+
 2006-10-04  Jim Meyering  <jim@meyering.net>
 
        * fts.c (fts_open): Tiny comment change.
index 6ac07e4..53c8775 100644 (file)
@@ -73,6 +73,41 @@ gl_tree_search (gl_oset_t set, const void *elt)
   return false;
 }
 
+static bool
+gl_tree_search_atleast (gl_oset_t set,
+                       gl_setelement_threshold_fn threshold_fn,
+                       const void *threshold,
+                       const void **eltp)
+{
+  gl_oset_node_t node;
+
+  for (node = set->root; node != NULL; )
+    {
+      if (! threshold_fn (node->value, threshold))
+       node = node->right;
+      else
+       {
+         /* We have an element >= VALUE.  But we need the leftmost such
+            element.  */
+         gl_oset_node_t found = node;
+         node = node->left;
+         for (; node != NULL; )
+           {
+             if (! threshold_fn (node->value, threshold))
+               node = node->right;
+             else
+               {
+                 found = node;
+                 node = node->left;
+               }
+           }
+         *eltp = found;
+         return true;
+       }
+    }
+  return false;
+}
+
 static gl_oset_node_t
 gl_tree_search_node (gl_oset_t set, const void *elt)
 {
index 6a227b0..a6fdb06 100644 (file)
@@ -105,6 +105,56 @@ gl_array_search (gl_oset_t set, const void *elt)
   return gl_array_indexof (set, elt) != (size_t)(-1);
 }
 
+static bool
+gl_array_search_atleast (gl_oset_t set,
+                        gl_setelement_threshold_fn threshold_fn,
+                        const void *threshold,
+                        const void **eltp)
+{
+  size_t count = set->count;
+
+  if (count > 0)
+    {
+      size_t low = 0;
+      size_t high = count;
+
+      /* At each loop iteration, low < high; for indices < low the values are
+        smaller than THRESHOLD; for indices >= high the values are nonexistent.
+        So, if an element >= THRESHOLD occurs in the list, it is at
+        low <= position < high.  */
+      do
+       {
+         size_t mid = low + (high - low) / 2; /* low <= mid < high */
+
+         if (! threshold_fn (set->elements[mid], threshold))
+           low = mid + 1;
+         else
+           {
+             /* We have an element >= THRESHOLD at index MID.  But we need the
+                minimal such index.  */
+             high = mid;
+             /* At each loop iteration, low <= high and
+                  compar (list->elements[high], value) >= 0,
+                and we know that the first occurrence of the element is at
+                low <= position <= high.  */
+             while (low < high)
+               {
+                 size_t mid2 = low + (high - low) / 2; /* low <= mid2 < high */
+
+                 if (! threshold_fn (set->elements[mid2], threshold))
+                   low = mid2 + 1;
+                 else
+                   high = mid2;
+               }
+             *eltp = set->elements[low];
+             return true;
+           }
+       }
+      while (low < high);
+    }
+  return false;
+}
+
 /* Ensure that set->allocated > set->count.  */
 static void
 grow (gl_oset_t set)
@@ -273,6 +323,7 @@ const struct gl_oset_implementation gl_array_oset_implementation =
     gl_array_create_empty,
     gl_array_size,
     gl_array_search,
+    gl_array_search_atleast,
     gl_array_add,
     gl_array_remove,
     gl_array_free,
index ac1185c..db02ab8 100644 (file)
@@ -565,6 +565,7 @@ const struct gl_oset_implementation gl_avltree_oset_implementation =
     gl_tree_create_empty,
     gl_tree_size,
     gl_tree_search,
+    gl_tree_search_atleast,
     gl_tree_add,
     gl_tree_remove,
     gl_tree_oset_free,
index 69ae2b6..83f964e 100644 (file)
@@ -47,6 +47,15 @@ gl_oset_search (gl_oset_t set, const void *elt)
 }
 
 bool
+gl_oset_search_atleast (gl_oset_t set,
+                       gl_setelement_threshold_fn threshold_fn,
+                       const void *threshold, const void **eltp)
+{
+  return ((const struct gl_oset_impl_base *) set)->vtable
+        ->search_atleast (set, threshold_fn, threshold, eltp);
+}
+
+bool
 gl_oset_add (gl_oset_t set, const void *elt)
 {
   return ((const struct gl_oset_impl_base *) set)->vtable->add (set, elt);
index 6c5d5eb..2a67994 100644 (file)
@@ -59,6 +59,7 @@ extern "C" {
    gl_oset_add                 O(n)   O(log n)
    gl_oset_remove              O(n)   O(log n)
    gl_oset_search            O(log n) O(log n)
+   gl_oset_search_atleast    O(log n) O(log n)
    gl_oset_iterator            O(1)   O(log n)
    gl_oset_iterator_next       O(1)   O(log n)
  */
@@ -69,6 +70,10 @@ extern "C" {
    NULL denotes pointer comparison.  */
 typedef int (*gl_setelement_compar_fn) (const void *elt1, const void *elt2);
 
+/* Type of function used to compare an element with a threshold.
+   Return true if the element is greater or equal than the threshold.  */
+typedef bool (*gl_setelement_threshold_fn) (const void *elt, const void *threshold);
+
 struct gl_oset_impl;
 /* Type representing an entire ordered set.  */
 typedef struct gl_oset_impl * gl_oset_t;
@@ -90,6 +95,16 @@ extern size_t gl_oset_size (gl_oset_t set);
    Return true if found, or false if not present in the set.  */
 extern bool gl_oset_search (gl_oset_t set, const void *elt);
 
+/* Search the least element in the ordered set that compares greater or equal
+   to the given THRESHOLD.  The representation of the THRESHOLD is defined
+   by the THRESHOLD_FN.
+   Return true and store the found element in *ELTP if found, otherwise return
+   false.  */
+extern bool gl_oset_search_atleast (gl_oset_t set,
+                                   gl_setelement_threshold_fn threshold_fn,
+                                   const void *threshold,
+                                   const void **eltp);
+
 /* Add an element to an ordered set.
    Return true if it was not already in the set and added.  */
 extern bool gl_oset_add (gl_oset_t set, const void *elt);
@@ -143,6 +158,9 @@ struct gl_oset_implementation
                             gl_setelement_compar_fn compar_fn);
   size_t (*size) (gl_oset_t set);
   bool (*search) (gl_oset_t set, const void *elt);
+  bool (*search_atleast) (gl_oset_t set,
+                         gl_setelement_threshold_fn threshold_fn,
+                         const void *threshold, const void **eltp);
   bool (*add) (gl_oset_t set, const void *elt);
   bool (*remove) (gl_oset_t set, const void *elt);
   void (*oset_free) (gl_oset_t set);
@@ -186,6 +204,16 @@ gl_oset_search (gl_oset_t set, const void *elt)
   return ((const struct gl_oset_impl_base *) set)->vtable->search (set, elt);
 }
 
+# define gl_oset_search_atleast gl_oset_search_atleast_inline
+static inline bool
+gl_oset_search_atleast (gl_oset_t set,
+                       gl_setelement_threshold_fn threshold_fn,
+                       const void *threshold, const void **eltp)
+{
+  return ((const struct gl_oset_impl_base *) set)->vtable
+        ->search_atleast (set, threshold_fn, threshold, eltp);
+}
+
 # define gl_oset_add gl_oset_add_inline
 static inline bool
 gl_oset_add (gl_oset_t set, const void *elt)
index 12c8632..78636d6 100644 (file)
@@ -796,6 +796,7 @@ const struct gl_oset_implementation gl_rbtree_oset_implementation =
     gl_tree_create_empty,
     gl_tree_size,
     gl_tree_search,
+    gl_tree_search_atleast,
     gl_tree_add,
     gl_tree_remove,
     gl_tree_oset_free,