#endif
+#define GNUNET_MEM_DISP_TRANSIENT 0
+#define GNUNET_MEM_DISP_STATIC 2
+#define GNUNET_MEM_DISP_DYNAMIC 4
+
/* ******************* bloomfilter ***************** */
/**
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 */
container_heap.c \
container_meta_data.c \
container_multihashmap.c \
+ container_slist.c \
crypto_aes.c \
crypto_crc.c \
crypto_hash.c \
test_container_meta_data \
test_container_multihashmap \
test_container_heap \
+ test_container_slist \
test_crypto_aes \
test_crypto_aes_weak \
test_crypto_crc \
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 = \
--- /dev/null
+/*
+ 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;
+}
fd_set sds;\r
#ifdef WINDOWS\r
/* handles */\r
- struct GNUNET_CONTAINER_Vector *handles;\r
+ struct GNUNET_CONTAINER_SList *handles;\r
#endif\r
};\r
\r
FD_ZERO (&fds->sds);\r
fds->nsds = 0;\r
#ifdef MINGW\r
- if (fds->handles)\r
- GNUNET_CONTAINER_vector_destroy (fds->handles);\r
- fds->handles = GNUNET_CONTAINER_vector_create (2);\r
+ GNUNET_CONTAINER_slist_clear (fds->handles);\r
#endif\r
}\r
\r
FD_COPY (&from->sds, &to->sds);\r
to->nsds = from->nsds;\r
#ifdef MINGW\r
- void *obj;\r
+ struct GNUNET_CONTAINER_SList_Iterator *iter;\r
\r
- if (to->handles)\r
- GNUNET_CONTAINER_vector_destroy (to->handles);\r
- to->handles = GNUNET_CONTAINER_vector_create (2);\r
- for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL;\r
- obj = GNUNET_CONTAINER_vector_get_next (from->handles))\r
+\r
+ GNUNET_CONTAINER_slist_clear (to->handles);\r
+\r
+ for (iter = GNUNET_CONTAINER_slist_begin (from->handles);\r
+ GNUNET_CONTAINER_slist_end (iter); GNUNET_CONTAINER_slist_next (iter))\r
{\r
- GNUNET_CONTAINER_vector_insert_last (to->handles, obj);\r
+ void *handle;\r
+ size_t len;\r
+\r
+ handle = GNUNET_CONTAINER_slist_get (iter, &len);\r
+ GNUNET_CONTAINER_slist_add (to->handles, GNUNET_MEM_DISP_TRANSIENT, handle, len);\r
}\r
#endif\r
}\r
HANDLE hw;\r
\r
GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE));\r
- GNUNET_CONTAINER_vector_insert_last (fds->handles, h);\r
+ GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE));\r
#else\r
int fd;\r
\r
const struct GNUNET_DISK_FileHandle *h)\r
{\r
#ifdef MINGW\r
- return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) !=\r
- (unsigned int) -1;\r
+ return GNUNET_CONTAINER_slist_contains (fds->handles, h->h, sizeof (HANDLE));\r
#else\r
return FD_ISSET (h->fd, &fds->sds);\r
#endif\r
GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
{\r
#ifdef MINGW\r
- GNUNET_CONTAINER_vector_destroy (fds->handles);\r
+ GNUNET_CONTAINER_slist_destroy (fds->handles);\r
#endif\r
GNUNET_free (fds);\r
}\r
\r
/* Poll read pipes */\r
if (rfds)\r
- for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--)\r
- {\r
- DWORD dwBytes;\r
-\r
- if (!PeekNamedPipe\r
- (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
- NULL, &dwBytes, NULL))\r
- {\r
- GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
-\r
- retcode = -1;\r
- SetErrnoFromWinError (GetLastError ());\r
+ {\r
+ struct GNUNET_CONTAINER_SList_Iterator *i;\r
+ int on_next;\r
+\r
+ on_next = GNUNET_NO;\r
+ for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);\r
+ GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
+ on_next || GNUNET_CONTAINER_slist_next (i))\r
+ {\r
+ HANDLE h;\r
+ DWORD dwBytes;\r
+\r
+ h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
+ on_next = GNUNET_NO;\r
+\r
+ if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
+ {\r
+ GNUNET_CONTAINER_slist_erase (i);\r
+ on_next = GNUNET_YES;\r
+\r
+ retcode = -1;\r
+ SetErrnoFromWinError (GetLastError ());\r
#if DEBUG_SOCK\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
#endif\r
- goto select_loop_end;\r
- }\r
- else if (dwBytes)\r
- {\r
- retcode++;\r
- }\r
- else\r
- GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
- }\r
+ goto select_loop_end;\r
+ }\r
+ else if (dwBytes)\r
+ {\r
+ retcode++;\r
+ }\r
+ else\r
+ {\r
+ GNUNET_CONTAINER_slist_erase (i);\r
+ on_next = GNUNET_YES;\r
+ }\r
+ }\r
+ }\r
\r
/* Poll for faulty pipes */\r
if (efds)\r
- for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--)\r
- {\r
- DWORD dwBytes;\r
+ {\r
+ struct GNUNET_CONTAINER_SList_Iterator *i;\r
+ int on_next;\r
+\r
+ on_next = GNUNET_NO;\r
+ for (i = GNUNET_CONTAINER_slist_begin (efds->handles);\r
+ GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
+ on_next || GNUNET_CONTAINER_slist_next (i))\r
+ {\r
+ HANDLE h;\r
+ DWORD dwBytes;\r
+\r
+ h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
\r
- if (PeekNamedPipe\r
- (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
- NULL, &dwBytes, NULL))\r
- {\r
- GNUNET_CONTAINER_vector_remove_at (efds->handles, i);\r
+ if (PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
+ {\r
+ GNUNET_CONTAINER_slist_erase (i);\r
+ on_next = GNUNET_YES;\r
\r
- retcode++;\r
- }\r
- }\r
+ retcode++;\r
+ }\r
+ else\r
+ on_next = GNUNET_NO;\r
+ }\r
+ }\r
\r
/* FIXME */\r
if (wfds)\r
- GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0);\r
+ GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0);\r
\r
/* Check for closed sockets */\r
for (i = 0; i < nfds; i++)\r
--- /dev/null
+/*
+ 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;
+}