363 lines
6.4 KiB
C
363 lines
6.4 KiB
C
|
/*
|
||
|
* 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);
|
||
|
}
|