| /* 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; |
| } |