Jelajahi Sumber

* TODO: Remove 'List' entries.
* src/Makefile.am (libeglib_la_SOURCES): Add sort.frag.h.
* src/sort.frag.h: New. Implements a "generic" bottom-up "counting"
mergesort that works both on singly- and doubly-linked lists.
* src/gslist.c (g_slist_sort): Use it.
* src/glist.c (g_list_sort): Likewise.
* src/glib.h (g_slist_sort, g_list_sort): Declare.
* test/slist.c, test/list.c: Add basic testcases.

And, the best part: it worked on the first try after fixing syntax errors :-)

svn path=/trunk/mono/; revision=64357

Raja R Harinath 19 tahun lalu
induk
melakukan
ec647b3658
9 mengubah file dengan 247 tambahan dan 4 penghapusan
  1. 11 0
      eglib/ChangeLog
  2. 0 4
      eglib/TODO
  3. 1 0
      eglib/src/Makefile.am
  4. 4 0
      eglib/src/glib.h
  5. 18 0
      eglib/src/glist.c
  6. 11 0
      eglib/src/gslist.c
  7. 81 0
      eglib/src/sort.frag.h
  8. 63 0
      eglib/test/list.c
  9. 58 0
      eglib/test/slist.c

+ 11 - 0
eglib/ChangeLog

@@ -1,3 +1,14 @@
+2006-08-25  Raja R Harinath  <[email protected]>
+
+	* TODO: Remove 'List' entries.
+	* src/Makefile.am (libeglib_la_SOURCES): Add sort.frag.h.
+	* src/sort.frag.h: New.  Implements a "generic" bottom-up "counting"
+	mergesort that works both on singly- and doubly-linked lists.
+	* src/gslist.c (g_slist_sort): Use it.
+	* src/glist.c (g_list_sort): Likewise.
+	* src/glib.h (g_slist_sort, g_list_sort): Declare.
+	* test/slist.c, test/list.c: Add basic testcases.
+
 2006-08-25 Gonzalo Paniagua Javier <[email protected]>
 
 	* src/gspawn.c: propagate errors from reads.

+ 0 - 4
eglib/TODO

@@ -71,10 +71,6 @@ Important Groups:
 	     11 g_file_test
 	      3 g_file_open_tmp
 	
-	* List
-	      3 g_list_insert_before
-	      2 g_list_sort
-	
 	* Miscelaneous
 	      5 g_newa
 	      3 g_spaced_primes_closest

+ 1 - 0
eglib/src/Makefile.am

@@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libeglib.la
 
 libeglib_la_SOURCES = \
 	eglib-config.h	\
+	sort.frag.h	\
 	glib.h	     	\
 	garray.c	\
 	gerror.c	\

+ 4 - 0
eglib/src/glib.h

@@ -234,6 +234,8 @@ GSList *g_slist_insert_sorted (GSList        *list,
 GSList *g_slist_insert_before (GSList        *list,
 			       GSList        *sibling,
 			       gpointer       data);
+GSList *g_slist_sort          (GSList        *list,
+			       GCompareFunc   func);
 
 #define g_slist_next(slist) ((slist) ? (((GSList *) (slist))->next) : NULL)
 
@@ -283,6 +285,8 @@ GList *g_list_insert_sorted (GList         *list,
 GList *g_list_insert_before (GList         *list,
 			     GList         *sibling,
 			     gpointer       data);
+GList *g_list_sort          (GList         *sort,
+			     GCompareFunc   func);
 
 /*
  * Array

+ 18 - 0
eglib/src/glist.c

@@ -288,3 +288,21 @@ g_list_copy (GList *list)
 	return copy;
 }
 
+typedef GList *digit;
+#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;
+}

+ 11 - 0
eglib/src/gslist.c

@@ -298,3 +298,14 @@ g_slist_insert_sorted (GSList *list, gpointer data, GCompareFunc func)
 	insert_after (prev, data);
 	return list;
 }
+
+typedef GSList *digit;
+#include "sort.frag.h"
+
+GSList*
+g_slist_sort (GSList *list, GCompareFunc func)
+{
+	if (!list || !list->next)
+		return list;
+	return do_sort (list, func);	
+}

+ 81 - 0
eglib/src/sort.frag.h

@@ -0,0 +1,81 @@
+/* A "counting" merge sort that avoids recursion */
+
+#define N_DIGITS (sizeof (size_t) * 8)
+
+static inline digit
+add_digits (digit first, digit second, GCompareFunc func)
+{
+	/* merge the two lists */
+	digit list = NULL;
+	digit *pos = &list;
+	while (first && second) {
+		if (func (first->data, second->data) > 0) {
+			*pos = second;
+			second = second->next;
+		} else {
+			*pos = first;
+			first = first->next;
+		}
+		pos = &((*pos)->next);
+	}
+	*pos = first ? first : second;
+	return list;
+}
+
+static inline digit
+combine_digits (digit *digits, int max_digit, GCompareFunc func)
+{
+	int i;
+	digit list = digits [0];
+	for (i = 1; i <= max_digit; ++i)
+		list = add_digits (digit [i], list, func);
+	return list;
+}
+
+static inline int
+increment (digit *digits, digit list, int max_digit, GCompareFunc func)
+{
+	int i;
+
+	if (!list)
+		return max_digit;
+
+	for (i = 0; digits [i]; i++) {
+		list = add_digits (digits [i], list, func);
+		digits [i] = NULL;
+		if (i == N_DIGITS-1) /* Should _never_ happen, but if it does, we just devolve into quadratic ;-) */
+			break;
+	}
+	digits [i] = list;
+	return i > max_digit ? i : max_digit;
+}
+
+static inline digit
+do_sort (digit list, GCompareFunc func)
+{
+	int max_digit = 0;
+	digit digits [N_DIGITS]; /* 128 bytes on 32bit, 512 bytes on 64bit */
+	memset (digits, 0, sizeof digits);
+
+	while (list && list->next) {
+		digit next = list->next;
+		digit tail = next->next;
+
+		if (func (list->data, next->data) > 0) {
+			next->next = list;
+			next = list;
+			list = list->next;
+		}
+		next->next = NULL;
+
+		max_digit = increment (digits, list, max_digit, func);
+
+		list = tail;
+	}
+
+	max_digit = increment (digits, list, max_digit, func);
+
+	return combine_digits (digits, max_digit, func);
+}
+
+#undef N_DIGITS

+ 63 - 0
eglib/test/list.c

@@ -306,6 +306,68 @@ test_list_insert_before ()
 	return OK;
 }
 
+#define N_ELEMS 100
+
+static int intcompare (gconstpointer p1, gconstpointer p2)
+{
+	return GPOINTER_TO_INT (p1) - GPOINTER_TO_INT (p2);
+}
+
+static gboolean verify_sort (GList *list)
+{
+	list = g_list_sort (list, intcompare);
+	if (list->prev)
+		return FALSE;
+
+	int prev = GPOINTER_TO_INT (list->data);
+	for (list = list->next; list; list = list->next) {
+		int curr = GPOINTER_TO_INT (list->data);
+		if (prev > curr)
+			return FALSE;
+		prev = curr;
+
+		if (!list->prev || list->prev->next != list)
+			return FALSE;
+	}
+	return TRUE;
+}
+
+RESULT
+test_list_sort ()
+{
+	int i = 0;
+	GList *list = NULL;
+
+	for (i = 0; i < N_ELEMS; ++i)
+		list = g_list_prepend (list, GINT_TO_POINTER (i));
+	if (!verify_sort (list))
+		return FAILED ("decreasing list");
+
+	g_list_free (list);
+
+	list = NULL;
+	for (i = 0; i < N_ELEMS; ++i)
+		list = g_list_prepend (list, GINT_TO_POINTER (-i));
+	if (!verify_sort (list))
+		return FAILED ("increasing list");
+
+	g_list_free (list);
+
+	list = NULL;
+	int mul = 1;
+	for (i = 0; i < N_ELEMS; ++i) {
+		list = g_list_prepend (list, GINT_TO_POINTER (mul * i));
+		mul = -mul;
+	}
+
+	if (!verify_sort (list))
+		return FAILED ("alternating list");
+
+	g_list_free (list);
+
+	return OK;
+}
+
 static Test list_tests [] = {
 	{       "length", test_list_length},
 	{          "nth", test_list_nth},
@@ -320,6 +382,7 @@ static Test list_tests [] = {
 	{       "remove", test_list_remove},
 	{  "remove_link", test_list_remove_link},
 	{  "remove_link", test_list_remove_link},
+	{         "sort", test_list_sort},
 	{NULL, NULL}
 };
 

+ 58 - 0
eglib/test/slist.c

@@ -161,6 +161,63 @@ test_slist_insert_before ()
 	return OK;
 }
 
+#define N_ELEMS 100
+
+static int intcompare (gconstpointer p1, gconstpointer p2)
+{
+	return GPOINTER_TO_INT (p1) - GPOINTER_TO_INT (p2);
+}
+
+static gboolean verify_sort (GSList *list)
+{
+	list = g_slist_sort (list, intcompare);
+
+	int prev = GPOINTER_TO_INT (list->data);
+	for (list = list->next; list; list = list->next) {
+		int curr = GPOINTER_TO_INT (list->data);
+		if (prev > curr)
+			return FALSE;
+		prev = curr;
+	}
+	return TRUE;
+}
+
+RESULT
+test_slist_sort ()
+{
+	int i = 0;
+	GSList *list = NULL;
+
+	for (i = 0; i < N_ELEMS; ++i)
+		list = g_slist_prepend (list, GINT_TO_POINTER (i));
+	if (!verify_sort (list))
+		return FAILED ("decreasing list");
+
+	g_slist_free (list);
+
+	list = NULL;
+	for (i = 0; i < N_ELEMS; ++i)
+		list = g_slist_prepend (list, GINT_TO_POINTER (-i));
+	if (!verify_sort (list))
+		return FAILED ("increasing list");
+
+	g_slist_free (list);
+
+	list = NULL;
+	int mul = 1;
+	for (i = 0; i < N_ELEMS; ++i) {
+		list = g_slist_prepend (list, GINT_TO_POINTER (mul * i));
+		mul = -mul;
+	}
+
+	if (!verify_sort (list))
+		return FAILED ("alternating list");
+
+	g_slist_free (list);
+
+	return OK;
+}
+
 static Test slist_tests [] = {
 	{"append", test_slist_append},
 	{"concat", test_slist_concat},
@@ -169,6 +226,7 @@ static Test slist_tests [] = {
 	{"remove_link", test_slist_remove_link},
 	{"insert_sorted", test_slist_insert_sorted},
 	{"insert_before", test_slist_insert_before},
+	{"sort", test_slist_sort},
 	{NULL, NULL}
 };