/* EINA - EFL data type library * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; * if not, see . */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "eina_inlist.h" #include "eina_error.h" #include "eina_private.h" /* FIXME: TODO please, refactor this :) */ /*============================================================================* * Local * *============================================================================*/ typedef struct _Eina_Iterator_Inlist Eina_Iterator_Inlist; typedef struct _Eina_Accessor_Inlist Eina_Accessor_Inlist; struct _Eina_Iterator_Inlist { Eina_Iterator iterator; const Eina_Inlist *head; const Eina_Inlist *current; }; struct _Eina_Accessor_Inlist { Eina_Accessor accessor; const Eina_Inlist *head; const Eina_Inlist *current; unsigned int index; }; static Eina_Bool eina_inlist_iterator_next(Eina_Iterator_Inlist *it, void **data) { if (it->current == NULL) return EINA_FALSE; if (data) *data = (void*) it->current; it->current = it->current->next; return EINA_TRUE; } static Eina_Inlist * eina_inlist_iterator_get_container(Eina_Iterator_Inlist *it) { return (Eina_Inlist*) it->head; } static void eina_inlist_iterator_free(Eina_Iterator_Inlist *it) { free(it); } static Eina_Bool eina_inlist_accessor_get_at(Eina_Accessor_Inlist *it, unsigned int index, void **data) { const Eina_Inlist *over; unsigned int middle; unsigned int i; if (it->index == index) { over = it->current; } else if (index > it->index) { /* Looking after current. */ for (i = it->index, over = it->current; i < index && over != NULL; ++i, over = over->next) ; } else { middle = it->index >> 1; if (index > middle) { /* Looking backward from current. */ for (i = it->index, over = it->current; i > index && over != NULL; --i, over = over->prev) ; } else { /* Looking from the start. */ for (i = 0, over = it->head; i < index && over != NULL; ++i, over = over->next) ; } } if (over == NULL) return EINA_FALSE; it->current = over; it->index = index; if (data) *data = (void*) over; return EINA_TRUE; } static Eina_Inlist * eina_inlist_accessor_get_container(Eina_Accessor_Inlist *it) { return (Eina_Inlist *) it->head; } static void eina_inlist_accessor_free(Eina_Accessor_Inlist *it) { free(it); } /*============================================================================* * Global * *============================================================================*/ /*============================================================================* * API * *============================================================================*/ /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_append(Eina_Inlist *list, Eina_Inlist *new_l) { Eina_Inlist *l; new_l->next = NULL; if (!list) { new_l->prev = NULL; new_l->last = new_l; return new_l; } if (list->last) l = list->last; else for (l = list; (l) && (l->next); l = l->next) ; l->next = new_l; new_l->prev = l; list->last = new_l; return list; } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_prepend(Eina_Inlist *list, Eina_Inlist *new_l) { new_l->prev = NULL; if (!list) { new_l->next = NULL; new_l->last = new_l; return new_l; } new_l->next = list; list->prev = new_l; new_l->last = list->last; list->last = NULL; return new_l; } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_append_relative(Eina_Inlist *list, Eina_Inlist *new_l, Eina_Inlist *relative) { if (relative) { if (relative->next) { new_l->next = relative->next; relative->next->prev = new_l; } else new_l->next = NULL; relative->next = new_l; new_l->prev = relative; if (!new_l->next) list->last = new_l; return list; } return eina_inlist_append(list, new_l); } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_prepend_relative(Eina_Inlist *list, Eina_Inlist *new_l, Eina_Inlist *relative) { if (relative) { new_l->prev = relative->prev; new_l->next = relative; relative->prev = new_l; if (new_l->prev) { new_l->prev->next = new_l; /* new_l->next could not be NULL, as it was set to 'relative' */ assert(new_l->next); return list; } else { /* new_l->next could not be NULL, as it was set to 'relative' */ assert(new_l->next); new_l->last = list->last; list->last = NULL; return new_l; } } return eina_inlist_prepend(list, new_l); } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_remove(Eina_Inlist *list, Eina_Inlist *item) { Eina_Inlist *return_l; /* checkme */ if (!list) return list; if (!item) return list; if (item->next) item->next->prev = item->prev; if (item->prev) { item->prev->next = item->next; return_l = list; } else { return_l = item->next; if (return_l) return_l->last = list->last; } if (item == list->last) list->last = item->prev; item->next = NULL; item->prev = NULL; return return_l; } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_promote(Eina_Inlist *list, Eina_Inlist *item) { if (item == list) return list; if (!item || !list) return list; if (item->next) item->next->prev = item->prev; item->prev->next = item->next; if (list->last == item) list->last = item->prev; item->next = list; item->prev = NULL; item->last = list->last; list->prev = item; list->last = NULL; return item; } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_demote(Eina_Inlist *list, Eina_Inlist *item) { Eina_Inlist *l; if (!item || !list) return list; if (list->last == item) return list; if (!list->last) { for (l = list; l->next; l = l->next) ; list->last = l; } l = list; if (item->prev) item->prev->next = item->next; else l = item->next; item->next->prev = item->prev; list->last->next = item; item->prev = list->last; item->next = NULL; l->last = item; return l; } /** * To be documented * FIXME: To be fixed */ EAPI Eina_Inlist * eina_inlist_find(Eina_Inlist *list, Eina_Inlist *item) { Eina_Inlist *l; for (l = list; l; l = l->next) { if (l == item) return item; } return NULL; } EAPI Eina_Iterator * eina_inlist_iterator_new(const Eina_Inlist *list) { Eina_Iterator_Inlist *it; if (!list) return NULL; eina_error_set(0); it = calloc(1, sizeof (Eina_Iterator_Inlist)); if (!it) { eina_error_set(EINA_ERROR_OUT_OF_MEMORY); return NULL; } it->head = list; it->current = list; it->iterator.next = FUNC_ITERATOR_NEXT(eina_inlist_iterator_next); it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(eina_inlist_iterator_get_container); it->iterator.free = FUNC_ITERATOR_FREE(eina_inlist_iterator_free); EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); return &it->iterator; } EAPI Eina_Accessor * eina_inlist_accessor_new(const Eina_Inlist *list) { Eina_Accessor_Inlist *it; if (!list) return NULL; eina_error_set(0); it = calloc(1, sizeof (Eina_Accessor_Inlist)); if (!it) { eina_error_set(EINA_ERROR_OUT_OF_MEMORY); return NULL; } it->head = list; it->current = list; it->index = 0; it->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_inlist_accessor_get_at); it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(eina_inlist_accessor_get_container); it->accessor.free = FUNC_ACCESSOR_FREE(eina_inlist_accessor_free); EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR); return &it->accessor; }