123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- /*!
- Temelia - Doubly Linked List implementation source file.
- Copyright (C) 2008 Ceata (http://ceata.org/proiecte/temelia).
- @author Dascalu Laurentiu, Macovei Alexandru
- This program is free software; you can redistribute it and
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 3
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include "include/doubly_linked_list.h"
- #include "include/common.h"
- #include "include/list_common.h"
- #include <stdlib.h>
- struct _doubly_linked_list_t
- {
- struct _doubly_linked_list_iterator_t *begin;
- struct _doubly_linked_list_iterator_t *end;
- int size;
- };
- static void _doubly_linked_list_reverse_aux(doubly_linked_list_iterator_t it);
- doubly_linked_list_t doubly_linked_list_new(void)
- {
- doubly_linked_list_t list;
- LIST_NEW(doubly_linked_list_t, list);
- return list;
- }
- doubly_linked_list_t doubly_linked_list_clone(doubly_linked_list_t list,
- void *(*clone)(void *key, void *context), void *context)
- {
- doubly_linked_list_t clone_list;
- doubly_linked_list_iterator_t it;
- LIST_CLONE(doubly_linked_list, list, it, clone_list, clone, context);
- return clone_list;
- }
- void doubly_linked_list_delete(doubly_linked_list_t list)
- {
- doubly_linked_list_iterator_t crt, prc;
- LIST_DELETE(list, crt, prc, doubly_linked_list_iterator);
- }
- int doubly_linked_list_is_empty(doubly_linked_list_t list)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER, -1);
- return list->size == 0;
- }
- void *doubly_linked_list_get_front(doubly_linked_list_t list)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(list->size, <=, 0, INVALID_INPUT, NULL);
- return doubly_linked_list_iterator_get_key(list->begin);
- }
- void *doubly_linked_list_get_back(doubly_linked_list_t list)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(list->size, <=, 0, INVALID_INPUT, NULL);
- return doubly_linked_list_iterator_get_key(list->end);
- }
- doubly_linked_list_iterator_t doubly_linked_list_get_begin(
- doubly_linked_list_t list)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
- return list->begin;
- }
- void doubly_linked_list_set_begin(doubly_linked_list_t list,
- doubly_linked_list_iterator_t begin)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- list->begin = begin;
- }
- doubly_linked_list_iterator_t doubly_linked_list_get_end(
- doubly_linked_list_t list)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
- return list->end;
- }
- void doubly_linked_list_set_end(doubly_linked_list_t list,
- doubly_linked_list_iterator_t end)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- list->end = end;
- }
- int doubly_linked_list_get_size(doubly_linked_list_t list)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER, -1);
- return list->size;
- }
- void doubly_linked_list_set_size(doubly_linked_list_t list, int size)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- list->size = size;
- }
- int doubly_linked_list_check(doubly_linked_list_t list,
- doubly_linked_list_iterator_t p)
- {
- doubly_linked_list_iterator_t it_left, it_right;
- _ASSERT(list, ==, NULL, NULL_POINTER, -1);
- _ASSERT(p, ==, NULL, NULL_POINTER, -1);
- for (it_left = list->begin, it_right = list->end; it_left != it_right;)
- {
- it_left = doubly_linked_list_iterator_get_next(it_left);
- it_right = doubly_linked_list_iterator_get_prev(it_right);
- }
- if (it_left == it_right)
- return 1;
- return 0;
- }
- doubly_linked_list_iterator_t doubly_linked_list_get_iterator_at(
- doubly_linked_list_t list, int position)
- {
- doubly_linked_list_iterator_t it;
- int i;
- _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(position, <, 0, INVALID_INPUT, NULL);
- _ASSERT(position, >=, list->size, INVALID_INPUT, NULL);
- it = NULL;
- // If position is in the first half, then move from beginning to it.
- if (position < list->size / 2)
- for (i = 0, it = list->begin; i < position && it != NULL; i++, it
- = doubly_linked_list_iterator_get_next(it))
- ;
- // Else, move from the end to it. Although the complexity is the same with
- // the search from beginning in any case, O(n), the constant is not the same.
- else
- for (i = list->size - 1, it = list->end; i > position && it != NULL; i--, it
- = doubly_linked_list_iterator_get_prev(it))
- ;
- return it;
- }
- void *doubly_linked_list_get_key_at(doubly_linked_list_t list, int position)
- {
- doubly_linked_list_iterator_t it = doubly_linked_list_get_iterator_at(list,
- position);
- if (it)
- return doubly_linked_list_iterator_get_key(it);
- return NULL;
- }
- void doubly_linked_list_set_key_at(doubly_linked_list_t list, int position,
- void *new_key)
- {
- doubly_linked_list_iterator_t it = doubly_linked_list_get_iterator_at(list,
- position);
- if (it)
- doubly_linked_list_iterator_set_key(it, new_key);
- }
- doubly_linked_list_iterator_t doubly_linked_list_search_key(
- doubly_linked_list_t list, void *key, int compare(void *x, void *y,
- void *context), void *context)
- {
- doubly_linked_list_iterator_t it_left, it_right;
- for (it_left = list->begin, it_right = list->end; it_left != it_right;)
- {
- if (!compare(doubly_linked_list_iterator_get_key(it_left), key, context))
- return it_left;
- if (!compare(doubly_linked_list_iterator_get_key(it_right), key,
- context))
- return it_right;
- it_left = doubly_linked_list_iterator_get_next(it_left);
- it_right = doubly_linked_list_iterator_get_prev(it_right);
- }
- return NULL;
- }
- int doubly_linked_list_search_iterator(doubly_linked_list_t list,
- doubly_linked_list_iterator_t it)
- {
- int i_left, i_right;
- doubly_linked_list_iterator_t it_left, it_right;
- _ASSERT(list, ==, NULL, NULL_POINTER, -1);
- for (it_left = list->begin, it_right = list->end, i_left = 0, i_right
- = list->size - 1; it_left != it_right;)
- {
- if (it_left == it)
- return i_left;
- if (it_right == it)
- return i_right;
- it_left = doubly_linked_list_iterator_get_next(it_left);
- it_right = doubly_linked_list_iterator_get_prev(it_right);
- }
- return -1;
- }
- void doubly_linked_list_remove_iterator(doubly_linked_list_t list,
- doubly_linked_list_iterator_t it, int delete_iterator)
- {
- doubly_linked_list_iterator_t aux;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- _ASSERT(it, ==, NULL, NULL_POINTER,);
- _ASSERT(list->size, ==, 0, EMPTY,);
- if (it == list->begin)
- {
- list->begin = doubly_linked_list_iterator_get_next(list->begin);
- doubly_linked_list_iterator_set_prev(list->begin, NULL);
- }
- else if (it == list->end)
- {
- aux = doubly_linked_list_iterator_get_prev(list->end);
- doubly_linked_list_iterator_set_next(aux, NULL);
- list->end = aux;
- }
- else
- {
- aux = doubly_linked_list_iterator_get_prev(it);
- doubly_linked_list_iterator_set_next(aux,
- doubly_linked_list_iterator_get_next(
- doubly_linked_list_iterator_get_next(aux)));
- doubly_linked_list_iterator_set_prev(
- doubly_linked_list_iterator_get_next(aux), aux);
- }
- list->size--;
- if (delete_iterator)
- _delete(it);
- }
- doubly_linked_list_iterator_t doubly_linked_list_remove_key(
- doubly_linked_list_t list, void *key, int compare(void *x, void *y,
- void *context), void *context, int free)
- {
- doubly_linked_list_iterator_t it = doubly_linked_list_search_key(list, key,
- compare, context);
- if (it)
- {
- doubly_linked_list_remove_iterator(list, it, free);
- if (free)
- return NULL;
- return it;
- }
- return NULL;
- }
- void doubly_linked_list_insert_before(doubly_linked_list_t list,
- doubly_linked_list_iterator_t it, void *key)
- {
- doubly_linked_list_iterator_t new_node;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- new_node = doubly_linked_list_iterator_new(key, NULL, NULL);
- if (list->size == 0)
- {
- if (it == NULL)
- list->begin = list->end = new_node;
- else
- {
- doubly_linked_list_iterator_delete(new_node);
- _ASSERT(NULL, ==, NULL, INVALID_INPUT,);
- }
- }
- else if (it == list->begin)
- {
- doubly_linked_list_iterator_set_next(new_node, it);
- doubly_linked_list_iterator_set_prev(it, new_node);
- list->begin = new_node;
- }
- else if (it == NULL)
- {
- doubly_linked_list_iterator_set_prev(new_node, list->end);
- doubly_linked_list_iterator_set_next(list->end, new_node);
- list->end = new_node;
- }
- else
- {
- doubly_linked_list_iterator_join(doubly_linked_list_iterator_get_prev(
- it), new_node, it);
- if (list->size == 1)
- list->begin = new_node;
- }
- list->size++;
- }
- void doubly_linked_list_insert_after(doubly_linked_list_t list,
- doubly_linked_list_iterator_t it, void *key)
- {
- doubly_linked_list_iterator_t new_node;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- new_node = doubly_linked_list_iterator_new(key, NULL, NULL);
- _ASSERT(new_node, ==, NULL, NULL_POINTER,);
- if (list->size == 0)
- {
- if (it == NULL)
- list->begin = list->end = new_node;
- else
- {
- doubly_linked_list_iterator_delete(new_node);
- return;
- }
- }
- else if (it == list->end)
- {
- doubly_linked_list_iterator_set_next(it, new_node);
- doubly_linked_list_iterator_set_prev(new_node, it);
- list->end = new_node;
- }
- else if (it == NULL)
- {
- doubly_linked_list_iterator_set_prev(list->begin, new_node);
- doubly_linked_list_iterator_set_next(new_node, list->begin);
- list->begin = new_node;
- }
- else
- {
- doubly_linked_list_iterator_join(it, new_node,
- doubly_linked_list_iterator_get_next(it));
- if (list->size == 1)
- list->end = new_node;
- }
- list->size++;
- }
- void doubly_linked_list_push_front(doubly_linked_list_t list, void *key)
- {
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- doubly_linked_list_insert_before(list, list->begin, key);
- }
- void doubly_linked_list_push_back(doubly_linked_list_t list, void *key)
- {
- doubly_linked_list_iterator_t new_node;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- new_node = doubly_linked_list_iterator_new(key, NULL, NULL);
- _ASSERT(new_node, ==, NULL, NULL_POINTER,);
- if (list->size == 0)
- {
- list->begin = list->end = new_node;
- list->size = 1;
- return;
- }
- doubly_linked_list_iterator_join(list->end, new_node, NULL);
- list->end = new_node;
- list->size++;
- }
- void doubly_linked_list_pop_front(doubly_linked_list_t list)
- {
- doubly_linked_list_iterator_t aux;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- _ASSERT(list->size, <=, 0, INVALID_INPUT,);
- aux = list->begin;
- if (list->size == 1)
- list->begin = list->end = NULL;
- else
- {
- list->begin = doubly_linked_list_iterator_get_next(list->begin);
- doubly_linked_list_iterator_set_prev(list->begin, NULL);
- }
- _delete(aux);
- list->size--;
- }
- void doubly_linked_list_pop_back(doubly_linked_list_t list)
- {
- doubly_linked_list_iterator_t aux;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- _ASSERT(list->size, <=, 0, INVALID_INPUT,);
- aux = list->end;
- if (list->size == 1)
- list->begin = list->end = NULL;
- else
- {
- list->end = doubly_linked_list_iterator_get_prev(list->end);
- doubly_linked_list_iterator_set_next(list->end, NULL);
- }
- _delete(aux);
- list->size--;
- }
- void doubly_linked_list_iterate(doubly_linked_list_t list, void key_handler(
- void *x, void *context), void *context, int order)
- {
- doubly_linked_list_iterator_t p;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- _ASSERT(key_handler, ==, NULL, NULL_POINTER,);
- if (order == 1)
- for (p = list->begin; p != NULL; p
- = doubly_linked_list_iterator_get_next(p))
- key_handler(doubly_linked_list_iterator_get_key(p), context);
- else if (order == -1)
- for (p = list->end; p != NULL; p
- = doubly_linked_list_iterator_get_prev(p))
- key_handler(doubly_linked_list_iterator_get_key(p), context);
- else
- temelia_errno = INVALID_INPUT;
- }
- void doubly_linked_list_sort(doubly_linked_list_t list, int compare(void *x,
- void *y, void *context), void *context)
- {
- void *aux;
- doubly_linked_list_iterator_t it;
- LIST_SORT(list, it, aux, compare, context, doubly_linked_list_iterator);
- }
- doubly_linked_list_t doubly_linked_list_merge(doubly_linked_list_t list1,
- doubly_linked_list_t list2,
- int compare(void *x, void *y, void *context), void *context)
- {
- doubly_linked_list_t L3;
- doubly_linked_list_iterator_t it1, it2;
- void *key1, *key2;
- _ASSERT(list1, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(list2, ==, NULL, NULL_POINTER, NULL);
- _ASSERT(compare, ==, NULL, NULL_POINTER, NULL);
- L3 = doubly_linked_list_new();
- it1 = list1->begin;
- it2 = list2->begin;
- LIST_MERGE(L3, it1, it2, key1, key2, doubly_linked_list, compare, context);
- return L3;
- }
- void doubly_linked_list_reverse(doubly_linked_list_t list)
- {
- void *aux;
- _ASSERT(list, ==, NULL, NULL_POINTER,);
- _doubly_linked_list_reverse_aux(list->begin);
- /*
- * Swaps "begin" with "end" for a consistent reverse;
- * also sets "end's" next iterator pointer to NULL
- */
- aux = list->begin;
- list->begin = list->end;
- list->end = aux;
- doubly_linked_list_iterator_set_next(list->end, NULL);
- doubly_linked_list_iterator_set_prev(list->begin, NULL);
- }
- void doubly_linked_list_spice(doubly_linked_list_t list1,
- doubly_linked_list_t list2, doubly_linked_list_iterator_t it)
- {
- doubly_linked_list_iterator_t next_node;
- _ASSERT(list1, ==, NULL, NULL_POINTER,);
- _ASSERT(list2, ==, NULL, NULL_POINTER,);
- if (it == NULL)
- {
- /*
- * => list2 -> list1
- */
- if (list1->end == NULL || list1->begin == list1->end)
- list1->end = list2->end;
- doubly_linked_list_iterator_join(list2->end, list1->begin,
- doubly_linked_list_iterator_get_next(list1->begin));
- list1->begin = list2->begin;
- }
- else if (list1->size > 0)
- {
- if (it == list1->end)
- {
- doubly_linked_list_iterator_join(list1->end, list2->begin,
- doubly_linked_list_iterator_get_next(list2->begin));
- list1->end = list2->end;
- }
- else
- {
- // Finally, we can use the given iterator :-)
- next_node = doubly_linked_list_iterator_get_next(it);
- _ASSERT(next_node, ==, NULL, NULL_POINTER,);
- doubly_linked_list_iterator_join(it, list2->begin,
- doubly_linked_list_iterator_get_next(list2->begin));
- doubly_linked_list_iterator_join(
- doubly_linked_list_iterator_get_prev(list2->end),
- list2->end, next_node);
- }
- }
- else if (list1->size == 0)
- {
- // Simply copies the two pointers
- list1->begin = list2->begin;
- list1->end = list2->end;
- }
- list1->size += list2->size;
- _delete(list2);
- }
- static void _doubly_linked_list_reverse_aux(doubly_linked_list_iterator_t it)
- {
- static doubly_linked_list_iterator_t _aux;
- if (it == NULL)
- return;
- _doubly_linked_list_reverse_aux(doubly_linked_list_iterator_get_next(it));
- _aux = doubly_linked_list_iterator_get_next(it);
- doubly_linked_list_iterator_set_next(_aux, it);
- doubly_linked_list_iterator_set_prev(it, _aux);
- }
|