From: Nils Durner Date: Sat, 3 Oct 2009 15:36:09 +0000 (+0000) Subject: use singly linked lists instead of vectors X-Git-Tag: initial-import-from-subversion-38251~23413 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=d5f3c16326273625b37cd0f2d5b4716ac650f51d;p=oweals%2Fgnunet.git use singly linked lists instead of vectors --- diff --git a/src/include/gnunet_container_lib.h b/src/include/gnunet_container_lib.h index bbf1ba2cf..8abf10e21 100644 --- a/src/include/gnunet_container_lib.h +++ b/src/include/gnunet_container_lib.h @@ -42,6 +42,10 @@ extern "C" #endif +#define GNUNET_MEM_DISP_TRANSIENT 0 +#define GNUNET_MEM_DISP_STATIC 2 +#define GNUNET_MEM_DISP_DYNAMIC 4 + /* ******************* bloomfilter ***************** */ /** @@ -870,6 +874,101 @@ void *GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap unsigned int GNUNET_CONTAINER_heap_get_size (struct GNUNET_CONTAINER_Heap *heap); +/* ******************** Singly linked list *************** */ + +/* Handle to a singly linked list */ +struct GNUNET_CONTAINER_SList; + +/* Handle to a singly linked list iterator */ +struct GNUNET_CONTAINER_SList_Iterator; + + +/** + * Add a new element to the list + * @param l list + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + */ +void GNUNET_CONTAINER_slist_add (struct GNUNET_CONTAINER_SList *l, int disp, const void *buf, size_t len); + +/** + * Create a new singly linked list + * @return the new list + */ +struct GNUNET_CONTAINER_SList *GNUNET_CONTAINER_slist_create (); + +/** + * Destroy a singly linked list + * @param l the list to be destroyed + */ +void GNUNET_CONTAINER_slist_destroy (struct GNUNET_CONTAINER_SList *l); + +/** + * Return the beginning of a list + * @param l list + * @return iterator pointing to the beginning + */ +const struct GNUNET_CONTAINER_SList_Iterator *GNUNET_CONTAINER_slist_begin(const struct GNUNET_CONTAINER_SList *l); + +/** + * Clear a list + * @param l list + */ +void GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l); + +/** + * Check if a list contains a certain element + * @param l list + * @param buf payload buffer to find + * @param lenght of the payload + */ +int GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, const void *buf, size_t len); + +/** + * Count the elements of a list + * @param l list + * @return number of elements in the list + */ +int GNUNET_CONTAINER_slist_count (const struct GNUNET_CONTAINER_SList *l); + +/** + * Remove an element from the list + * @param i iterator that points to the element to be removed + */ +void GNUNET_CONTAINER_slist_erase (struct GNUNET_CONTAINER_SList_Iterator *i); + +/** + * Insert an element into a list at a specific position + * @param before where to insert the new element + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the payload + */ +void GNUNET_CONTAINER_slist_insert (struct GNUNET_CONTAINER_SList_Iterator *before, int disp, const void *buf, size_t len); + +/** + * Advance an iterator to the next element + * @param i iterator + * @return GNUNET_YES on success, GNUNET_NO if the end has been reached + */ +int GNUNET_CONTAINER_slist_next (struct GNUNET_CONTAINER_SList_Iterator *i); + +/** + * Check if an iterator points beyond the end of a list + * @param i iterator + * @return GNUNET_YES if the end has been reached, GNUNET_NO if the iterator + * points to a valid element + */ +int GNUNET_CONTAINER_slist_end (struct GNUNET_CONTAINER_SList_Iterator *i); + +/** + * Retrieve the element at a specific position in a list + * @param i iterator + * @param len payload length + * @return payload + */ +void *GNUNET_CONTAINER_slist_get (const struct GNUNET_CONTAINER_SList_Iterator *i, size_t *len); #if 0 /* keep Emacsens' auto-indent happy */ diff --git a/src/util/Makefile.am b/src/util/Makefile.am index f69c64b9f..32d1299d0 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -27,6 +27,7 @@ libgnunetutil_la_SOURCES = \ container_heap.c \ container_meta_data.c \ container_multihashmap.c \ + container_slist.c \ crypto_aes.c \ crypto_crc.c \ crypto_hash.c \ @@ -96,6 +97,7 @@ check_PROGRAMS = \ test_container_meta_data \ test_container_multihashmap \ test_container_heap \ + test_container_slist \ test_crypto_aes \ test_crypto_aes_weak \ test_crypto_crc \ @@ -175,6 +177,11 @@ test_container_heap_SOURCES = \ test_container_heap_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la +test_container_slist_SOURCES = \ + test_container_slist.c +test_container_slist_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + test_crypto_aes_SOURCES = \ test_crypto_aes.c test_crypto_aes_LDADD = \ diff --git a/src/util/container_slist.c b/src/util/container_slist.c new file mode 100644 index 000000000..c279bb2ea --- /dev/null +++ b/src/util/container_slist.c @@ -0,0 +1,270 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet 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 2, or (at your + option) any later version. + + GNUnet 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 GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/container_slist.c + * @brief Implementation of a singly-linked list + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_container_lib.h" + +struct GNUNET_CONTAINER_SList_Elem +{ + void *elem; + size_t len; + int disp; + struct GNUNET_CONTAINER_SList_Elem *next; +}; + +struct GNUNET_CONTAINER_SList +{ + struct GNUNET_CONTAINER_SList_Elem head; +}; + +struct GNUNET_CONTAINER_SList_Iterator +{ + struct GNUNET_CONTAINER_SList_Elem *last; + struct GNUNET_CONTAINER_SList_Elem *elem; +}; + +/** + * Create a new element that is to be inserted into the list + * @internal + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + * @return a new element + */ +static struct GNUNET_CONTAINER_SList_Elem * +create_elem (int disp, const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + e = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList_Elem)); + e->disp = disp; + if (disp == GNUNET_MEM_DISP_TRANSIENT) + { + e->elem = GNUNET_malloc (len); + memcpy (e->elem, buf, len); + } + else + e->elem = (void *) buf; + e->len = len; + + return e; +} + +/** + * Add a new element to the list + * @param l list + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the buffer + */ +void +GNUNET_CONTAINER_slist_add (struct GNUNET_CONTAINER_SList *l, int disp, + const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + e = create_elem (disp, buf, len); + e->next = l->head.next; + l->head.next = e; +} + +/** + * Create a new singly linked list + * @return the new list + */ +struct GNUNET_CONTAINER_SList * +GNUNET_CONTAINER_slist_create () +{ + struct GNUNET_CONTAINER_SList *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList)); + if (NULL == ret) + return NULL; + + memset (&ret->head, 0, sizeof (struct GNUNET_CONTAINER_SList)); + + return ret; +} + +/** + * Destroy a singly linked list + * @param l the list to be destroyed + */ +void +GNUNET_CONTAINER_slist_destroy (struct GNUNET_CONTAINER_SList *l) +{ + GNUNET_CONTAINER_slist_clear (l); + GNUNET_free (l); +} + +/** + * Return the beginning of a list + * @param l list + * @return iterator pointing to the beginning + */ +const struct GNUNET_CONTAINER_SList_Iterator * +GNUNET_CONTAINER_slist_begin (const struct GNUNET_CONTAINER_SList *l) +{ + struct GNUNET_CONTAINER_SList_Iterator *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList_Iterator)); + ret->elem = l->head.next; + ret->last = (struct GNUNET_CONTAINER_SList_Elem *) &l->head; + return ret; +} + +/** + * Clear a list + * @param l list + */ +void +GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l) +{ + struct GNUNET_CONTAINER_SList_Elem *e, *n; + + e = l->head.next; + while (e != NULL) + { + if (e->disp != GNUNET_MEM_DISP_STATIC) + GNUNET_free (e->elem); + n = e->next; + GNUNET_free (e); + e = n; + } + l->head.next = NULL; +} + +/** + * Check if a list contains a certain element + * @param l list + * @param buf payload buffer to find + * @param lenght of the payload + */ +int +GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, + const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + for (e = l->head.next; e != NULL; e = e->next) + if (e->len == len && memcmp (buf, e->elem, len) == 0) + return GNUNET_YES; + + return GNUNET_NO; +} + +/** + * Count the elements of a list + * @param l list + * @return number of elements in the list + */ +int +GNUNET_CONTAINER_slist_count (const struct GNUNET_CONTAINER_SList *l) +{ + int n; + struct GNUNET_CONTAINER_SList_Elem *e; + + for (n = 0, e = l->head.next; e != NULL; e = e->next) + n++; + + return n; +} + +/** + * Remove an element from the list + * @param i iterator that points to the element to be removed + */ +void +GNUNET_CONTAINER_slist_erase (struct GNUNET_CONTAINER_SList_Iterator *i) +{ + struct GNUNET_CONTAINER_SList_Elem *next; + + next = i->elem->next; + i->last->next = next; + if (i->elem->disp != GNUNET_MEM_DISP_STATIC) + GNUNET_free (i->elem->elem); + GNUNET_free (i->elem); + i->elem = next; +} + +/** + * Insert an element into a list at a specific position + * @param before where to insert the new element + * @param disp memory disposition + * @param buf payload buffer + * @param len length of the payload + */ +void +GNUNET_CONTAINER_slist_insert (struct GNUNET_CONTAINER_SList_Iterator *before, + int disp, const void *buf, size_t len) +{ + struct GNUNET_CONTAINER_SList_Elem *e; + + e = create_elem (disp, buf, len); + e->next = before->elem; + before->last->next = e; +} + +/** + * Advance an iterator to the next element + * @param i iterator + * @return GNUNET_YES on success, GNUNET_NO if the end has been reached + */ +int +GNUNET_CONTAINER_slist_next (struct GNUNET_CONTAINER_SList_Iterator *i) +{ + i->last = i->elem; + i->elem = i->elem->next; + + return i->elem != NULL; +} + +/** + * Check if an iterator points beyond the end of a list + * @param i iterator + * @return GNUNET_YES if the end has been reached, GNUNET_NO if the iterator + * points to a valid element + */ +int +GNUNET_CONTAINER_slist_end (struct GNUNET_CONTAINER_SList_Iterator *i) +{ + return i->elem == NULL; +} + +/** + * Retrieve the element at a specific position in a list + * @param i iterator + * @param len payload length + * @return payload + */ +void * +GNUNET_CONTAINER_slist_get (const struct GNUNET_CONTAINER_SList_Iterator *i, + size_t * len) +{ + if (len) + *len = i->elem->len; + return i->elem->elem; +} diff --git a/src/util/network.c b/src/util/network.c index 30b2873cb..fa5dcf503 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -43,7 +43,7 @@ struct GNUNET_NETWORK_FDSet fd_set sds; #ifdef WINDOWS /* handles */ - struct GNUNET_CONTAINER_Vector *handles; + struct GNUNET_CONTAINER_SList *handles; #endif }; @@ -416,9 +416,7 @@ GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds) FD_ZERO (&fds->sds); fds->nsds = 0; #ifdef MINGW - if (fds->handles) - GNUNET_CONTAINER_vector_destroy (fds->handles); - fds->handles = GNUNET_CONTAINER_vector_create (2); + GNUNET_CONTAINER_slist_clear (fds->handles); #endif } @@ -486,15 +484,19 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, FD_COPY (&from->sds, &to->sds); to->nsds = from->nsds; #ifdef MINGW - void *obj; + struct GNUNET_CONTAINER_SList_Iterator *iter; - if (to->handles) - GNUNET_CONTAINER_vector_destroy (to->handles); - to->handles = GNUNET_CONTAINER_vector_create (2); - for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL; - obj = GNUNET_CONTAINER_vector_get_next (from->handles)) + + GNUNET_CONTAINER_slist_clear (to->handles); + + for (iter = GNUNET_CONTAINER_slist_begin (from->handles); + GNUNET_CONTAINER_slist_end (iter); GNUNET_CONTAINER_slist_next (iter)) { - GNUNET_CONTAINER_vector_insert_last (to->handles, obj); + void *handle; + size_t len; + + handle = GNUNET_CONTAINER_slist_get (iter, &len); + GNUNET_CONTAINER_slist_add (to->handles, GNUNET_MEM_DISP_TRANSIENT, handle, len); } #endif } @@ -528,7 +530,7 @@ GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, HANDLE hw; GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE)); - GNUNET_CONTAINER_vector_insert_last (fds->handles, h); + GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE)); #else int fd; @@ -550,8 +552,7 @@ GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h) { #ifdef MINGW - return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) != - (unsigned int) -1; + return GNUNET_CONTAINER_slist_contains (fds->handles, h->h, sizeof (HANDLE)); #else return FD_ISSET (h->fd, &fds->sds); #endif @@ -606,7 +607,7 @@ void GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) { #ifdef MINGW - GNUNET_CONTAINER_vector_destroy (fds->handles); + GNUNET_CONTAINER_slist_destroy (fds->handles); #endif GNUNET_free (fds); } @@ -736,50 +737,76 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, /* Poll read pipes */ if (rfds) - for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--) - { - DWORD dwBytes; - - if (!PeekNamedPipe - (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0, - NULL, &dwBytes, NULL)) - { - GNUNET_CONTAINER_vector_remove_at (rfds->handles, i); - - retcode = -1; - SetErrnoFromWinError (GetLastError ()); + { + struct GNUNET_CONTAINER_SList_Iterator *i; + int on_next; + + on_next = GNUNET_NO; + for (i = GNUNET_CONTAINER_slist_begin (rfds->handles); + GNUNET_CONTAINER_slist_end (i) != GNUNET_YES; + on_next || GNUNET_CONTAINER_slist_next (i)) + { + HANDLE h; + DWORD dwBytes; + + h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL); + on_next = GNUNET_NO; + + if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL)) + { + GNUNET_CONTAINER_slist_erase (i); + on_next = GNUNET_YES; + + retcode = -1; + SetErrnoFromWinError (GetLastError ()); #if DEBUG_SOCK - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe"); + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe"); #endif - goto select_loop_end; - } - else if (dwBytes) - { - retcode++; - } - else - GNUNET_CONTAINER_vector_remove_at (rfds->handles, i); - } + goto select_loop_end; + } + else if (dwBytes) + { + retcode++; + } + else + { + GNUNET_CONTAINER_slist_erase (i); + on_next = GNUNET_YES; + } + } + } /* Poll for faulty pipes */ if (efds) - for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--) - { - DWORD dwBytes; + { + struct GNUNET_CONTAINER_SList_Iterator *i; + int on_next; + + on_next = GNUNET_NO; + for (i = GNUNET_CONTAINER_slist_begin (efds->handles); + GNUNET_CONTAINER_slist_end (i) != GNUNET_YES; + on_next || GNUNET_CONTAINER_slist_next (i)) + { + HANDLE h; + DWORD dwBytes; + + h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL); - if (PeekNamedPipe - (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0, - NULL, &dwBytes, NULL)) - { - GNUNET_CONTAINER_vector_remove_at (efds->handles, i); + if (PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL)) + { + GNUNET_CONTAINER_slist_erase (i); + on_next = GNUNET_YES; - retcode++; - } - } + retcode++; + } + else + on_next = GNUNET_NO; + } + } /* FIXME */ if (wfds) - GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0); + GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0); /* Check for closed sockets */ for (i = 0; i < nfds; i++) diff --git a/src/util/test_container_slist.c b/src/util/test_container_slist.c new file mode 100644 index 000000000..a22d4be8a --- /dev/null +++ b/src/util/test_container_slist.c @@ -0,0 +1,109 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet 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 2, or (at your + option) any later version. + + GNUnet 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 GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file util/test_container_slist.c + * @brief Testcases for singly linked lists + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_container_lib.h" + +#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); return 1; } +#define CHECK(c) { if (! (c)) ABORT(); } + +int +main (int argc, char *argv[]) +{ + struct GNUNET_CONTAINER_SList *l; + struct GNUNET_CONTAINER_SList_Iterator *it; + unsigned int i, j, s; + + + GNUNET_log_setup ("test-container-slist", "WARNING", NULL); + + l = GNUNET_CONTAINER_slist_create (); + CHECK (l != NULL); + CHECK (GNUNET_CONTAINER_slist_count (l) == 0); + + for (i = 0; i < 100; i++) + GNUNET_CONTAINER_slist_add (l, GNUNET_MEM_DISP_TRANSIENT, &i, sizeof (i)); + CHECK (GNUNET_CONTAINER_slist_count (l) == 100); + + for (it = GNUNET_CONTAINER_slist_begin (l), i = 99; + GNUNET_CONTAINER_slist_end (it) != GNUNET_YES; + GNUNET_CONTAINER_slist_next (it), i--) + { + void *p; + + p = GNUNET_CONTAINER_slist_get (it, &s); + CHECK (p != NULL); + j = *(int *) p; + CHECK (i == j); + CHECK (s == sizeof (i)); + + j *= 2; + GNUNET_CONTAINER_slist_insert (it, GNUNET_MEM_DISP_TRANSIENT, &j, + sizeof (j)); + } + CHECK (GNUNET_CONTAINER_slist_count (l) == 200); + i = 198; + CHECK (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i))); + + for (it = GNUNET_CONTAINER_slist_begin (l); + GNUNET_CONTAINER_slist_end (it) != GNUNET_YES;) + { + void *p; + + p = GNUNET_CONTAINER_slist_get (it, &s); + CHECK (p != NULL); + CHECK (s == sizeof (i)); + i = *(int *) p; + + CHECK (GNUNET_CONTAINER_slist_next (it) == GNUNET_YES); + CHECK (GNUNET_CONTAINER_slist_end (it) != GNUNET_YES); + + p = GNUNET_CONTAINER_slist_get (it, &s); + CHECK (p != NULL); + CHECK (s == sizeof (j)); + j = *(int *) p; + + CHECK (j * 2 == i); + + GNUNET_CONTAINER_slist_erase (it); + } + CHECK (GNUNET_CONTAINER_slist_count (l) == 100); + i = 99; + CHECK (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i)) == GNUNET_NO); + i = 198; + CHECK (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i))); + + GNUNET_CONTAINER_slist_clear (l); + CHECK (GNUNET_CONTAINER_slist_count (l) == 0); + + for (i = 0; i < 100; i++) + GNUNET_CONTAINER_slist_add (l, GNUNET_MEM_DISP_TRANSIENT, &i, sizeof (i)); + + GNUNET_CONTAINER_slist_destroy (l); + + return 0; +}