mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 10:23:46 +00:00
261 lines
4.2 KiB
C
261 lines
4.2 KiB
C
/*
|
|
** Copyright (C) 1995 University of Melbourne.
|
|
** This file may only be copied under the terms of the GNU Library General
|
|
** Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
*/
|
|
/*
|
|
** Linked list module.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include "std.h"
|
|
#include "list.h"
|
|
|
|
/*
|
|
** Make an empty list.
|
|
*/
|
|
|
|
List *makelist0()
|
|
{
|
|
reg List *list;
|
|
|
|
list = make(List);
|
|
ldata(list) = NULL;
|
|
next(list) = list;
|
|
prev(list) = list;
|
|
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
** Make a list with the argument is its only element.
|
|
*/
|
|
|
|
List *list_makelist(void * data)
|
|
{
|
|
reg List *list;
|
|
|
|
assert(data != NULL);
|
|
list = makelist0();
|
|
addhead(list, data);
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
** Add some data to the head of a list.
|
|
*/
|
|
|
|
List *list_addhead(List *list, void *data)
|
|
{
|
|
reg List *item;
|
|
|
|
if (list == NULL)
|
|
list = makelist0();
|
|
|
|
item = make(List);
|
|
ldata(item) = data;
|
|
llength(list)++;
|
|
|
|
/* item's pointers */
|
|
next(item) = next(list);
|
|
prev(item) = list;
|
|
/* neighbours' pointers */
|
|
next(prev(item)) = item;
|
|
prev(next(item)) = item;
|
|
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
** Add some data to the tail of a list.
|
|
*/
|
|
|
|
List *list_addtail(List *list, void *data)
|
|
{
|
|
reg List *item;
|
|
|
|
if (list == NULL)
|
|
list = makelist0();
|
|
|
|
item = make(List);
|
|
ldata(item) = data;
|
|
llength(list)++;
|
|
|
|
/* item's pointers */
|
|
next(item) = list;
|
|
prev(item) = prev(list);
|
|
/* neighbours' pointers */
|
|
next(prev(item)) = item;
|
|
prev(next(item)) = item;
|
|
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
** Destructively append list2 to list1. Since the header of
|
|
** list2 is not meaningful after the operation, it is freed.
|
|
*/
|
|
|
|
List *addlist(List *list1, List *list2)
|
|
{
|
|
if (list1 == NULL)
|
|
list1 = makelist0();
|
|
|
|
if (list2 == NULL)
|
|
list2 = makelist0();
|
|
|
|
if (llength(list2) > 0)
|
|
{
|
|
if (llength(list1) == 0)
|
|
{
|
|
ldata(list1) = ldata(list2);
|
|
/* pointers from header */
|
|
next(list1) = next(list2);
|
|
prev(list1) = prev(list2);
|
|
/* pointers to header */
|
|
prev(next(list1)) = list1;
|
|
next(prev(list1)) = list1;
|
|
}
|
|
else
|
|
{
|
|
llength(list1) = llength(list1) + llength(list2);
|
|
/* end of list 1 to start of list 2 */
|
|
next(prev(list1)) = next(list2);
|
|
prev(next(list2)) = prev(list1);
|
|
/* end of list 2 to start of list 1 */
|
|
next(prev(list2)) = list1;
|
|
prev(list1) = prev(list2);
|
|
}
|
|
}
|
|
|
|
oldmem(list2);
|
|
return list1;
|
|
}
|
|
|
|
/*
|
|
** (Semi-) nondestructively append list2 to list1.
|
|
** The header of the first list is indeed altered,
|
|
** but only the data pointers of the second are used.
|
|
*/
|
|
|
|
List *addndlist(List *list1, List *list2)
|
|
{
|
|
reg List *ptr;
|
|
|
|
if (list1 == NULL)
|
|
list1 = makelist0();
|
|
|
|
if (list2 == NULL)
|
|
list2 = makelist0();
|
|
|
|
for_list (ptr, list2)
|
|
addtail(list1, ldata(ptr));
|
|
|
|
return list1;
|
|
}
|
|
|
|
/*
|
|
** Insert into a list before a given position.
|
|
*/
|
|
|
|
void list_insert_before(List *list, List *where, void *data)
|
|
{
|
|
reg List *item;
|
|
|
|
item = make(List);
|
|
ldata(item) = data;
|
|
llength(list)++;
|
|
|
|
/* item's pointers */
|
|
next(item) = where;
|
|
prev(item) = prev(where);
|
|
/* neighbour's pointers */
|
|
next(prev(item)) = item;
|
|
prev(next(item)) = item;
|
|
}
|
|
|
|
/*
|
|
** Insert into a list after a given position.
|
|
*/
|
|
|
|
void list_insert_after(List *list, List *where, void *data)
|
|
{
|
|
reg List *item;
|
|
|
|
item = make(List);
|
|
ldata(item) = data;
|
|
llength(list)++;
|
|
|
|
/* item's pointers */
|
|
next(item) = next(where);
|
|
prev(item) = where;
|
|
/* neighbour's pointers */
|
|
next(prev(item)) = item;
|
|
prev(next(item)) = item;
|
|
}
|
|
|
|
/*
|
|
** Return the length of a given list.
|
|
*/
|
|
|
|
int length(const List *list)
|
|
{
|
|
if (list == NULL)
|
|
return 0;
|
|
|
|
return llength(list);
|
|
}
|
|
|
|
/*
|
|
** Delete an item from its linked list, and free the node,
|
|
** and maybe the data.
|
|
*/
|
|
|
|
void delete(List *list, List *item, void (* func)(void *))
|
|
{
|
|
if (list == NULL)
|
|
return;
|
|
|
|
if (item == NULL)
|
|
return;
|
|
|
|
if (func != NULL)
|
|
func(ldata(item));
|
|
|
|
llength(list)--;
|
|
next(prev(item)) = next(item);
|
|
prev(next(item)) = prev(item);
|
|
|
|
oldmem(item);
|
|
}
|
|
|
|
/*
|
|
** Free a whole list, including the header and maybe the data
|
|
** pointed to by the list. Of course, if they were not allocated
|
|
** by newmem and malloc, then all Hell will break loose.
|
|
*/
|
|
|
|
void oldlist(List *list, void (* func)(void *))
|
|
{
|
|
reg List *ptr;
|
|
reg List *item;
|
|
|
|
if (list == NULL)
|
|
return;
|
|
|
|
ptr = next(list);
|
|
while (ptr != list)
|
|
{
|
|
item = ptr;
|
|
ptr = next(ptr);
|
|
|
|
if (func != NULL)
|
|
func(ldata(item));
|
|
|
|
oldmem(item);
|
|
}
|
|
|
|
oldmem(list);
|
|
}
|