summaryrefslogtreecommitdiffstats
path: root/tinySAK/src/tsk_list.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinySAK/src/tsk_list.c')
-rw-r--r--tinySAK/src/tsk_list.c604
1 files changed, 604 insertions, 0 deletions
diff --git a/tinySAK/src/tsk_list.c b/tinySAK/src/tsk_list.c
new file mode 100644
index 0000000..d441bfc
--- /dev/null
+++ b/tinySAK/src/tsk_list.c
@@ -0,0 +1,604 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or 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.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tsk_list.c
+ * @brief Linked list.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tsk_list.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+//#include <assert.h>
+#include <string.h>
+
+// FIXME: remove asserts
+
+/**@defgroup tsk_list_group Linked list.
+* For more information about linked list you can visit http://en.wikipedia.org/wiki/Linked_list.
+*/
+
+/** tsk_list_find_by_item
+*/
+static int tsk_list_find_by_item(const tsk_list_item_t* item, const void* _item)
+{
+ return (item == (const tsk_list_item_t*)_item) ? 0 : -1;
+}
+
+/**@ingroup tsk_list_group
+* Creates a linked list object.
+* You MUST use @ref TSK_OBJECT_SAFE_FREE() to safely free the object.
+*/
+tsk_list_t* tsk_list_create()
+{
+ return tsk_object_new(tsk_list_def_t);
+}
+
+/**@ingroup tsk_list_group
+* Create and initialize an item to be added to a linked list.
+* You MUST use @ref TSK_OBJECT_SAFE_FREE() to safely free the object.
+*/
+tsk_list_item_t* tsk_list_item_create()
+{
+ return tsk_object_new(tsk_list_item_def_t);
+}
+
+/**@ingroup tsk_list_group
+* Locks the list to avoid concurrent access. The list should be unlocked using
+* @ref tsk_list_unlock.
+* @param list The list to lock.
+* @retval zero if succeed and non-zero error code otherwise.
+* @sa @ref tsk_list_unlock
+*/
+int tsk_list_lock(tsk_list_t* list)
+{
+ if(list){
+ if(!list->mutex){
+ list->mutex = tsk_mutex_create();
+ }
+ return tsk_mutex_lock(list->mutex);
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+/**@ingroup tsk_list_group
+* UnLocks a previously locked list.
+* @param list The list to unlock.
+* @retval zero if succeed and non-zero error code otherwise.
+* @sa @ref tsk_list_lock
+*/
+int tsk_list_unlock(tsk_list_t* list)
+{
+ if(list && list->mutex){
+ return tsk_mutex_unlock(list->mutex);
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+/**@ingroup tsk_list_group
+* Remove an free an item from the @a list.
+* @param list the list from which to remove the @a item.
+* @param item the item to remove (and free) from the @a list.
+*/
+void tsk_list_remove_item(tsk_list_t* list, tsk_list_item_t* item)
+{
+ tsk_list_remove_item_by_pred(list, tsk_list_find_by_item, (const void*)item);
+}
+
+/**@ingroup tsk_list_group
+* Pops an object from the @a list.
+* @param list The list from which to pop the object.
+* @param tskobj Any valid object(declared using @ref TSK_DECLARE_OBJECT) to remove.
+* @retval The item.
+*/
+tsk_list_item_t* tsk_list_pop_item_by_data(tsk_list_t* list, const tsk_object_t * tskobj)
+{
+ if(list){
+ tsk_list_item_t *prev = tsk_null;
+ tsk_list_item_t *curr = prev = list->head;
+
+ while(curr){
+ if(!tsk_object_cmp(curr->data, tskobj)){
+ if(prev == curr){
+ /* Found at first position. */
+ if(list->head == list->tail){
+ /* There was only one item */
+ list->head = list->tail = tsk_null;
+ }
+ else{
+ list->head = curr->next;
+ }
+ }
+ else {
+ if(curr == list->tail){
+ /* Found at last position */
+ list->tail = prev;
+ list->tail->next = tsk_null;
+ }
+ else{
+ prev->next = curr->next;
+ }
+ }
+
+ return curr;
+ }
+
+ prev = curr;
+ curr = curr->next;
+ }
+ }
+
+ return 0;
+}
+
+/**@ingroup tsk_list_group
+* Removes an object from the @a list.
+* @param list The list from which to remove the object.
+* @param tskobj Any valid object(declared using @ref TSK_DECLARE_OBJECT) to remove.
+*/
+void tsk_list_remove_item_by_data(tsk_list_t* list, const tsk_object_t * tskobj)
+{
+ tsk_list_item_t* item;
+ if((item = tsk_list_pop_item_by_data(list, tskobj))){
+ tsk_object_unref(item);
+ }
+}
+
+/**@ingroup tsk_list_group
+* Pops an item from the @a list using a predicate function.
+* @param list The list from which to pop the item.
+* @param predicate The predicate function used to match the item.
+* @param data Arbitrary data to pass to the predicate function.
+* @retval The item
+*/
+tsk_list_item_t* tsk_list_pop_item_by_pred(tsk_list_t* list, tsk_list_func_predicate predicate, const void * data)
+{
+ if(list){
+ tsk_list_item_t *prev = tsk_null;
+ tsk_list_item_t *curr = prev = list->head;
+
+ while(curr){
+ if(!predicate(curr, data)){
+ if(prev == curr){
+ /* Found at first position. */
+ if(list->head == list->tail){
+ /* There was only one item */
+ list->head = list->tail = tsk_null;
+ }
+ else{
+ list->head = curr->next;
+ }
+ }
+ else {
+ if(curr == list->tail){
+ /* Found at last position */
+ list->tail = prev;
+ list->tail->next = tsk_null;
+ }
+ else{
+ prev->next = curr->next;
+ }
+ }
+
+ return curr;
+ }
+
+ prev = curr;
+ curr = curr->next;
+ }
+ }
+
+ return 0;
+}
+
+/**@ingroup tsk_list_group
+* Removes an item from the @a list using a predicate function.
+* @param list The list from which to remove the item.
+* @param predicate The predicate function used to match the item.
+* @param data Arbitrary data to pass to the predicate function.
+*/
+void tsk_list_remove_item_by_pred(tsk_list_t* list, tsk_list_func_predicate predicate, const void * data)
+{
+ tsk_list_item_t* item;
+ if((item = tsk_list_pop_item_by_pred(list, predicate, data))){
+ tsk_object_unref(item);
+ }
+}
+
+/**@ingroup tsk_list_group
+* Clean up and remove all items from the @a list.
+* @param list The list ro clean up.
+*/
+void tsk_list_clear_items(tsk_list_t* list)
+{
+ if(list){
+ tsk_list_item_t* next = tsk_null;
+ tsk_list_item_t* curr = list->head;
+
+ while(curr){
+ next = curr->next;
+ tsk_object_unref(curr);
+ curr = next;
+ }
+ list->head = tsk_null;
+ list->tail = tsk_null;
+ }
+}
+
+/**@ingroup tsk_list_group
+* Pops first item from the @a list. The item will be definitely removed from the list.
+* @param list The list from which to pop the item.
+* @retval The first item. It is up to you to free the returned item (@ref TSK_OBJECT_SAFE_FREE(item)).
+*/
+tsk_list_item_t* tsk_list_pop_first_item(tsk_list_t* list)
+{
+ tsk_list_item_t* item = tsk_null;
+ if(list){
+ item = list->head;
+ if(list->head){
+ if(list->head->next){
+ list->head = list->head->next;
+ }
+ else{
+ list->head = list->tail = tsk_null;
+ }
+ }
+ }
+
+ return item;
+}
+
+/**@ingroup tsk_list_group
+* Add an item to the @a list.
+* @param list The destination @a list.
+* @param item The @a item to add.
+* @param back Indicates whether to put the item back or not.
+*/
+void tsk_list_push_item(tsk_list_t* list, tsk_list_item_t** item, tsk_bool_t back)
+{
+ // do not test
+ tsk_bool_t first = !list->head;
+
+ if(back && list->tail){
+ list->tail->next = *item, list->tail = *item, (*item)->next = tsk_null;
+ }
+ else {
+ (*item)->next = list->head, list->head = *item;
+ }
+
+ if(first){
+ list->tail = list->head = *item, list->tail->next = tsk_null;
+ }
+ (*item) = tsk_null;
+}
+
+/**@ingroup tsk_list_group
+* Add an item to the list in ascending or descending order.
+* @param list The destination @a list.
+* @param item The @a item to add.
+* @param ascending Indicates whether to put the @a item in ascending order or not.
+*/
+void tsk_list_push_filtered_item(tsk_list_t* list, tsk_list_item_t** item, tsk_bool_t ascending)
+{
+ if(list)
+ {
+ tsk_list_item_t *prev = tsk_null;
+ tsk_list_item_t *curr = prev = list->head;
+
+ while(curr)
+ {
+ int diff = tsk_object_cmp((*item), curr);
+ if((diff </*=*/ 0 && ascending) || (diff >/*=*/0 && !ascending)){
+ if(curr == list->head){
+ tsk_list_push_front_item(list, item);
+ }
+ else{
+ (*item)->next = curr;
+ prev->next = (*item);
+ }
+
+ return;
+ }
+
+ prev = curr;
+ curr = curr->next;
+ }
+
+ tsk_list_push_back_item(list, item);
+ }
+}
+
+/**@ingroup tsk_list_group
+* Add all items in @a src into @a dest.
+* @param dest The destination list.
+* @param src The source list.
+* @param back Indicates whether to put the list back or not.
+**/
+int tsk_list_push_list(tsk_list_t* dest, const tsk_list_t* src, tsk_bool_t back)
+{
+ const tsk_list_item_t* curr = (src)->head;
+ tsk_object_t* copy;
+
+ if(!dest || !src){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ while(curr){
+ copy = tsk_object_ref(curr->data);
+ tsk_list_push_data(dest, (void**)&copy, back);
+
+ curr = curr->next;
+ }
+ return 0;
+}
+
+/**@ingroup tsk_list_group
+* Add an opaque data to the @a list.
+* @param list The destination @a list.
+* @param data The @a data to add.
+* @param back Indicates whether to put the item back or not.
+*/
+int tsk_list_push_data(tsk_list_t* list, void** data, tsk_bool_t back)
+{
+ if(list && data && *data){
+ tsk_list_item_t *item = tsk_list_item_create();
+ item->data = *data;
+
+ tsk_list_push_item(list, &item, back);
+ (*data) = tsk_null;
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+/**@ingroup tsk_list_group
+* Add an opaque data to the list in ascending or descending order.
+* @param list The destination @a list.
+* @param data The @a data to add.
+* @param ascending Indicates whether to put the @a data in ascending order or not.
+*/
+int tsk_list_push_filtered_data(tsk_list_t* list, void** data, tsk_bool_t ascending)
+{
+ if(list && data && *data){
+ tsk_list_item_t *item = tsk_list_item_create();
+ item->data = *data;
+
+ tsk_list_push_filtered_item(list, &item, ascending);
+ (*data) = tsk_null;
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+/**@ingroup tsk_list_group
+* Find an item from a list.
+* @param list The @a list holding the item.
+* @param tskobj The @a object to find.
+* @retval A @ref tsk_list_item_t item if found and NULL otherwize.
+*/
+const tsk_list_item_t* tsk_list_find_item_by_data(const tsk_list_t* list, const tsk_object_t* tskobj)
+{
+ if(list && tskobj){
+ tsk_list_item_t *item;
+ tsk_list_foreach(item, list){
+ if(!tsk_object_cmp(item->data, tskobj)){
+ return item;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**@ingroup tsk_list_group
+* Find first item matching criteria defined by the @a predicate.
+* @param list the list to query
+* @param predicate the predicate against which to test each item
+* @param data data passed to the predicate function for comparaison
+* @retval the item which match the criteria and NULL otherwise
+* @sa @ref tsk_list_find_item_by_data
+*/
+const tsk_list_item_t* tsk_list_find_item_by_pred(const tsk_list_t* list, tsk_list_func_predicate predicate, const void* data)
+{
+ if(predicate){
+ const tsk_list_item_t *item;
+ tsk_list_foreach(item, list){
+ if(!predicate(item, data)){
+ return item;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_WARN("Cannot use an uninitialized predicate function");
+ }
+ return tsk_null;
+}
+
+/**@ingroup tsk_list_group
+* Find first item matching criteria defined by the @a predicate.
+* @param list the list to query
+* @param predicate the predicate against which to test each item
+* @param data data passed to the predicate function for comparaison
+* @retval the data holded by the item which match the criteria and NULL otherwise
+* @sa @ref tsk_list_find_item_by_pred
+*/
+const tsk_object_t* tsk_list_find_object_by_pred(const tsk_list_t* list, tsk_list_func_predicate predicate, const void* data)
+{
+ const tsk_list_item_t *item;
+ if((item = tsk_list_find_item_by_pred(list, predicate, data))){
+ return item->data;
+ }
+ else{
+ return tsk_null;
+ }
+}
+
+/**@ingroup tsk_list_group
+* Counts the number of item matching the predicate.
+* @param list The list containing the items to count
+* @param predicate The predicate to use to match the items
+* @param data Data passed to the predicate function for comparaison
+* @retval The number of item matching the predicate
+*/
+tsk_size_t tsk_list_count(const tsk_list_t* list, tsk_list_func_predicate predicate, const void* data)
+{
+ tsk_size_t count = 0;
+ if(predicate && list){
+ const tsk_list_item_t *item;
+ tsk_list_foreach(item, list){
+ if(!predicate(item, data)){
+ ++count;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ }
+
+ return count;
+}
+
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// Item object definition
+//
+static tsk_object_t* tsk_list_item_ctor(tsk_object_t * self, va_list * app)
+{
+ tsk_list_item_t *item = self;
+ if(item){
+ }
+ return self;
+}
+
+static tsk_object_t* tsk_list_item_dtor(tsk_object_t *self)
+{
+ tsk_list_item_t *item = self;
+ if(item){
+ item->data = tsk_object_unref(item->data);
+ }
+ else{
+ TSK_DEBUG_WARN("Cannot free an uninitialized item");
+ }
+ return item;
+}
+
+static int tsk_list_item_cmp(const tsk_object_t *_item1, const tsk_object_t *_item2)
+{
+ const tsk_list_item_t* item1 = _item1;
+ const tsk_list_item_t* item2 = _item2;
+
+ if(item1 && item2){
+ return tsk_object_cmp(item1->data, item2->data);
+ }
+ else return -1;
+}
+
+static const tsk_object_def_t tsk_list_item_def_s =
+{
+ sizeof(tsk_list_item_t),
+ tsk_list_item_ctor,
+ tsk_list_item_dtor,
+ tsk_list_item_cmp,
+};
+const tsk_object_def_t *tsk_list_item_def_t = &tsk_list_item_def_s;
+
+//=================================================================================================
+// List object definition
+//
+static tsk_object_t* tsk_list_ctor(tsk_object_t *self, va_list *app)
+{
+ tsk_list_t *list = self;
+ if(list){
+ }
+
+ return self;
+}
+
+static tsk_object_t* tsk_list_dtor(tsk_object_t *self)
+{
+ tsk_list_t *list = self;
+ if(list){
+#if 0
+ /* Not thread-safe */
+ tsk_list_item_t* next = tsk_null;
+ tsk_list_item_t* curr = list->head;
+
+ while(curr){
+ next = curr->next;
+ /*curr =*/ tsk_object_unref(curr);
+ curr = next;
+ }
+#else
+ /* Thread-safe method */
+ tsk_list_item_t* item;
+ while((item = tsk_list_pop_first_item(list))){
+ tsk_object_unref(item);
+ }
+#endif
+
+ /* destroy the on-demand mutex */
+ if(list->mutex){
+ tsk_mutex_destroy(&list->mutex);
+ }
+ }
+ else{
+ TSK_DEBUG_WARN("Cannot free an uninitialized list");
+ }
+ return list;
+}
+
+static const tsk_object_def_t tsk_list_def_s =
+{
+ sizeof(tsk_list_t),
+ tsk_list_ctor,
+ tsk_list_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tsk_list_def_t = &tsk_list_def_s;
+
OpenPOWER on IntegriCloud