glib_compat: lift g_list_sort() & g_slist_sort() from glib code

This commit is contained in:
Nguyen Anh Quynh 2016-12-26 18:32:02 +08:00
parent b05087d314
commit fba6046fd0
2 changed files with 170 additions and 84 deletions

View file

@ -178,49 +178,99 @@ GList *g_list_remove_link(GList *list, GList *llink)
return list; return list;
} }
GList *g_list_sort(GList *list, GCompareFunc compare) // code copied from glib/glist.c, version 2.28.0
static GList *g_list_sort_merge(GList *l1,
GList *l2,
GFunc compare_func,
gpointer user_data)
{ {
GList *i, *it, *j; GList list, *l, *lprev;
/* base case for singletons or empty lists */ gint cmp;
if (list == NULL || list->next == NULL) return list;
i = list; l = &list;
j = i->next; lprev = NULL;
/* i walks half as fast as j, ends up in middle */
while (j) { while (l1 && l2)
j = j->next; {
if (j) { cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
i = i->next;
j = j->next; if (cmp <= 0)
} {
} l->next = l1;
/* split the list midway */ l1 = l1->next;
j = i->next; }
j->prev = NULL; /* make j the head of its own list */ else
i->next = NULL; {
/* will never have NULL return from either call below */ l->next = l2;
i = g_list_sort(list, compare); l2 = l2->next;
j = g_list_sort(j, compare); }
if ((*compare)(i->data, j->data) <= 0) { l = l->next;
list = i; l->prev = lprev;
i = i->next; lprev = l;
} else { }
list = j; l->next = l1 ? l1 : l2;
j = j->next; l->next->prev = l;
}
it = list; return list.next;
while (i && j) { }
if ((*compare)(i->data, j->data) <= 0) {
it->next = i; static GList *g_list_sort_real(GList *list,
i = i->next; GFunc compare_func,
} else { gpointer user_data)
it->next = j; {
j = j->next; GList *l1, *l2;
}
it = it->next; if (!list)
} return NULL;
if (i) it->next = i; if (!list->next)
else it->next = j; return list;
return list;
l1 = list;
l2 = list->next;
while ((l2 = l2->next) != NULL)
{
if ((l2 = l2->next) == NULL)
break;
l1 = l1->next;
}
l2 = l1->next;
l1->next = NULL;
return g_list_sort_merge (g_list_sort_real (list, compare_func, user_data),
g_list_sort_real (l2, compare_func, user_data),
compare_func,
user_data);
}
/**
* g_list_sort:
* @list: a #GList
* @compare_func: the comparison function used to sort the #GList.
* This function is passed the data from 2 elements of the #GList
* and should return 0 if they are equal, a negative value if the
* first element comes before the second, or a positive value if
* the first element comes after the second.
*
* Sorts a #GList using the given comparison function.
*
* Returns: the start of the sorted #GList
*/
/**
* GCompareFunc:
* @a: a value.
* @b: a value to compare with.
* @Returns: negative value if @a &lt; @b; zero if @a = @b; positive
* value if @a > @b.
*
* Specifies the type of a comparison function used to compare two
* values. The function should return a negative integer if the first
* value comes before the second, 0 if they are equal, or a positive
* integer if the first value comes after the second.
**/
GList *g_list_sort (GList *list, GCompareFunc compare_func)
{
return g_list_sort_real (list, (GFunc) compare_func, NULL);
} }
/* END of g_list related functions */ /* END of g_list related functions */
@ -267,48 +317,82 @@ GSList *g_slist_prepend(GSList *list, gpointer data)
return head; return head;
} }
GSList *g_slist_sort(GSList *list, GCompareFunc compare) static GSList *g_slist_sort_merge (GSList *l1,
GSList *l2,
GFunc compare_func,
gpointer user_data)
{ {
GSList *i, *it, *j; GSList list, *l;
/* base case for singletons or empty lists */ gint cmp;
if (list == NULL || list->next == NULL) return list;
i = list; l=&list;
j = i->next;
/* i walks half as fast as j, ends up in middle */ while (l1 && l2)
while (j) { {
j = j->next; cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
if (j) {
i = i->next; if (cmp <= 0)
j = j->next; {
} l=l->next=l1;
} l1=l1->next;
/* split the list midway */ }
j = i->next; else
i->next = NULL; {
/* will never have NULL return from either call below */ l=l->next=l2;
i = g_slist_sort(list, compare); l2=l2->next;
j = g_slist_sort(j, compare); }
if ((*compare)(i->data, j->data) <= 0) { }
list = i; l->next= l1 ? l1 : l2;
i = i->next;
} else { return list.next;
list = j; }
j = j->next;
} static GSList *g_slist_sort_real (GSList *list,
it = list; GFunc compare_func,
while (i && j) { gpointer user_data)
if ((*compare)(i->data, j->data) <= 0) { {
it->next = i; GSList *l1, *l2;
i = i->next;
} else { if (!list)
it->next = j; return NULL;
j = j->next; if (!list->next)
} return list;
it = it->next;
} l1 = list;
if (i) it->next = i; l2 = list->next;
else it->next = j;
return list; while ((l2 = l2->next) != NULL)
{
if ((l2 = l2->next) == NULL)
break;
l1=l1->next;
}
l2 = l1->next;
l1->next = NULL;
return g_slist_sort_merge (g_slist_sort_real (list, compare_func, user_data),
g_slist_sort_real (l2, compare_func, user_data),
compare_func,
user_data);
}
/**
* g_slist_sort:
* @list: a #GSList
* @compare_func: the comparison function used to sort the #GSList.
* This function is passed the data from 2 elements of the #GSList
* and should return 0 if they are equal, a negative value if the
* first element comes before the second, or a positive value if
* the first element comes after the second.
*
* Sorts a #GSList using the given comparison function.
*
* Returns: the start of the sorted #GSList
*/
GSList *g_slist_sort (GSList *list,
GCompareFunc compare_func)
{
return g_slist_sort_real (list, (GFunc) compare_func, NULL);
} }
/* END of g_slist related functions */ /* END of g_slist related functions */

View file

@ -44,11 +44,13 @@ typedef unsigned int guint;
typedef char gchar; typedef char gchar;
typedef int gboolean; typedef int gboolean;
typedef gint (*GCompareDataFunc)(gconstpointer a,
gconstpointer b,
gpointer user_data);
typedef void (*GFunc)(gpointer data, gpointer user_data); typedef void (*GFunc)(gpointer data, gpointer user_data);
typedef gint (*GCompareFunc)(gconstpointer v1, gconstpointer v2); typedef gint (*GCompareFunc)(gconstpointer v1, gconstpointer v2);
typedef void (*GDestroyNotify)(gpointer data); typedef void (*GDestroyNotify)(gpointer data);
guint g_direct_hash(gconstpointer v);
guint g_str_hash(gconstpointer v); guint g_str_hash(gconstpointer v);
gboolean g_str_equal(gconstpointer v1, gconstpointer v2); gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
guint g_int_hash(gconstpointer v); guint g_int_hash(gconstpointer v);