Merge pull request #2745 from lambdageek/dev/monoerror-sre-internals
[mono.git] / eglib / src / glist.c
index ddf50e555ac285fa0a569d839720677bf157c40e..882fda48ec9b75772bd8f780d2f1fbef9266ab54 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * glist.c: Doubly-linked list implementation
  *
- * Author:
+ * Authors:
  *   Duncan Mak (duncan@novell.com)
+ *   Raja R Harinath (rharinath@novell.com)
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -35,27 +36,33 @@ g_list_alloc ()
 }
 
 static inline GList*
-_prepend (GList *list, gpointer data)
+new_node (GList *prev, gpointer data, GList *next)
 {
-       GList *head = g_list_alloc ();
-       head->data = data;
-       head->next = list;
-
-       if (list){
-               head->prev = list->prev;
-               if (list->prev)
-                       list->prev->next = head;
-               
-               list->prev = head;
-       }
-       
-       return head;
+       GList *node = g_list_alloc ();
+       node->data = data;
+       node->prev = prev;
+       node->next = next;
+       if (prev)
+               prev->next = node;
+       if (next)
+               next->prev = node;
+       return node;
+}
+
+static inline GList*
+disconnect_node (GList *node)
+{
+       if (node->next)
+               node->next->prev = node->prev;
+       if (node->prev)
+               node->prev->next = node->next;
+       return node;
 }
 
 GList *
 g_list_prepend (GList *list, gpointer data)
 {
-       return _prepend (list, data);
+       return new_node (list ? list->prev : NULL, data, list);
 }
 
 void
@@ -77,33 +84,18 @@ g_list_free (GList *list)
 GList*
 g_list_append (GList *list, gpointer data)
 {
-       return g_list_concat (list, g_list_prepend (NULL, data));
-}
-
-static inline GList*
-_concat (GList *list1, GList *list2)
-{
-       GList *last;
-       if (!list1 && !list2)
-               return NULL;
-       
-       if (!list1)
-               return list2;
-
-       if (!list2)
-               return list1;
-
-       last = g_list_last (list1);
-       last->next = list2;
-       list2->prev = last;
-
-       return list1;
+       GList *node = new_node (g_list_last (list), data, NULL);
+       return list ? list : node;
 }
 
 GList *
 g_list_concat (GList *list1, GList *list2)
 {
-       return _concat (list1, list2);
+       if (list1 && list2) {
+               list2->prev = g_list_last (list1);
+               list2->prev->next = list2;
+       }
+       return list1 ? list1 : list2;
 }
 
 guint
@@ -122,60 +114,45 @@ g_list_length (GList *list)
 GList*
 g_list_remove (GList *list, gconstpointer data)
 {
-       GList *current;
-
-       if (!list)
-               return NULL;
-
-       if (list->data == data){
-               GList *next = list->next;
-               g_list_free_1 (list);
-               return next;
-       }
-       
-       current = list->next;
-
-       while (current){
-               if (current->data == data){
-                       current->prev->next = current->next;
-                       current->next->prev = current->prev;
+       GList *current = g_list_find (list, data);
+       if (!current)
+               return list;
 
-                       g_list_free_1 (current);
-                       break;
-               }
-               
-               current = current->next;
-       }
+       if (current == list)
+               list = list->next;
+       g_list_free_1 (disconnect_node (current));
 
        return list;
 }
 
 GList*
-g_list_remove_link (GList *list, GList *link)
+g_list_remove_all (GList *list, gconstpointer data)
 {
-       GList *current;
+       GList *current = g_list_find (list, data);
 
-       if (!list)
-               return NULL;
+       if (!current)
+               return list;
 
-       if (list == link){
-               GList *next = list->next;
-               list->next = NULL;
-               return next;
+       while (current) {
+               if (current == list)
+                       list = list->next;
+               g_list_free_1 (disconnect_node (current));
+
+               current = g_list_find (list, data);
        }
 
-       current = list->next;
+       return list;
+}
 
-       while (current){
-               if (current == link){
-                       current->prev->next = current->next;
-                       current->next->prev = current->prev;
-                       current->next = NULL;
-                       break;
-               }
+GList*
+g_list_remove_link (GList *list, GList *link)
+{
+       if (list == link)
+               list = list->next;
 
-               current = current->next;
-       }
+       disconnect_node (link);
+       link->next = NULL;
+       link->prev = NULL;
 
        return list;
 }
@@ -202,6 +179,22 @@ g_list_find (GList *list, gconstpointer data)
        return NULL;
 }
 
+GList*
+g_list_find_custom (GList *list, gconstpointer data, GCompareFunc func)
+{
+       if (!func)
+               return NULL;
+       
+       while (list) {
+               if (func (list->data, data) == 0)
+                       return list;
+               
+               list = list->next;
+       }
+       
+       return NULL;
+}
+
 GList*
 g_list_reverse (GList *list)
 {
@@ -245,47 +238,32 @@ g_list_last (GList *list)
 GList*
 g_list_insert_sorted (GList *list, gpointer data, GCompareFunc func)
 {
-       GList *current = NULL;
-       
+       GList *prev = NULL;
+       GList *current;
+       GList *node;
+
        if (!func)
                return list;
 
-       if (!list)
-               return g_list_prepend (NULL, data);
-
-       if (func (list->data, data) > 0)
-               return g_list_prepend (list, data);
-       
-       current = list->next;
-
-       while (current){
-               if (func (current->data, data) > 0){
-                       current->prev->next = g_list_prepend (current, data);
-                       break;
-               }
-
-               if (current->next == NULL){
-                       g_list_append (list, data);
+       /* Invariant: !prev || func (prev->data, data) <= 0) */
+       for (current = list; current; current = current->next) {
+               if (func (current->data, data) > 0)
                        break;
-               }
-               
-               current = current->next;
+               prev = current;
        }
 
-       return list;
+       node = new_node (prev, data, current);
+       return list == current ? node : list;
 }
 
 GList*
 g_list_insert_before (GList *list, GList *sibling, gpointer data)
 {
-       if (!list)
-               return g_list_prepend (NULL, data);
-
-       if (!sibling)
-               return g_list_append (list, data);
-
-       else 
-               return g_list_prepend (sibling, data);
+       if (sibling) {
+               GList *node = new_node (sibling->prev, data, sibling);
+               return list == sibling ? node : list;
+       }
+       return g_list_append (list, data);
 }
 
 void
@@ -297,12 +275,6 @@ g_list_foreach (GList *list, GFunc func, gpointer user_data)
        }
 }
 
-GList*
-g_list_sort (GList *list, GCompareFunc func)
-{
-       return NULL;
-}
-
 gint
 g_list_index (GList *list, gconstpointer data)
 {
@@ -322,49 +294,52 @@ g_list_index (GList *list, gconstpointer data)
 GList*
 g_list_nth (GList *list, guint n)
 {
-       guint i = n;
-       GList *value = list;
-       
-       while (i > 0){
-               if (value){
-                       value = value->next;
-                       i --;
-               } else {
-                       value = NULL;
+       for (; list; list = list->next) {
+               if (n == 0)
                        break;
-               }
+               n--;
        }
-
-       return value;
+       return list;
 }
 
 gpointer
 g_list_nth_data (GList *list, guint n)
 {
-       return g_list_nth (list, n)->data;
+       GList *node = g_list_nth (list, n);
+       return node ? node->data : NULL;
 }
 
 GList*
 g_list_copy (GList *list)
 {
-       GList *copy, *tmp;
-
-       if (!list)
-               return NULL;
+       GList *copy = NULL;
 
-       copy = g_list_prepend (NULL, list->data);
+       if (list) {
+               GList *tmp = new_node (NULL, list->data, NULL);
+               copy = tmp;
 
-       if (list->next == NULL)
-               return copy;
-       
-       tmp = copy;
-
-       while (list->next) {
-               tmp = g_list_concat (tmp, g_list_prepend (NULL, list->next->data));
-               tmp = tmp->next;
-               list = list->next;
+               for (list = list->next; list; list = list->next)
+                       tmp = new_node (tmp, list->data, NULL);
        }
 
        return copy;
 }
 
+typedef GList list_node;
+#include "sort.frag.h"
+
+GList*
+g_list_sort (GList *list, GCompareFunc func)
+{
+       GList *current;
+       if (!list || !list->next)
+               return list;
+       list = do_sort (list, func);
+
+       /* Fixup: do_sort doesn't update 'prev' pointers */
+       list->prev = NULL;
+       for (current = list; current->next; current = current->next)
+               current->next->prev = current;
+
+       return list;
+}