From 5d5424d6882291fbb52090318e7b76d7c4f66b00 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 7 Nov 2018 10:21:38 +0000 Subject: [PATCH 01/10] Feature: Added stub files for refobject lists --- Makefile.am | 6 ++++-- include/igloo/list.h | 30 ++++++++++++++++++++++++++++++ src/list.c | 23 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 include/igloo/list.h create mode 100644 src/list.c diff --git a/Makefile.am b/Makefile.am index f1b5ce1..99dfb14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,12 +20,14 @@ pkginclude_HEADERS = \ include/igloo/ro.h \ include/igloo/types.h \ include/igloo/typedef.h \ - include/igloo/buffer.h + include/igloo/buffer.h \ + include/igloo/list.h libigloo_la_SOURCES = \ src/libigloo.c \ src/ro.c \ - src/buffer.c + src/buffer.c \ + src/list.c libigloo_la_LIBADD = \ avl/libiceavl.la \ httpp/libicehttpp.la \ diff --git a/include/igloo/list.h b/include/igloo/list.h new file mode 100644 index 0000000..d5eaa3b --- /dev/null +++ b/include/igloo/list.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _LIBIGLOO__LIST_H_ +#define _LIBIGLOO__LIST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..480dfbc --- /dev/null +++ b/src/list.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include From 336553165b670b0ac5d06eb2fcf5b01f6a52bebf Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 7 Nov 2018 14:01:03 +0000 Subject: [PATCH 02/10] Feature: Implemented igloo_list_t --- include/igloo/list.h | 49 ++++++++ include/igloo/ro.h | 1 + include/igloo/types.h | 2 + src/list.c | 278 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 330 insertions(+) diff --git a/include/igloo/list.h b/include/igloo/list.h index d5eaa3b..ddf7fe0 100644 --- a/include/igloo/list.h +++ b/include/igloo/list.h @@ -23,6 +23,55 @@ extern "C" { #endif +#include + +/* About thread safety: + * This set of functions is intentinally not thread safe. + */ + +typedef struct igloo_list_iterator_tag igloo_list_iterator_t; +typedef struct igloo_list_iterator_tag igloo_list_iterator_storage_t; + +igloo_RO_FORWARD_TYPE(igloo_list_t); + +/* ---[ PRIVATE ]--- */ +struct igloo_list_iterator_tag { + igloo_list_t *list; + size_t idx; +}; +/* ---[ END PRIVATE ]--- */ + +/* + * Those types are defined here as they must be known to the compiler. + * Nobody should ever try to access them directly. + */ +void igloo_list_preallocate(igloo_list_t *list, size_t request); +int igloo_list_set_type__real(igloo_list_t *list, const igloo_ro_type_t *type); +#define igloo_list_set_type(list,type) igloo_list_set_type__real((list),(igloo_ro__type__ ## type)) +int igloo_list_push(igloo_list_t *list, igloo_ro_t element); +int igloo_list_unshift(igloo_list_t *list, igloo_ro_t element); +igloo_ro_t igloo_list_shift(igloo_list_t *list); +igloo_ro_t igloo_list_pop(igloo_list_t *list); + +int igloo_list_merge(igloo_list_t *list, igloo_list_t *elements); + +igloo_list_iterator_t * igloo_list_iterator_start(igloo_list_t *list, void *storage, size_t storage_length); +igloo_ro_t igloo_list_iterator_next(igloo_list_iterator_t *iterator); +void igloo_list_iterator_end(igloo_list_iterator_t *iterator); +int igloo_list_iterator_rewind(igloo_list_iterator_t *iterator); + +#define igloo_list_foreach(list,type,var,code) \ +do { \ + igloo_list_iterator_storage_t __igloo_list_iterator_storage; \ + igloo_list_iterator_t *__igloo_list_iterator = igloo_list_iterator_start((list), &__igloo_list_iterator_storage, sizeof(__igloo_list_iterator_storage)); \ + type var; \ + for (; !igloo_RO_IS_NULL((var) = igloo_RO_TO_TYPE(igloo_list_iterator_next(__igloo_list_iterator),type));) { \ + code; \ + igloo_ro_unref((var)); \ + } \ + igloo_list_iterator_end(__igloo_list_iterator); \ +} while (0); + #ifdef __cplusplus } #endif diff --git a/include/igloo/ro.h b/include/igloo/ro.h index ae429bf..fbed872 100644 --- a/include/igloo/ro.h +++ b/include/igloo/ro.h @@ -102,6 +102,7 @@ int igloo_ro_new__return_zero(igloo_ro_t self, const igloo_ro_type_t *type, va_l #define igloo_RO_GET_TYPE(x) (igloo_RO__GETBASE((x)) == NULL ? NULL : igloo_RO__GETBASE((x))->type) #define igloo_RO_GET_TYPENAME(x) (igloo_RO_GET_TYPE((x)) == NULL ? NULL : igloo_RO_GET_TYPE((x))->type_name) #define igloo_RO_IS_VALID(x,type) (!igloo_RO_IS_NULL((x)) && igloo_RO_GET_TYPE((x)) == (igloo_ro__type__ ## type)) +#define igloo_RO_HAS_TYPE(x,type) (!igloo_RO_IS_NULL((x)) && igloo_RO_GET_TYPE((x)) == (type)) /* Create a new refobject * The type argument gives the type for the new object, diff --git a/include/igloo/types.h b/include/igloo/types.h index ace9b20..d9c4494 100644 --- a/include/igloo/types.h +++ b/include/igloo/types.h @@ -33,6 +33,7 @@ extern "C" { #include "typedef.h" typedef struct igloo_buffer_tag igloo_buffer_t; +typedef struct igloo_list_tag igloo_list_t; /* * This header includes forward declarations for several basic types. @@ -47,6 +48,7 @@ typedef union __attribute__ ((__transparent_union__)) { /* Those are libigloo's own types */ igloo_RO_TYPE(igloo_ro_base_t) igloo_RO_TYPE(igloo_buffer_t) + igloo_RO_TYPE(igloo_list_t) /* Now we add the current compilation unit's private types if any */ #ifdef igloo_RO_PRIVATETYPES diff --git a/src/list.c b/src/list.c index 480dfbc..3a0fe09 100644 --- a/src/list.c +++ b/src/list.c @@ -20,4 +20,282 @@ #include #endif +#include +#include + #include + +struct igloo_list_tag { + igloo_ro_base_t __base; + size_t offset; + size_t fill; + size_t length; + igloo_ro_t *elements; + const igloo_ro_type_t *type; +}; + +static void __free(igloo_ro_t self); + +igloo_RO_PUBLIC_TYPE(igloo_list_t, + igloo_RO_TYPEDECL_FREE(__free), + igloo_RO_TYPEDECL_NEW_NOOP() + ); + +static void __free(igloo_ro_t self) +{ + igloo_list_t *list = igloo_RO_TO_TYPE(self, igloo_list_t); + size_t i; + + for (i = list->offset; i < list->fill; i++) { + igloo_ro_unref(list->elements[i]); + } +} + +static inline void igloo_list_preallocate__realign(igloo_list_t *list) +{ + if (!list->offset) + return; + + memmove(list->elements, list->elements + list->offset, (list->fill - list->offset)*sizeof(*list->elements)); +} + +void igloo_list_preallocate(igloo_list_t *list, size_t request) +{ + size_t new_len; + + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return; + + new_len = (list->fill - list->offset) + request; + + if (new_len > list->length || (new_len + 32) > list->length) { + igloo_ro_t *n; + + igloo_list_preallocate__realign(list); + + n = realloc(list->elements, new_len*sizeof(*list->elements)); + if (!n) + return; + + list->elements = n; + list->length = new_len; + } + + if (list->offset > 16) + igloo_list_preallocate__realign(list); +} + +int igloo_list_set_type__real(igloo_list_t *list, const igloo_ro_type_t *type) +{ + size_t i; + + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return -1; + + for (i = list->offset; i < list->fill; i++) { + if (!igloo_RO_HAS_TYPE(list->elements[i], type)) { + return -1; + } + } + + list->type = type; + return 0; +} + +int igloo_list_push(igloo_list_t *list, igloo_ro_t element) +{ + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return -1; + + if ((list->type && !igloo_RO_HAS_TYPE(element, list->type)) || igloo_RO_IS_NULL(element)) + return -1; + + igloo_list_preallocate(list, 1); + + if (list->fill == list->length) + return -1; + + if (igloo_ro_ref(element) != 0) + return -1; + + list->elements[list->fill++] = element; + + return 0; +} +int igloo_list_unshift(igloo_list_t *list, igloo_ro_t element) +{ + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return -1; + + if (list->offset == list->fill) + return igloo_list_push(list, element); + + if ((list->type && !igloo_RO_HAS_TYPE(element, list->type)) || igloo_RO_IS_NULL(element)) + return -1; + + if (!list->offset) { + igloo_list_preallocate(list, 1); + + if (list->fill == list->length) + return -1; + + memmove(list->elements + 1, list->elements, sizeof(*list->elements)*list->fill); + list->offset++; + list->fill++; + } + + if (!list->offset) + return -1; + + if (igloo_ro_ref(element) != 0) + return -1; + + list->elements[--list->offset] = element; + + return 0; +} + +igloo_ro_t igloo_list_shift(igloo_list_t *list) +{ + igloo_ro_t ret; + + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return igloo_RO_NULL; + + if (list->offset == list->fill) + return igloo_RO_NULL; + + ret = list->elements[list->offset++]; + + igloo_list_preallocate(list, 0); + + return ret; +} + +igloo_ro_t igloo_list_pop(igloo_list_t *list) +{ + igloo_ro_t ret; + + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return igloo_RO_NULL; + + if (list->offset == list->fill) + return igloo_RO_NULL; + + ret = list->elements[--list->fill]; + + igloo_list_preallocate(list, 0); + + return ret; +} + +static inline int igloo_list_copy_elements(igloo_list_t *list, igloo_list_t *elements) +{ + size_t i; + + for (i = elements->offset; i < elements->fill; i++) { + if (list->fill == list->length) { + igloo_list_preallocate(list, 1); + + if (list->fill == list->length) + return -1; + } + + if (igloo_ro_ref(elements->elements[i]) != 0) + return -1; + + list->elements[list->fill++] = elements->elements[i]; + } + + return 0; +} + +int igloo_list_merge(igloo_list_t *list, igloo_list_t *elements) +{ + size_t old_fill; + + if (!igloo_RO_IS_VALID(list, igloo_list_t) || !igloo_RO_IS_VALID(elements, igloo_list_t)) + return -1; + + if (list->type) { + size_t i; + + for (i = elements->offset; i < elements->fill; i++) { + if (!igloo_RO_HAS_TYPE(elements->elements[i], list->type)) + return -1; + } + } + + igloo_list_preallocate(list, elements->fill - elements->offset); + + old_fill = list->fill; + if (igloo_list_copy_elements(list, elements) != 0) { + size_t i; + + for (i = old_fill; i < list->fill; i++) { + igloo_ro_unref(list->elements[i]); + } + + list->fill = old_fill; + + return -1; + } + + return 0; +} + +igloo_list_iterator_t * igloo_list_iterator_start(igloo_list_t *list, void *storage, size_t storage_length) +{ + igloo_list_iterator_t *iterator; + + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return NULL; + + if (!storage || storage_length != sizeof(igloo_list_iterator_t)) + return NULL; + + iterator = storage; + memset(iterator, 0, sizeof(*iterator)); + + if (igloo_ro_ref(list) != 0) + return NULL; + + iterator->list = list; + + igloo_list_iterator_rewind(iterator); + + return iterator; +} + +igloo_ro_t igloo_list_iterator_next(igloo_list_iterator_t *iterator) +{ + size_t physical; + + physical = iterator->idx + iterator->list->offset; + + if (physical >= iterator->list->fill) + return igloo_RO_NULL; + + if (igloo_ro_unref(iterator->list->elements[physical]) == 0) + return igloo_RO_NULL; + + iterator->idx++; + + return iterator->list->elements[physical]; +} +void igloo_list_iterator_end(igloo_list_iterator_t *iterator) +{ + if (!iterator) + return; + + igloo_ro_unref(iterator->list); +} +int igloo_list_iterator_rewind(igloo_list_iterator_t *iterator) +{ + if (!iterator) + return -1; + + iterator->idx = 0; + + return 0; +} From eec0dc6c845f47571c3466c542d8269893ed22ef Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 7 Nov 2018 14:08:59 +0000 Subject: [PATCH 03/10] Fix: Correctly realign elements in list if space at the end is requested --- src/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/list.c b/src/list.c index 3a0fe09..7f37184 100644 --- a/src/list.c +++ b/src/list.c @@ -81,7 +81,7 @@ void igloo_list_preallocate(igloo_list_t *list, size_t reques list->length = new_len; } - if (list->offset > 16) + if (list->offset > 16 || ((list->length - list->fill) < request)) igloo_list_preallocate__realign(list); } From 4b579f596c8d6498e90b2eb4fdca7b9948492a2a Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 10:54:08 +0000 Subject: [PATCH 04/10] Fix: Corrected offset and fill pointer on realign --- src/list.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/list.c b/src/list.c index 7f37184..7cf522a 100644 --- a/src/list.c +++ b/src/list.c @@ -53,10 +53,15 @@ static void __free(igloo_ro_t self) static inline void igloo_list_preallocate__realign(igloo_list_t *list) { + size_t new_len; + if (!list->offset) return; - memmove(list->elements, list->elements + list->offset, (list->fill - list->offset)*sizeof(*list->elements)); + new_len = list->fill - list->offset; + memmove(list->elements, list->elements + list->offset, new_len*sizeof(*list->elements)); + list->offset = 0; + list->fill = new_len; } void igloo_list_preallocate(igloo_list_t *list, size_t request) From 28fea532cf1ed1ea494803b2fd878ffe1b37dad4 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 13:14:22 +0000 Subject: [PATCH 05/10] Feature: Added igloo_list_clear() --- include/igloo/list.h | 1 + src/list.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/igloo/list.h b/include/igloo/list.h index ddf7fe0..bf90eac 100644 --- a/include/igloo/list.h +++ b/include/igloo/list.h @@ -45,6 +45,7 @@ struct igloo_list_iterator_tag { * Those types are defined here as they must be known to the compiler. * Nobody should ever try to access them directly. */ +int igloo_list_clear(igloo_list_t *list); void igloo_list_preallocate(igloo_list_t *list, size_t request); int igloo_list_set_type__real(igloo_list_t *list, const igloo_ro_type_t *type); #define igloo_list_set_type(list,type) igloo_list_set_type__real((list),(igloo_ro__type__ ## type)) diff --git a/src/list.c b/src/list.c index 7cf522a..f528e11 100644 --- a/src/list.c +++ b/src/list.c @@ -44,11 +44,24 @@ igloo_RO_PUBLIC_TYPE(igloo_list_t, static void __free(igloo_ro_t self) { igloo_list_t *list = igloo_RO_TO_TYPE(self, igloo_list_t); + igloo_list_clear(list); +} + +int igloo_list_clear(igloo_list_t *list) +{ size_t i; + if (!igloo_RO_IS_VALID(list, igloo_list_t)) + return -1; + for (i = list->offset; i < list->fill; i++) { igloo_ro_unref(list->elements[i]); } + + list->offset = 0; + list->fill = 0; + + return 0; } static inline void igloo_list_preallocate__realign(igloo_list_t *list) From f744fff84de254aae6cbcafa13f4c6c12f21e6b9 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 13:15:11 +0000 Subject: [PATCH 06/10] Fix: Corrected igloo_list_iterator_next()'s reference counting --- src/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/list.c b/src/list.c index f528e11..c76cd8b 100644 --- a/src/list.c +++ b/src/list.c @@ -294,7 +294,7 @@ igloo_ro_t igloo_list_iterator_next(igloo_list_iterator_t *iterator if (physical >= iterator->list->fill) return igloo_RO_NULL; - if (igloo_ro_unref(iterator->list->elements[physical]) == 0) + if (igloo_ro_ref(iterator->list->elements[physical]) != 0) return igloo_RO_NULL; iterator->idx++; From 8255b1bd212ceeb79ccc91cab22aca3ac922e3b6 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 13:26:09 +0000 Subject: [PATCH 07/10] Fix: Corrected igloo_list_foreach()'s understanding of type and pointer-of-type --- include/igloo/list.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/igloo/list.h b/include/igloo/list.h index bf90eac..5bf1264 100644 --- a/include/igloo/list.h +++ b/include/igloo/list.h @@ -65,7 +65,7 @@ int igloo_list_iterator_rewind(igloo_list_iterator_t *iterat do { \ igloo_list_iterator_storage_t __igloo_list_iterator_storage; \ igloo_list_iterator_t *__igloo_list_iterator = igloo_list_iterator_start((list), &__igloo_list_iterator_storage, sizeof(__igloo_list_iterator_storage)); \ - type var; \ + type * var; \ for (; !igloo_RO_IS_NULL((var) = igloo_RO_TO_TYPE(igloo_list_iterator_next(__igloo_list_iterator),type));) { \ code; \ igloo_ro_unref((var)); \ From f9377086a4988071ba72c32c58ac8351a44150c0 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 13:28:25 +0000 Subject: [PATCH 08/10] Feature: Added tests for igloo_list_t --- src/tests/Makefile.am | 7 + src/tests/ctest_list.c | 419 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 426 insertions(+) create mode 100644 src/tests/ctest_list.c diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index deb6469..db53be0 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -39,6 +39,13 @@ ctest_buffer_test_LDADD = libice_ctest.la \ src/buffer.o check_PROGRAMS += ctest_buffer.test +ctest_list_test_SOURCES = %reldir%/ctest_list.c +ctest_list_test_LDADD = libice_ctest.la \ + thread/libicethread.la \ + avl/libiceavl.la \ + src/ro.o \ + src/list.o +check_PROGRAMS += ctest_list.test # Add all programs to TESTS TESTS = $(check_PROGRAMS) diff --git a/src/tests/ctest_list.c b/src/tests/ctest_list.c new file mode 100644 index 0000000..655575d --- /dev/null +++ b/src/tests/ctest_list.c @@ -0,0 +1,419 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "ctest_lib.h" + +#include +#include + +static void test_create_ref_unref(void) +{ + igloo_list_t *a; + + a = igloo_ro_new(igloo_list_t); + ctest_test("list created", !igloo_RO_IS_NULL(a)); + + ctest_test("un-referenced", igloo_ro_unref(a) == 0); +} + +static void test__create_push_unshift(igloo_list_t **list, igloo_ro_base_t **a, igloo_ro_base_t **b) +{ + *list = NULL; + *a = NULL; + *b = NULL; + + *list = igloo_ro_new(igloo_list_t); + + ctest_test("list created", !igloo_RO_IS_NULL(*list)); + + *a = igloo_ro_new(igloo_ro_base_t); + ctest_test("test object a created", !igloo_RO_IS_NULL(*a)); + + *b = igloo_ro_new(igloo_ro_base_t); + ctest_test("test object b created", !igloo_RO_IS_NULL(*b)); + + ctest_test("test object a pushed", igloo_list_push(*list, *a) == 0); + ctest_test("test object b unshifted", igloo_list_unshift(*list, *b) == 0); +} + +static void test_list_push_unshift(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + + test__create_push_unshift(&list, &a, &b); + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +static void test_list_push_unshift_pop(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + test__create_push_unshift(&list, &a, &b); + + ret = igloo_list_pop(list); + ctest_test("popped element", !igloo_RO_IS_NULL(ret)); + ctest_test("popped element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced popped element", igloo_ro_unref(ret) == 0); + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +static void test_list_push_unshift_pop_pop(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + test__create_push_unshift(&list, &a, &b); + + ret = igloo_list_pop(list); + ctest_test("popped element", !igloo_RO_IS_NULL(ret)); + ctest_test("popped element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced popped element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_pop(list); + ctest_test("popped element", !igloo_RO_IS_NULL(ret)); + ctest_test("popped element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced popped element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_pop(list); + ctest_test("popped no element", igloo_RO_IS_NULL(ret)); + igloo_ro_unref(ret); /* just in case we got an element */ + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +static void test_list_push_unshift_shift(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + test__create_push_unshift(&list, &a, &b); + + ret = igloo_list_shift(list); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +static void test_list_push_unshift_shift_shift(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + test__create_push_unshift(&list, &a, &b); + + ret = igloo_list_shift(list); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_shift(list); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_shift(list); + ctest_test("shifted no element", igloo_RO_IS_NULL(ret)); + igloo_ro_unref(ret); /* just in case we got an element */ + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + + +static void test_list_push_unshift_pop_shift(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + test__create_push_unshift(&list, &a, &b); + + ret = igloo_list_pop(list); + ctest_test("popped element", !igloo_RO_IS_NULL(ret)); + ctest_test("popped element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced popped element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_shift(list); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} +static void test_list_push_unshift_shift_pop(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + test__create_push_unshift(&list, &a, &b); + + ret = igloo_list_shift(list); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_pop(list); + ctest_test("popped element", !igloo_RO_IS_NULL(ret)); + ctest_test("popped element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced popped element", igloo_ro_unref(ret) == 0); + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +static void test_list_merge(void) +{ + igloo_list_t *list_a; + igloo_list_t *list_b; + igloo_ro_base_t *a; + igloo_ro_base_t *b; + igloo_ro_t ret; + + list_a = igloo_ro_new(igloo_list_t); + ctest_test("list a created", !igloo_RO_IS_NULL(list_a)); + + list_b = igloo_ro_new(igloo_list_t); + ctest_test("list a created", !igloo_RO_IS_NULL(list_b)); + + a = igloo_ro_new(igloo_ro_base_t); + ctest_test("test object a created", !igloo_RO_IS_NULL(a)); + + b = igloo_ro_new(igloo_ro_base_t); + ctest_test("test object b created", !igloo_RO_IS_NULL(b)); + + ctest_test("test object a pushed to list a", igloo_list_push(list_a, a) == 0); + ctest_test("test object b pushed to list b", igloo_list_push(list_b, b) == 0); + + ctest_test("merged list b into list a", igloo_list_merge(list_a, list_b) == 0); + + ret = igloo_list_shift(list_a); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_shift(list_a); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_shift(list_a); + ctest_test("shifted no element", igloo_RO_IS_NULL(ret)); + igloo_ro_unref(ret); /* just in case we got an element */ + + ret = igloo_list_shift(list_b); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches b", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == b); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ret = igloo_list_shift(list_b); + ctest_test("shifted no element", igloo_RO_IS_NULL(ret)); + igloo_ro_unref(ret); /* just in case we got an element */ + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list a", igloo_ro_unref(list_a) == 0); + ctest_test("un-referenced list b", igloo_ro_unref(list_b) == 0); +} + +static void test_list_set_type(void) +{ + igloo_list_t *list; + igloo_ro_base_t *a; + igloo_list_t *b; + igloo_ro_t ret; + + list = igloo_ro_new(igloo_list_t); + ctest_test("list created", !igloo_RO_IS_NULL(list)); + + a = igloo_ro_new(igloo_ro_base_t); + ctest_test("test object a created", !igloo_RO_IS_NULL(a)); + + b = igloo_ro_new(igloo_list_t); + ctest_test("test object b created", !igloo_RO_IS_NULL(b)); + + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) == 0); + ctest_test("pinned list to type igloo_list_t", igloo_list_set_type(list, igloo_list_t) == 0); + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) == 0); + + ctest_test("test object a pushed to list", igloo_list_push(list, a) == 0); + + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) == 0); + ctest_test("can not pin list to type igloo_list_t", igloo_list_set_type(list, igloo_list_t) != 0); + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) == 0); + + ctest_test("test object b failed to pushed to list", igloo_list_push(list, b) != 0); + + ctest_test("list cleared", igloo_list_clear(list) == 0); + + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) == 0); + ctest_test("can not pin list to type igloo_list_t", igloo_list_set_type(list, igloo_list_t) == 0); + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) == 0); + + ctest_test("un-referenced list a", igloo_ro_unref(list) == 0); + list = igloo_ro_new(igloo_list_t); + ctest_test("list created", !igloo_RO_IS_NULL(list)); + + ctest_test("test object a pushed to list", igloo_list_push(list, a) == 0); + ctest_test("test object b pushed to list", igloo_list_push(list, b) == 0); + + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) != 0); + ctest_test("pinned list to type igloo_list_t", igloo_list_set_type(list, igloo_list_t) != 0); + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) != 0); + + ret = igloo_list_shift(list); + ctest_test("shifted element", !igloo_RO_IS_NULL(ret)); + ctest_test("shifted element matches a", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == a); + ctest_test("un-referenced shifted element", igloo_ro_unref(ret) == 0); + + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) != 0); + ctest_test("can not pin list to type igloo_list_t", igloo_list_set_type(list, igloo_list_t) == 0); + ctest_test("pinned list to type igloo_ro_base_t", igloo_list_set_type(list, igloo_ro_base_t) != 0); + + ctest_test("un-referenced a", igloo_ro_unref(a) == 0); + ctest_test("un-referenced b", igloo_ro_unref(b) == 0); + ctest_test("un-referenced list a", igloo_ro_unref(list) == 0); +} + +static void test_list_iterator(void) +{ + igloo_list_t *list; + igloo_ro_base_t * elements[3] = {NULL, NULL, NULL}; + igloo_list_iterator_storage_t storage; + igloo_list_iterator_t *iterator; + size_t i; + + test__create_push_unshift(&list, &(elements[1]), &(elements[0])); + + iterator = igloo_list_iterator_start(list, &storage, sizeof(storage)); + ctest_test("iterator created", iterator != NULL); + + for (i = 0; i < (sizeof(elements)/sizeof(*elements)); i++) { + igloo_ro_t ret = igloo_list_iterator_next(iterator); + ctest_test("shifted element matches corresponding element in list", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == elements[i]); + if (!igloo_RO_IS_NULL(ret)) { + ctest_test("un-referenced element returned by iterator", igloo_ro_unref(ret) == 0); + } + } + + ctest_test("rewinded iterator", igloo_list_iterator_rewind(iterator) == 0); + + for (i = 0; i < (sizeof(elements)/sizeof(*elements)); i++) { + igloo_ro_t ret = igloo_list_iterator_next(iterator); + ctest_test("shifted element matches corresponding element in list", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == elements[i]); + if (!igloo_RO_IS_NULL(ret)) { + ctest_test("un-referenced element returned by iterator", igloo_ro_unref(ret) == 0); + } + } + + ctest_test("rewinded iterator", igloo_list_iterator_rewind(iterator) == 0); + + for (i = 0; i < 1; i++) { + igloo_ro_t ret = igloo_list_iterator_next(iterator); + ctest_test("shifted element matches corresponding element in list", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == elements[i]); + if (!igloo_RO_IS_NULL(ret)) { + ctest_test("un-referenced element returned by iterator", igloo_ro_unref(ret) == 0); + } + } + + ctest_test("rewinded iterator", igloo_list_iterator_rewind(iterator) == 0); + + for (i = 0; i < (sizeof(elements)/sizeof(*elements)); i++) { + igloo_ro_t ret = igloo_list_iterator_next(iterator); + ctest_test("shifted element matches corresponding element in list", igloo_RO_TO_TYPE(ret, igloo_ro_base_t) == elements[i]); + if (!igloo_RO_IS_NULL(ret)) { + ctest_test("un-referenced element returned by iterator", igloo_ro_unref(ret) == 0); + } + } + + igloo_list_iterator_end(iterator); + + ctest_test("un-referenced a", igloo_ro_unref(elements[0]) == 0); + ctest_test("un-referenced b", igloo_ro_unref(elements[1]) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +static void test_list_foreach(void) +{ + igloo_list_t *list; + igloo_ro_base_t * elements[3] = {NULL, NULL, NULL}; + size_t i = 0; + + test__create_push_unshift(&list, &(elements[1]), &(elements[0])); + + igloo_list_foreach(list, igloo_ro_base_t, ret, { + ctest_test("foreach returned element matches corresponding element in list", ret == elements[i]); + i++; + }); + + ctest_test("un-referenced a", igloo_ro_unref(elements[0]) == 0); + ctest_test("un-referenced b", igloo_ro_unref(elements[1]) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + +int main (void) +{ + ctest_init(); + + test_create_ref_unref(); + + test_list_push_unshift(); + test_list_push_unshift_pop(); + test_list_push_unshift_pop_pop(); + test_list_push_unshift_shift(); + test_list_push_unshift_shift_shift(); + test_list_push_unshift_pop_shift(); + test_list_push_unshift_shift_pop(); + + test_list_merge(); + + test_list_set_type(); + + test_list_iterator(); + + test_list_foreach(); + + ctest_fin(); + + return 0; +} From 7b73af07a93080343fba6505a383a7ecafd738cb Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 13:31:20 +0000 Subject: [PATCH 09/10] Fix: Corrected possition of comment --- include/igloo/list.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/igloo/list.h b/include/igloo/list.h index 5bf1264..df4b632 100644 --- a/include/igloo/list.h +++ b/include/igloo/list.h @@ -35,16 +35,16 @@ typedef struct igloo_list_iterator_tag igloo_list_iterator_storage_t; igloo_RO_FORWARD_TYPE(igloo_list_t); /* ---[ PRIVATE ]--- */ +/* + * Those types are defined here as they must be known to the compiler. + * Nobody should ever try to access them directly. + */ struct igloo_list_iterator_tag { igloo_list_t *list; size_t idx; }; /* ---[ END PRIVATE ]--- */ -/* - * Those types are defined here as they must be known to the compiler. - * Nobody should ever try to access them directly. - */ int igloo_list_clear(igloo_list_t *list); void igloo_list_preallocate(igloo_list_t *list, size_t request); int igloo_list_set_type__real(igloo_list_t *list, const igloo_ro_type_t *type); From 97f1652f7d6c29ae3be186f7e1500ddd81fd0467 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 8 Nov 2018 13:52:30 +0000 Subject: [PATCH 10/10] Feature: Added some comments on how the igloo_list_t API is to be used --- include/igloo/list.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/igloo/list.h b/include/igloo/list.h index df4b632..7a1e2ab 100644 --- a/include/igloo/list.h +++ b/include/igloo/list.h @@ -45,22 +45,54 @@ struct igloo_list_iterator_tag { }; /* ---[ END PRIVATE ]--- */ +/* To create lists use: igloo_ro_new(igloo_list_t) + */ + +/* Clear a list (remove all elements). */ int igloo_list_clear(igloo_list_t *list); +/* Preallocate space for later mass-adding of elements. */ void igloo_list_preallocate(igloo_list_t *list, size_t request); +/* Limit elements to those of the given type. */ int igloo_list_set_type__real(igloo_list_t *list, const igloo_ro_type_t *type); #define igloo_list_set_type(list,type) igloo_list_set_type__real((list),(igloo_ro__type__ ## type)) +/* Add an element at the end of the list. */ int igloo_list_push(igloo_list_t *list, igloo_ro_t element); +/* Add an element at the begin of a list. */ int igloo_list_unshift(igloo_list_t *list, igloo_ro_t element); +/* Get and remove the first element from the list. */ igloo_ro_t igloo_list_shift(igloo_list_t *list); +/* Get and remove the last element from the list. */ igloo_ro_t igloo_list_pop(igloo_list_t *list); +/* Merge the content of the list elements into the list list. The list elements is not changed. */ int igloo_list_merge(igloo_list_t *list, igloo_list_t *elements); +/* Creates a new iterator that can be used to walk the list. + * The memory pointed to by storage of size storage_length is used to store the iterator's internal + * values. It must be allocated (e.g. on stack) untill igloo_list_iterator_end() is called. + * igloo_list_iterator_storage_t is provided to be used as storage object. + * Example: + * igloo_list_iterator_storage_t storage; + * igloo_list_iterator_t *iterator = igloo_list_iterator_start(list, &storage, sizeof(storage)); + */ igloo_list_iterator_t * igloo_list_iterator_start(igloo_list_t *list, void *storage, size_t storage_length); +/* Get next element from iterator. */ igloo_ro_t igloo_list_iterator_next(igloo_list_iterator_t *iterator); +/* Destory iterator. */ void igloo_list_iterator_end(igloo_list_iterator_t *iterator); +/* Rewind iterator. The next call to igloo_list_iterator_next() will return the first element again. */ int igloo_list_iterator_rewind(igloo_list_iterator_t *iterator); +/* Go thru all elements in the list. + * Parameters: + * list: the list to use. + * type: the type of elements in the list + * var: the variable to store the current element in. + * code: the code block to be used in the loop. + * + * Note: This can only be used on lists that contain only one type of objects. + * See also: igloo_list_set_type() + */ #define igloo_list_foreach(list,type,var,code) \ do { \ igloo_list_iterator_storage_t __igloo_list_iterator_storage; \