[runtime] Move eglib into mono/eglib so it becomes a convenience library similar...
[mono.git] / mono / eglib / gslist.c
diff --git a/mono/eglib/gslist.c b/mono/eglib/gslist.c
new file mode 100644 (file)
index 0000000..5baa297
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * gslist.c: Singly-linked list implementation
+ *
+ * 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
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * (C) 2006 Novell, Inc.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+
+GSList*
+g_slist_alloc (void)
+{
+       return g_new0 (GSList, 1);
+}
+
+void
+g_slist_free_1 (GSList *list)
+{
+       g_free (list);
+}
+
+GSList*
+g_slist_append (GSList *list, gpointer data)
+{
+       return g_slist_concat (list, g_slist_prepend (NULL, data));
+}
+
+/* This is also a list node constructor. */
+GSList*
+g_slist_prepend (GSList *list, gpointer data)
+{
+       GSList *head = g_slist_alloc ();
+       head->data = data;
+       head->next = list;
+
+       return head;
+}
+
+/*
+ * Insert the given data in a new node after the current node. 
+ * Return new node.
+ */
+static inline GSList *
+insert_after (GSList *list, gpointer data)
+{
+       list->next = g_slist_prepend (list->next, data);
+       return list->next;
+}
+
+/*
+ * Return the node prior to the node containing 'data'.
+ * If the list is empty, or the first node contains 'data', return NULL.
+ * If no node contains 'data', return the last node.
+ */
+static inline GSList*
+find_prev (GSList *list, gconstpointer data)
+{
+       GSList *prev = NULL;
+       while (list) {
+               if (list->data == data)
+                       break;
+               prev = list;
+               list = list->next;
+       }
+       return prev;
+}
+
+/* like 'find_prev', but searches for node 'link' */
+static inline GSList*
+find_prev_link (GSList *list, GSList *link)
+{
+       GSList *prev = NULL;
+       while (list) {
+               if (list == link)
+                       break;
+               prev = list;
+               list = list->next;
+       }
+       return prev;
+}
+
+GSList*
+g_slist_insert_before (GSList *list, GSList *sibling, gpointer data)
+{
+       GSList *prev = find_prev_link (list, sibling);
+
+       if (!prev)
+               return g_slist_prepend (list, data);
+
+       insert_after (prev, data);
+       return list;
+}
+
+void
+g_slist_free (GSList *list)
+{
+       while (list) {
+               GSList *next = list->next;
+               g_slist_free_1 (list);
+               list = next;
+       }
+}
+
+GSList*
+g_slist_copy (GSList *list)
+{
+       GSList *copy, *tmp;
+
+       if (!list)
+               return NULL;
+
+       copy = g_slist_prepend (NULL, list->data);
+       tmp = copy;
+
+       for (list = list->next; list; list = list->next)
+               tmp = insert_after (tmp, list->data);
+
+       return copy;
+}
+
+GSList*
+g_slist_concat (GSList *list1, GSList *list2)
+{
+       if (!list1)
+               return list2;
+
+       g_slist_last (list1)->next = list2;
+       return list1;
+}
+
+void
+g_slist_foreach (GSList *list, GFunc func, gpointer user_data)
+{
+       while (list) {
+               (*func) (list->data, user_data);
+               list = list->next;
+       }
+}
+
+GSList*
+g_slist_last (GSList *list)
+{
+       if (!list)
+               return NULL;
+
+       while (list->next)
+               list = list->next;
+
+       return list;
+}
+
+GSList*
+g_slist_find (GSList *list, gconstpointer data)
+{
+       for (; list; list = list->next)
+               if (list->data == data)
+                       break;
+       return list;
+}
+
+GSList *
+g_slist_find_custom (GSList *list, gconstpointer data, GCompareFunc func)
+{
+       if (!func)
+               return NULL;
+       
+       while (list) {
+               if (func (list->data, data) == 0)
+                       return list;
+               
+               list = list->next;
+       }
+       
+       return NULL;
+}
+
+guint
+g_slist_length (GSList *list)
+{
+       guint length = 0;
+
+       while (list) {
+               length ++;
+               list = list->next;
+       }
+
+       return length;
+}
+
+GSList*
+g_slist_remove (GSList *list, gconstpointer data)
+{
+       GSList *prev = find_prev (list, data);
+       GSList *current = prev ? prev->next : list;
+
+       if (current) {
+               if (prev)
+                       prev->next = current->next;
+               else
+                       list = current->next;
+               g_slist_free_1 (current);
+       }
+
+       return list;
+}
+
+GSList*
+g_slist_remove_all (GSList *list, gconstpointer data)
+{
+       GSList *next = list;
+       GSList *prev = NULL;
+       GSList *current;
+
+       while (next) {
+               GSList *tmp_prev = find_prev (next, data);
+               if (tmp_prev)
+                       prev = tmp_prev;
+               current = prev ? prev->next : list;
+
+               if (!current)
+                       break;
+
+               next = current->next;
+
+               if (prev)
+                       prev->next = next;
+               else
+                       list = next;
+               g_slist_free_1 (current);
+       }
+
+       return list;
+}
+
+GSList*
+g_slist_remove_link (GSList *list, GSList *link)
+{
+       GSList *prev = find_prev_link (list, link);
+       GSList *current = prev ? prev->next : list;
+
+       if (current) {
+               if (prev)
+                       prev->next = current->next;
+               else
+                       list = current->next;
+               current->next = NULL;
+       }
+
+       return list;
+}
+
+GSList*
+g_slist_delete_link (GSList *list, GSList *link)
+{
+       list = g_slist_remove_link (list, link);
+       g_slist_free_1 (link);
+
+       return list;
+}
+
+GSList*
+g_slist_reverse (GSList *list)
+{
+       GSList *prev = NULL;
+       while (list){
+               GSList *next = list->next;
+               list->next = prev;
+               prev = list;
+               list = next;
+       }
+
+       return prev;
+}
+
+GSList*
+g_slist_insert_sorted (GSList *list, gpointer data, GCompareFunc func)
+{
+       GSList *prev = NULL;
+       
+       if (!func)
+               return list;
+
+       if (!list || func (list->data, data) > 0)
+               return g_slist_prepend (list, data);
+
+       /* Invariant: func (prev->data, data) <= 0) */
+       for (prev = list; prev->next; prev = prev->next)
+               if (func (prev->next->data, data) > 0)
+                       break;
+
+       /* ... && (prev->next == 0 || func (prev->next->data, data) > 0)) */
+       insert_after (prev, data);
+       return list;
+}
+
+gint
+g_slist_index (GSList *list, gconstpointer data)
+{
+       gint index = 0;
+       
+       while (list) {
+               if (list->data == data)
+                       return index;
+               
+               index++;
+               list = list->next;
+       }
+       
+       return -1;
+}
+
+GSList*
+g_slist_nth (GSList *list, guint n)
+{
+       for (; list; list = list->next) {
+               if (n == 0)
+                       break;
+               n--;
+       }
+       return list;
+}
+
+gpointer
+g_slist_nth_data (GSList *list, guint n)
+{
+       GSList *node = g_slist_nth (list, n);
+       return node ? node->data : NULL;
+}
+
+typedef GSList list_node;
+#include "sort.frag.h"
+
+GSList*
+g_slist_sort (GSList *list, GCompareFunc func)
+{
+       if (!list || !list->next)
+               return list;
+       return do_sort (list, func);
+}