maint.mk: fix "release" target to build _version
[gnulib.git] / lib / gl_anytreehash_list1.h
index 45418cf..48228c5 100644 (file)
@@ -1,5 +1,5 @@
 /* Sequential list data type implemented by a hash table with a binary tree.
-   Copyright (C) 2006-2007 Free Software Foundation, Inc.
+   Copyright (C) 2006-2007, 2009-2013 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2006.
 
    This program is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@ struct gl_multiple_nodes
 #define MULTIPLE_NODES_MAGIC  (void *) -1
 
 /* Resize the hash table if needed, after list->count was incremented.  */
-static inline void
+static void
 hash_resize_after_add (gl_list_t list)
 {
   size_t count = (list->root != 0 ? list->root->branch_size : 0);
@@ -87,7 +87,7 @@ compare_position_threshold (const void *x, const void *threshold)
 }
 
 /* Return the first element of a non-empty ordered set of nodes.  */
-static inline gl_list_node_t
+static gl_list_node_t
 gl_oset_first (gl_oset_t set)
 {
   gl_oset_iterator_t iter = gl_oset_iterator (set);
@@ -101,11 +101,12 @@ gl_oset_first (gl_oset_t set)
 
 /* Add a node to the hash table structure.
    If duplicates are allowed, this function performs in average time
-   O((log n)^2): gl_oset_add may need to add an element to an ordered set of
-   size O(n), needing O(log n) comparison function calls.  The comparison
+   O((log n)^2): gl_oset_nx_add may need to add an element to an ordered set
+   of size O(n), needing O(log n) comparison function calls.  The comparison
    function is compare_by_position, which is O(log n) worst-case.
-   If duplicates are forbidden, this function is O(1).  */
-static void
+   If duplicates are forbidden, this function is O(1).
+   Return 0 upon success, -1 upon out-of-memory.  */
+static int
 add_to_bucket (gl_list_t list, gl_list_node_t new_node)
 {
   size_t bucket = new_node->h.hashcode % list->table_size;
@@ -134,8 +135,7 @@ add_to_bucket (gl_list_t list, gl_list_node_t new_node)
                     {
                       /* Found already multiple nodes with the same value.
                          Add the new_node to it.  */
-                      gl_oset_add (nodes, new_node);
-                      return;
+                      return gl_oset_nx_add (nodes, new_node);
                     }
                 }
               else
@@ -150,19 +150,30 @@ add_to_bucket (gl_list_t list, gl_list_node_t new_node)
                       struct gl_multiple_nodes *multi_entry;
 
                       nodes =
-                        gl_oset_create_empty (OSET_TREE_FLAVOR,
-                                              compare_by_position, NULL);
+                        gl_oset_nx_create_empty (OSET_TREE_FLAVOR,
+                                                 compare_by_position, NULL);
+                      if (nodes == NULL)
+                        return -1;
 
-                      gl_oset_add (nodes, node);
-                      gl_oset_add (nodes, new_node);
+                      if (gl_oset_nx_add (nodes, node) < 0)
+                        goto fail;
+                      if (gl_oset_nx_add (nodes, new_node) < 0)
+                        goto fail;
 
-                      multi_entry = XMALLOC (struct gl_multiple_nodes);
+                      multi_entry =
+                       (struct gl_multiple_nodes *) malloc (sizeof (struct gl_multiple_nodes));
+                      if (multi_entry == NULL)
+                        goto fail;
                       multi_entry->h.hash_next = entry->hash_next;
                       multi_entry->h.hashcode = entry->hashcode;
                       multi_entry->magic = MULTIPLE_NODES_MAGIC;
                       multi_entry->nodes = nodes;
                       *entryp = &multi_entry->h;
-                      return;
+                      return 0;
+
+                    fail:
+                      gl_oset_free (nodes);
+                      return -1;
                     }
                 }
             }
@@ -171,7 +182,13 @@ add_to_bucket (gl_list_t list, gl_list_node_t new_node)
   /* If no duplicates are allowed, multiple nodes are not needed.  */
   new_node->h.hash_next = list->table[bucket];
   list->table[bucket] = &new_node->h;
+  return 0;
 }
+/* Tell GCC that the likely return value is 0.  */
+#if __GNUC__ >= 3
+# define add_to_bucket(list,node) \
+    __builtin_expect ((add_to_bucket) (list, node), 0)
+#endif
 
 /* Remove a node from the hash table structure.
    If duplicates are allowed, this function performs in average time
@@ -253,8 +270,9 @@ remove_from_bucket (gl_list_t list, gl_list_node_t old_node)
 }
 
 /* Build up the hash table during initialization: Store all the nodes of
-   list->root in the hash table.  */
-static inline void
+   list->root in the hash table.
+   Return 0 upon success, -1 upon out-of-memory.  */
+static int
 add_nodes_to_buckets (gl_list_t list)
 {
   /* Iterate across all nodes.  */
@@ -278,7 +296,7 @@ add_nodes_to_buckets (gl_list_t list)
       for (;;)
         {
           if (stack_ptr == &stack[0])
-            return;
+            goto done;
           stack_ptr--;
           if (!stack_ptr->rightp)
             break;
@@ -289,10 +307,52 @@ add_nodes_to_buckets (gl_list_t list)
         (list->base.hashcode_fn != NULL
          ? list->base.hashcode_fn (node->value)
          : (size_t)(uintptr_t) node->value);
-      add_to_bucket (list, node);
+      if (add_to_bucket (list, node) < 0)
+        goto fail;
       /* Descend on right branch.  */
       stack_ptr->rightp = true;
       node = node->right;
       stack_ptr++;
     }
+ done:
+  return 0;
+
+ fail:
+  /* Undo everything.  */
+  for (;;)
+    {
+      /* Descend on left branch.  */
+      stack_ptr->rightp = false;
+      node = node->left;
+      stack_ptr++;
+      /* Descend on right branch.  */
+      for (;;)
+        {
+          if (node == NULL)
+            break;
+          stack_ptr->node = node;
+          stack_ptr->rightp = true;
+          node = node->right;
+          stack_ptr++;
+        }
+      /* Climb up again.  */
+      for (;;)
+        {
+          if (stack_ptr == &stack[0])
+            goto fail_done;
+          stack_ptr--;
+          if (stack_ptr->rightp)
+            break;
+        }
+      node = stack_ptr->node;
+      /* Remove the current node from the hash table.  */
+      remove_from_bucket (list, node);
+    }
+ fail_done:
+  return -1;
 }
+/* Tell GCC that the likely return value is 0.  */
+#if __GNUC__ >= 3
+# define add_nodes_to_buckets(list) \
+    __builtin_expect ((add_nodes_to_buckets) (list), 0)
+#endif