blob: 38d8ee89e16cd2a81306415476be5bdb677aa401 [file] [log] [blame]
/* libnih
*
* list.c - generic circular doubly-linked list implementation
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nih/macros.h>
#include <nih/logging.h>
#include <nih/alloc.h>
#include "list.h"
/* Prototypes for static functions */
static inline NihList *nih_list_cut (NihList *entry);
/**
* nih_list_init:
* @entry: entry to be initialised.
*
* Initialise an already allocated list entry, once done it can be used
* as the start of a new list or added to an existing list.
**/
void
nih_list_init (NihList *entry)
{
nih_assert (entry != NULL);
entry->prev = entry->next = entry;
}
/**
* nih_list_new:
* @parent: parent object for new list.
*
* Allocates a new list structure, usually used as the start of a new
* list. You may prefer to allocate the NihList structure statically and
* use nih_list_init() to initialise it instead.
*
* The structure is allocated using nih_alloc() so can be used as a context
* to other allocations.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned list. When all parents
* of the returned list are freed, the returned list will also be
* freed.
*
* Returns: the new list or NULL if the allocation failed.
**/
NihList *
nih_list_new (const void *parent)
{
NihList *list;
list = nih_new (parent, NihList);
if (! list)
return NULL;
nih_list_init (list);
nih_alloc_set_destructor (list, nih_list_destroy);
return list;
}
/**
* nih_list_entry_new:
* @parent: parent object for new list entry.
*
* Allocates a new list entry structure, leaving the caller to set the
* data of the entry.
*
* The structure is allocated using nih_alloc() so can be used as a context
* to other allocations.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned list entry. When all parents
* of the returned list entry are freed, the returned list entry will also be
* freed.
*
* Returns: the new list entry or NULL if the allocation failed.
**/
NihListEntry *
nih_list_entry_new (const void *parent)
{
NihListEntry *list;
list = nih_new (parent, NihListEntry);
if (! list)
return NULL;
nih_list_init (&list->entry);
nih_alloc_set_destructor (list, nih_list_destroy);
list->data = NULL;
return list;
}
/**
* nih_list_add:
* @list: entry in the destination list,
* @entry: entry to be added to the list.
*
* Adds @entry to a new list immediately before the @list entry. If @list
* is the pointer you are using to refer to the list itself, this results
* in @entry being appended to the list.
*
* If @entry is already in another list it is removed so there is no need
* to call nih_list_remove() before this function. There is also no
* requirement that the lists be different, so this can be used to reorder
* a list.
*
* Returns: @entry which is now a member of the same list as @list.
**/
NihList *
nih_list_add (NihList *list,
NihList *entry)
{
nih_assert (list != NULL);
nih_assert (entry != NULL);
nih_list_cut (entry);
entry->prev = list->prev;
list->prev->next = entry;
list->prev = entry;
entry->next = list;
return entry;
}
/**
* nih_list_add_after:
* @list: entry in the destination list,
* @entry: entry to be added to the list.
*
* Adds @entry to a new list immediately after the @list entry. If @list
* is the pointer you are using to refer to the list itself and that entry
* has no data, this results in @entry being pushed onto a stack under it.
*
* If @entry is already in another list it is removed so there is no need
* to call nih_list_remove() before this function. There is also no
* requirement that the lists be different, so this can be used to reorder
* a list.
*
* Returns: @entry which is now a member of the same list as @list.
**/
NihList *
nih_list_add_after (NihList *list,
NihList *entry)
{
nih_assert (list != NULL);
nih_assert (entry != NULL);
nih_list_cut (entry);
entry->next = list->next;
list->next->prev = entry;
list->next = entry;
entry->prev = list;
return entry;
}
/**
* nih_list_cut:
* @entry: entry to be removed.
*
* Removes @entry from its containing list, but does not alter @entry
* itself; care should be taken to set the pointers immediately after.
*
* Returns: @entry unmodified.
**/
static inline NihList *
nih_list_cut (NihList *entry)
{
nih_assert (entry != NULL);
entry->prev->next = entry->next;
entry->next->prev = entry->prev;
return entry;
}
/**
* nih_list_remove:
* @entry: entry to be removed.
*
* Removes @entry from its containing list. The entry is not freed, but
* is instead returned so that it can be added to another list (though
* there's no need to call nih_list_remove() first if you wanted to do
* that) or used as the start of a new list.
*
* Returns: @entry as a lone entry.
**/
NihList *
nih_list_remove (NihList *entry)
{
nih_assert (entry != NULL);
nih_list_cut (entry);
nih_list_init (entry);
return entry;
}
/**
* nih_list_destroy:
* @entry: entry to be removed.
*
* Removes @entry from its containing list.
*
* Normally used or called from an nih_alloc() destructor so that the list
* item is automatically removed from its containing list when freed.
*
* Returns: zero.
**/
int
nih_list_destroy (NihList *entry)
{
nih_assert (entry != NULL);
nih_list_cut (entry);
return 0;
}