From 30f0def02adb98ac1003e30a53417cc6ce10d596 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 9 Apr 2019 14:26:33 -0400 Subject: [PATCH 01/25] Initial commit list generic linked list --- README.md | 2 +- src/util/list.c | 124 ++++++++++++++++++++++++++++++++++++++ src/util/list.h | 59 ++++++++++++++++++ tests/util/CMakeLists.txt | 8 ++- tests/util/test_list.cpp | 74 +++++++++++++++++++++++ 5 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/util/list.c create mode 100644 src/util/list.h create mode 100644 tests/util/test_list.cpp diff --git a/README.md b/README.md index 5e5949e..56dc1fa 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ EPANET {#epanet-readme} ## For EPANET-related questions and discussion -For community discussion, FAQ, and roadmapping of the project, go to the [Community Forum](http://community.wateranalytics.org/category/epanet). +For community discussion, FAQ, and roadmapping of the project, go to the [Community Forum](http://community.wateranalytics.org/category/epanet). ## What is on this Repository? The EPANET Library is a pressurized pipe network hydraulic and water quality analysis toolkit written in C. If you are interested in using/extending EPANET for academic, personal, or commercial use, then you've come to the right place. diff --git a/src/util/list.c b/src/util/list.c new file mode 100644 index 0000000..ad36c65 --- /dev/null +++ b/src/util/list.c @@ -0,0 +1,124 @@ +// +// Author: David Muto +// https://gist.github.com/pseudomuto/6334796#file-list-c +// +// Modified by: +// Michael E. Tryby +// US EPA ORD +// +// Accessed on: April 9, 2019 +// + + +#include +#include +#include + +#include "list.h" + + +list_t *create_list(int elementSize, freeFunction freeFn) +{ + list_t *list; + list = (list_t *)calloc(1, sizeof(list_t)); + + assert(elementSize > 0); + list->logicalLength = 0; + list->elementSize = elementSize; + list->head = list->tail = NULL; + list->freeFn = freeFn; + return list; +} + +void delete_list(list_t *list) +{ + listNode *current; + while(list->head != NULL) { + current = list->head; + list->head = current->next; + + if (list->freeFn) { + list->freeFn(current->data); + } + + free(current->data); + free(current); + } + + free(list); +} + +void prepend_list(list_t *list, void *element) +{ + listNode *node = malloc(sizeof(listNode)); + node->data = malloc(list->elementSize); + memcpy(node->data, element, list->elementSize); + + node->next = list->head; + list->head = node; + + // first node? + if(!list->tail) { + list->tail = list->head; + } + + list->logicalLength++; +} + +void append_list(list_t *list, void *element) +{ + listNode *node = malloc(sizeof(listNode)); + node->data = malloc(list->elementSize); + node->next = NULL; + + memcpy(node->data, element, list->elementSize); + + if(list->logicalLength == 0) { + list->head = list->tail = node; + } else { + list->tail->next = node; + list->tail = node; + } + + list->logicalLength++; +} + +void for_each_list(list_t *list, listIterator iterator) +{ + assert(iterator != NULL); + + listNode *node = list->head; + bool result = true; + while(node != NULL && result) { + result = iterator(node->data); + node = node->next; + } +} + +void head_list(list_t *list, void *element, bool removeFromList) +{ + assert(list->head != NULL); + + listNode *node = list->head; + memcpy(element, node->data, list->elementSize); + + if(removeFromList) { + list->head = node->next; + list->logicalLength--; + + free(node->data); + free(node); + } +} + +void tail_list(list_t *list, void *element) +{ + assert(list->tail != NULL); + listNode *node = list->tail; + memcpy(element, node->data, list->elementSize); +} + +int size_list(list_t *list) +{ + return list->logicalLength; +} diff --git a/src/util/list.h b/src/util/list.h new file mode 100644 index 0000000..f19b7d4 --- /dev/null +++ b/src/util/list.h @@ -0,0 +1,59 @@ +// +// Author: David Muto +// https://gist.github.com/pseudomuto/6334796#file-list-h +// +// Modified by: +// Michael E. Tryby +// US EPA ORD +// +// Accessed on: April 9, 2019 +// + + +#ifndef LIST_H +#define LIST_H + + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +// a common function used to free malloc'd objects +typedef void(*freeFunction)(void *); +typedef bool (*listIterator)(void *); + + +typedef struct _listNode { + void *data; + struct _listNode *next; +} listNode; + + +typedef struct { + int logicalLength; + int elementSize; + listNode *head; + listNode *tail; + freeFunction freeFn; +} list_t; + + +list_t *create_list(int elementSize, freeFunction freeFn); +void delete_list(list_t *list); + +void prepend_list(list_t *list, void *element); +void append_list(list_t *list, void *element); +int size_list(list_t *list); + +void for_each_list(list_t *list, listIterator iterator); +void head_list(list_t *list, void *element, bool removeFromList); +void tail_list(list_t *list, void *element); + + +#if defined(__cplusplus) +} +#endif + +#endif /* LIST_H */ diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index 0bd4a43..59463e9 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -add_executable(test_errormanager ./test_errormanager.cpp +add_executable(test_errormanager ./test_errormanager.cpp ../../src/util/errormanager.c) target_include_directories(test_errormanager PUBLIC ../../src/) target_link_libraries(test_errormanager ${Boost_LIBRARIES}) @@ -18,3 +18,9 @@ add_executable(test_filemanager ./test_filemanager.cpp ../../src/util/cstr_helper.c) target_include_directories(test_filemanager PUBLIC ../../src/) target_link_libraries(test_filemanager ${Boost_LIBRARIES}) + + +add_executable(test_list ./test_list.cpp + ../../src/util/list.c) +target_include_directories(test_list PUBLIC ../../src/) +target_link_libraries(test_list ${Boost_LIBRARIES}) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp new file mode 100644 index 0000000..346be50 --- /dev/null +++ b/tests/util/test_list.cpp @@ -0,0 +1,74 @@ +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/test_list.cpp + Description: Tests for util/list.c + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/09/2019 + ****************************************************************************** +*/ + +#define BOOST_TEST_MODULE list + +#include + +#include "util/list.h" + + +bool iterate_int(void *data) +{ + printf("Found value: %d\n", *(int *)data); + return true; +} + + +BOOST_AUTO_TEST_SUITE(test_list) + + +BOOST_AUTO_TEST_CASE(test_create_delete) { + + list_t *list; + list = create_list(sizeof(int), NULL); + + delete_list(list); +} + + +struct Fixture{ + Fixture() { + list = NULL; + + list = create_list(sizeof(int), NULL); + } + ~Fixture() { + delete_list(list); + } + list_t *list; +}; + + +BOOST_FIXTURE_TEST_CASE(test_list_append, Fixture){ + +int i, numbers = 10; + + for(i = 1; i <= numbers; i++) { + append_list(list, &i); + } + BOOST_CHECK(size_list(list) == 10); +} + +BOOST_FIXTURE_TEST_CASE(test_list_foreach, Fixture) { + + int i, numbers = 10; + + for (i = 1; i <= numbers; i++) { + append_list(list, &i); + } + + for_each_list(list, iterate_int); +} + +BOOST_AUTO_TEST_SUITE_END() From 6f236f00ef8e4fbfb2ef14ff6ff26a3565314530 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 9 Apr 2019 15:16:54 -0400 Subject: [PATCH 02/25] Update test_list.cpp Tests are passing --- tests/util/test_list.cpp | 63 +++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 346be50..4cbc633 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -24,6 +24,17 @@ bool iterate_int(void *data) return true; } +bool iterate_string(void *data) +{ + char *string = *(char **)data; + printf("Found string value: %s\n", string); + return true; +} + +void free_string(void *data) +{ + free(*(char **)data); +} BOOST_AUTO_TEST_SUITE(test_list) @@ -37,38 +48,44 @@ BOOST_AUTO_TEST_CASE(test_create_delete) { } -struct Fixture{ - Fixture() { - list = NULL; +BOOST_AUTO_TEST_CASE(test_int_list){ - list = create_list(sizeof(int), NULL); - } - ~Fixture() { - delete_list(list); - } - list_t *list; -}; + int i, numbers = 10; + list_t *list = NULL; - -BOOST_FIXTURE_TEST_CASE(test_list_append, Fixture){ - -int i, numbers = 10; + list = create_list(sizeof(int), NULL); for(i = 1; i <= numbers; i++) { append_list(list, &i); } BOOST_CHECK(size_list(list) == 10); -} - -BOOST_FIXTURE_TEST_CASE(test_list_foreach, Fixture) { - - int i, numbers = 10; - - for (i = 1; i <= numbers; i++) { - append_list(list, &i); - } for_each_list(list, iterate_int); + + delete_list(list); } + +BOOST_AUTO_TEST_CASE(test_string_list) { + int i, numNames = 5; + const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; + + list_t *list = NULL; + + list = create_list(sizeof(char *), free_string); + + char *name; + for (i = 0; i < numNames; i++) { + name = _strdup(names[i]); + append_list(list, &name); + } + + BOOST_CHECK(size_list(list) == 5); + + for_each_list(list, iterate_string); + + delete_list(list); +} + + BOOST_AUTO_TEST_SUITE_END() From dcfa51f9382b0291633be7f8df1fc87334b67300 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 9 Apr 2019 16:09:37 -0400 Subject: [PATCH 03/25] Update list.h Adding documentation --- src/util/list.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/util/list.h b/src/util/list.h index f19b7d4..6bc47e7 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -40,15 +40,49 @@ typedef struct { } list_t; +/** +@brief Initializes a linked list to store elements of elementSize and to call +freeFunction for each element when destroying a list. +*/ list_t *create_list(int elementSize, freeFunction freeFn); + +/** +@brief Frees dynamically allocated nodes and optionally calls freeFunction +with each node’s data pointer. +*/ void delete_list(list_t *list); +/** +@brief Adds a node to the head of the list. +*/ void prepend_list(list_t *list, void *element); + +/** +@brief Adds a node to the tail of the list. +*/ void append_list(list_t *list, void *element); + +/** +@brief Returns the number of items in the list. +*/ int size_list(list_t *list); + +/** +@brief Calles the supplied iterator function with the data element of each +node (iterates over the list). +*/ void for_each_list(list_t *list, listIterator iterator); + +/** +@brief Returns the head of the list (optionally removing it at the same time). +*/ void head_list(list_t *list, void *element, bool removeFromList); + + +/** +@brief Returns the tail of the list. +*/ void tail_list(list_t *list, void *element); From 1fdee6ac7e2a8df19d36430c3f71c22268fcd6bd Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 9 Apr 2019 16:16:54 -0400 Subject: [PATCH 04/25] Fix typo --- src/util/list.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/util/list.h b/src/util/list.h index 6bc47e7..dcd2032 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -67,9 +67,8 @@ void append_list(list_t *list, void *element); */ int size_list(list_t *list); - /** -@brief Calles the supplied iterator function with the data element of each +@brief Calls the supplied iterator function with the data element of each node (iterates over the list). */ void for_each_list(list_t *list, listIterator iterator); @@ -79,7 +78,6 @@ void for_each_list(list_t *list, listIterator iterator); */ void head_list(list_t *list, void *element, bool removeFromList); - /** @brief Returns the tail of the list. */ From 07995beda1ad8a12d99e257dfb6f07be948403b0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 9 Apr 2019 18:09:41 -0400 Subject: [PATCH 05/25] Fixing bug in head_list --- src/util/list.c | 12 +++++++++--- src/util/list.h | 2 +- tests/util/test_list.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index ad36c65..e1b8253 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -95,17 +95,23 @@ void for_each_list(list_t *list, listIterator iterator) } } -void head_list(list_t *list, void *element, bool removeFromList) +void head_list(list_t *list, void **element, bool removeFromList) { assert(list->head != NULL); + + listNode *node = list->head; - listNode *node = list->head; - memcpy(element, node->data, list->elementSize); + *element = (void *)malloc(list->elementSize); + memcpy(*element, node->data, list->elementSize); if(removeFromList) { list->head = node->next; list->logicalLength--; + if (list->freeFn) { + list->freeFn(node->data); + } + free(node->data); free(node); } diff --git a/src/util/list.h b/src/util/list.h index dcd2032..bb33ea2 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -76,7 +76,7 @@ void for_each_list(list_t *list, listIterator iterator); /** @brief Returns the head of the list (optionally removing it at the same time). */ -void head_list(list_t *list, void *element, bool removeFromList); +void head_list(list_t *list, void **element, bool removeFromList); /** @brief Returns the tail of the list. diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 4cbc633..b319d9c 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -88,4 +88,31 @@ BOOST_AUTO_TEST_CASE(test_string_list) { } +BOOST_AUTO_TEST_CASE(test_head_list) { + int i, numNames = 5; + const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; + + list_t *list = NULL; + + list = create_list(sizeof(char *), free_string); + + char *name; + for (i = 0; i < numNames; i++) { + name = _strdup(names[i]); + append_list(list, &name); + } + BOOST_CHECK(size_list(list) == 5); + + + char *temp = NULL; + head_list(list, &(void *)temp, true); + name = *(char **)temp; + + BOOST_CHECK(size_list(list) == 4); + + free(temp); + delete_list(list); +} + + BOOST_AUTO_TEST_SUITE_END() From 39038bc17e3b0e75083d61738d647dc512750586 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 9 Apr 2019 18:17:15 -0400 Subject: [PATCH 06/25] Fixing indentation --- src/util/list.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index e1b8253..3aaa661 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -33,13 +33,13 @@ list_t *create_list(int elementSize, freeFunction freeFn) void delete_list(list_t *list) { listNode *current; + while(list->head != NULL) { current = list->head; list->head = current->next; - if (list->freeFn) { - list->freeFn(current->data); - } + if (list->freeFn) + list->freeFn(current->data); free(current->data); free(current); @@ -98,19 +98,17 @@ void for_each_list(list_t *list, listIterator iterator) void head_list(list_t *list, void **element, bool removeFromList) { assert(list->head != NULL); - - listNode *node = list->head; - *element = (void *)malloc(list->elementSize); + listNode *node = list->head; + *element = (void *)malloc(list->elementSize); memcpy(*element, node->data, list->elementSize); if(removeFromList) { list->head = node->next; list->logicalLength--; - if (list->freeFn) { - list->freeFn(node->data); - } + if (list->freeFn) + list->freeFn(node->data); free(node->data); free(node); From ea02e1736e28cf851f5900a2f6a3f0640772a242 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 10:44:34 -0400 Subject: [PATCH 07/25] Fixed memory leak Fixed memory leak in test_head_list --- src/util/list.c | 23 +++++--- src/util/list.h | 4 +- tests/util/test_list.cpp | 112 ++++++++++++++++++++++----------------- 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 3aaa661..47bded9 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -10,7 +10,14 @@ // +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC #include +#include +#else +#include +#endif + #include #include @@ -95,31 +102,33 @@ void for_each_list(list_t *list, listIterator iterator) } } -void head_list(list_t *list, void **element, bool removeFromList) +void *head_list(list_t *list, bool removeFromList) { assert(list->head != NULL); listNode *node = list->head; - *element = (void *)malloc(list->elementSize); - memcpy(*element, node->data, list->elementSize); + void *element = (void *)malloc(list->elementSize); + memcpy(element, node->data, list->elementSize); if(removeFromList) { list->head = node->next; list->logicalLength--; - if (list->freeFn) - list->freeFn(node->data); - free(node->data); free(node); } + return element; } -void tail_list(list_t *list, void *element) +void *tail_list(list_t *list) { assert(list->tail != NULL); + listNode *node = list->tail; + void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); + + return element; } int size_list(list_t *list) diff --git a/src/util/list.h b/src/util/list.h index bb33ea2..311234f 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -76,12 +76,12 @@ void for_each_list(list_t *list, listIterator iterator); /** @brief Returns the head of the list (optionally removing it at the same time). */ -void head_list(list_t *list, void **element, bool removeFromList); +void *head_list(list_t *list, bool removeFromList); /** @brief Returns the tail of the list. */ -void tail_list(list_t *list, void *element); +void *tail_list(list_t *list); #if defined(__cplusplus) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index b319d9c..f41a2e8 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -18,22 +18,31 @@ #include "util/list.h" +boost::test_tools::predicate_result check_string(std::string test, std::string ref) +{ + if (ref.compare(test) == 0) + return true; + else + return false; +} + + bool iterate_int(void *data) { - printf("Found value: %d\n", *(int *)data); - return true; + printf("Found value: %d\n", *(int *)data); + return true; } bool iterate_string(void *data) { - char *string = *(char **)data; - printf("Found string value: %s\n", string); - return true; + char *string = *(char **)data; + printf("Found string value: %s\n", string); + return true; } void free_string(void *data) { - free(*(char **)data); + free(*(char **)data); } BOOST_AUTO_TEST_SUITE(test_list) @@ -41,7 +50,7 @@ BOOST_AUTO_TEST_SUITE(test_list) BOOST_AUTO_TEST_CASE(test_create_delete) { - list_t *list; + list_t *list; list = create_list(sizeof(int), NULL); delete_list(list); @@ -50,68 +59,71 @@ BOOST_AUTO_TEST_CASE(test_create_delete) { BOOST_AUTO_TEST_CASE(test_int_list){ - int i, numbers = 10; - list_t *list = NULL; + int i, numbers = 10; + list_t *list = NULL; - list = create_list(sizeof(int), NULL); + list = create_list(sizeof(int), NULL); for(i = 1; i <= numbers; i++) { append_list(list, &i); } - BOOST_CHECK(size_list(list) == 10); + BOOST_CHECK(size_list(list) == 10); - for_each_list(list, iterate_int); + for_each_list(list, iterate_int); - delete_list(list); + delete_list(list); +} + +struct FixtureStrings{ + FixtureStrings() { + name = NULL; + list = NULL; + + int numNames = 5; + const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; + + list = create_list(sizeof(char *), free_string); + + for (int i = 0; i < numNames; i++) { + name = _strdup(names[i]); + append_list(list, &name); + } + } + ~FixtureStrings() { + delete_list(list); + } + char *name; + list_t *list; +}; + +BOOST_FIXTURE_TEST_CASE(test_string_list, FixtureStrings) { + + BOOST_CHECK(size_list(list) == 5); + + for_each_list(list, iterate_string); } -BOOST_AUTO_TEST_CASE(test_string_list) { - int i, numNames = 5; - const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; +BOOST_FIXTURE_TEST_CASE(test_head_list, FixtureStrings) { - list_t *list = NULL; + void *temp = head_list(list, true); - list = create_list(sizeof(char *), free_string); + BOOST_CHECK(check_string(*(char **)temp, "David")); + BOOST_CHECK(size_list(list) == 4); - char *name; - for (i = 0; i < numNames; i++) { - name = _strdup(names[i]); - append_list(list, &name); - } - - BOOST_CHECK(size_list(list) == 5); - - for_each_list(list, iterate_string); - - delete_list(list); + free_string(temp); + free(temp); } -BOOST_AUTO_TEST_CASE(test_head_list) { - int i, numNames = 5; - const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; +BOOST_FIXTURE_TEST_CASE(test_tail_list, FixtureStrings) { - list_t *list = NULL; + void *temp = tail_list(list); - list = create_list(sizeof(char *), free_string); + BOOST_CHECK(check_string(*(char **)temp, "Jimi")); + BOOST_CHECK(size_list(list) == 5); - char *name; - for (i = 0; i < numNames; i++) { - name = _strdup(names[i]); - append_list(list, &name); - } - BOOST_CHECK(size_list(list) == 5); - - - char *temp = NULL; - head_list(list, &(void *)temp, true); - name = *(char **)temp; - - BOOST_CHECK(size_list(list) == 4); - - free(temp); - delete_list(list); + free(temp); } From f9dd9bc766fb9f3e806ce72db46ed4169887cab3 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 10:57:55 -0400 Subject: [PATCH 08/25] Clean up and inline comments --- src/util/list.c | 9 ++++++++- src/util/list.h | 4 ++-- tests/util/test_list.cpp | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 47bded9..286172a 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -24,7 +24,7 @@ #include "list.h" -list_t *create_list(int elementSize, freeFunction freeFn) +list_t *create_list(size_t elementSize, freeFunction freeFn) { list_t *list; list = (list_t *)calloc(1, sizeof(list_t)); @@ -103,20 +103,27 @@ void for_each_list(list_t *list, listIterator iterator) } void *head_list(list_t *list, bool removeFromList) +// +// Warning: Caller is responsible for freeing the node->data returned. +// { assert(list->head != NULL); listNode *node = list->head; void *element = (void *)malloc(list->elementSize); + // Copying pointer to node->data memcpy(element, node->data, list->elementSize); if(removeFromList) { + // Disconnecting head node list->head = node->next; list->logicalLength--; + // Freeing pointer to node->data and node free(node->data); free(node); } + // Now element points to data formerly pointed to by node return element; } diff --git a/src/util/list.h b/src/util/list.h index 311234f..0a84753 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -33,7 +33,7 @@ typedef struct _listNode { typedef struct { int logicalLength; - int elementSize; + size_t elementSize; listNode *head; listNode *tail; freeFunction freeFn; @@ -44,7 +44,7 @@ typedef struct { @brief Initializes a linked list to store elements of elementSize and to call freeFunction for each element when destroying a list. */ -list_t *create_list(int elementSize, freeFunction freeFn); +list_t *create_list(size_t elementSize, freeFunction freeFn); /** @brief Frees dynamically allocated nodes and optionally calls freeFunction diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index f41a2e8..97a3ea0 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -111,6 +111,7 @@ BOOST_FIXTURE_TEST_CASE(test_head_list, FixtureStrings) { BOOST_CHECK(check_string(*(char **)temp, "David")); BOOST_CHECK(size_list(list) == 4); + // To free a node, free both the data and reference to data free_string(temp); free(temp); } From 6537b4fca0e341792de37c5c634efc5425292c15 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 11:03:23 -0400 Subject: [PATCH 09/25] Updating file headers --- src/util/list.c | 25 ++++++++++++++----------- src/util/list.h | 25 ++++++++++++++----------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 286172a..8ebb23e 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -1,14 +1,17 @@ -// -// Author: David Muto -// https://gist.github.com/pseudomuto/6334796#file-list-c -// -// Modified by: -// Michael E. Tryby -// US EPA ORD -// -// Accessed on: April 9, 2019 -// - +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/list.h + Description: Generic list + https://gist.github.com/pseudomuto/6334796#file-list-c + Accessed: April 9, 2019 + Authors: David Muto, Modified by Michael E. Tryby + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/09/2019 + ****************************************************************************** +*/ #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC diff --git a/src/util/list.h b/src/util/list.h index 0a84753..264975d 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -1,14 +1,17 @@ -// -// Author: David Muto -// https://gist.github.com/pseudomuto/6334796#file-list-h -// -// Modified by: -// Michael E. Tryby -// US EPA ORD -// -// Accessed on: April 9, 2019 -// - +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: util/list.h + Description: Generic list + https://gist.github.com/pseudomuto/6334796#file-list-h + Accessed: April 9, 2019 + Authors: David Muto, Modified by Michael E. Tryby + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/09/2019 + ****************************************************************************** +*/ #ifndef LIST_H #define LIST_H From 3d62254eb8827f9ef7f2316f2ccec2ac523c1cd0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 11:11:13 -0400 Subject: [PATCH 10/25] Update list.c Updating in line comments. --- src/util/list.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 8ebb23e..7fe5f36 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -113,8 +113,8 @@ void *head_list(list_t *list, bool removeFromList) assert(list->head != NULL); listNode *node = list->head; + // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); - // Copying pointer to node->data memcpy(element, node->data, list->elementSize); if(removeFromList) { @@ -126,18 +126,25 @@ void *head_list(list_t *list, bool removeFromList) free(node->data); free(node); } - // Now element points to data formerly pointed to by node + // Now element points to data formerly pointed to by node. Caller + // is responsible for freeing both pointer to data and data. return element; } void *tail_list(list_t *list) +// +// Warning: Caller is responsible for freeing the node->data returned. +// { assert(list->tail != NULL); listNode *node = list->tail; + // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); + // Pointer to element data gets returned. Caller is responsible + // for freeing pointer to data. return element; } From dba0d1cf52b47ee3499ba972959d9b3a2b6c6a5d Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 11:15:35 -0400 Subject: [PATCH 11/25] Update test_list.cpp --- tests/util/test_list.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 97a3ea0..683c391 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -76,14 +76,14 @@ BOOST_AUTO_TEST_CASE(test_int_list){ struct FixtureStrings{ FixtureStrings() { - name = NULL; list = NULL; int numNames = 5; const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; list = create_list(sizeof(char *), free_string); - + + char *name; for (int i = 0; i < numNames; i++) { name = _strdup(names[i]); append_list(list, &name); @@ -92,7 +92,6 @@ struct FixtureStrings{ ~FixtureStrings() { delete_list(list); } - char *name; list_t *list; }; From fbecf1b915cb050300ab2f06e95d1b8b51ba4f79 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 11:25:01 -0400 Subject: [PATCH 12/25] Fixing indent Spaces not tabs --- src/util/list.c | 35 ++++++++++++++++---------------- src/util/list.h | 16 +++++++-------- tests/util/test_errormanager.cpp | 10 ++++----- tests/util/test_list.cpp | 24 +++++++++++----------- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 7fe5f36..3f87234 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -4,8 +4,8 @@ Version: 2.2 Module: util/list.h Description: Generic list - https://gist.github.com/pseudomuto/6334796#file-list-c - Accessed: April 9, 2019 + https://gist.github.com/pseudomuto/6334796#file-list-c + Accessed: April 9, 2019 Authors: David Muto, Modified by Michael E. Tryby Copyright: see AUTHORS License: see LICENSE @@ -29,8 +29,8 @@ list_t *create_list(size_t elementSize, freeFunction freeFn) { - list_t *list; - list = (list_t *)calloc(1, sizeof(list_t)); + list_t *list; + list = (list_t *)calloc(1, sizeof(list_t)); assert(elementSize > 0); list->logicalLength = 0; @@ -54,8 +54,7 @@ void delete_list(list_t *list) free(current->data); free(current); } - - free(list); + free(list); } void prepend_list(list_t *list, void *element) @@ -106,45 +105,45 @@ void for_each_list(list_t *list, listIterator iterator) } void *head_list(list_t *list, bool removeFromList) -// -// Warning: Caller is responsible for freeing the node->data returned. +// +// Warning: Caller is responsible for freeing the node->data returned. // { assert(list->head != NULL); listNode *node = list->head; - // Allocating and copying pointer to node data + // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); if(removeFromList) { - // Disconnecting head node + // Disconnecting head node list->head = node->next; list->logicalLength--; - // Freeing pointer to node->data and node + // Freeing pointer to node->data and node free(node->data); free(node); } - // Now element points to data formerly pointed to by node. Caller - // is responsible for freeing both pointer to data and data. + // Now element points to data formerly pointed to by node. Caller + // is responsible for freeing both pointer to data and data. return element; } void *tail_list(list_t *list) -// -// Warning: Caller is responsible for freeing the node->data returned. +// +// Warning: Caller is responsible for freeing the node->data returned. // { assert(list->tail != NULL); listNode *node = list->tail; - // Allocating and copying pointer to node data + // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); - // Pointer to element data gets returned. Caller is responsible - // for freeing pointer to data. + // Pointer to element data gets returned. Caller is responsible + // for freeing pointer to data. return element; } diff --git a/src/util/list.h b/src/util/list.h index 264975d..5a1ded7 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -4,7 +4,7 @@ Version: 2.2 Module: util/list.h Description: Generic list - https://gist.github.com/pseudomuto/6334796#file-list-h + https://gist.github.com/pseudomuto/6334796#file-list-h Accessed: April 9, 2019 Authors: David Muto, Modified by Michael E. Tryby Copyright: see AUTHORS @@ -29,17 +29,17 @@ typedef bool (*listIterator)(void *); typedef struct _listNode { - void *data; - struct _listNode *next; + void *data; + struct _listNode *next; } listNode; typedef struct { - int logicalLength; - size_t elementSize; - listNode *head; - listNode *tail; - freeFunction freeFn; + int logicalLength; + size_t elementSize; + listNode *head; + listNode *tail; + freeFunction freeFn; } list_t; diff --git a/tests/util/test_errormanager.cpp b/tests/util/test_errormanager.cpp index 43f59e2..8e70774 100644 --- a/tests/util/test_errormanager.cpp +++ b/tests/util/test_errormanager.cpp @@ -45,16 +45,16 @@ BOOST_AUTO_TEST_CASE (test_create_destroy) struct Fixture{ Fixture() { - error_message = NULL; + error_message = NULL; error_handle = create_error_manager(&mock_lookup); } ~Fixture() { delete_error_manager(error_handle); free(error_message); - } - int error; - error_handle_t *error_handle; - char *error_message; + } + int error; + error_handle_t *error_handle; + char *error_message; }; diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 683c391..eb656f3 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -76,23 +76,23 @@ BOOST_AUTO_TEST_CASE(test_int_list){ struct FixtureStrings{ FixtureStrings() { - list = NULL; + list = NULL; int numNames = 5; const char *names[] = { "David", "Kevin", "Michael", "Craig", "Jimi" }; - list = create_list(sizeof(char *), free_string); - - char *name; - for (int i = 0; i < numNames; i++) { - name = _strdup(names[i]); - append_list(list, &name); - } + list = create_list(sizeof(char *), free_string); + + char *name; + for (int i = 0; i < numNames; i++) { + name = _strdup(names[i]); + append_list(list, &name); + } } ~FixtureStrings() { delete_list(list); - } - list_t *list; + } + list_t *list; }; BOOST_FIXTURE_TEST_CASE(test_string_list, FixtureStrings) { @@ -110,8 +110,8 @@ BOOST_FIXTURE_TEST_CASE(test_head_list, FixtureStrings) { BOOST_CHECK(check_string(*(char **)temp, "David")); BOOST_CHECK(size_list(list) == 4); - // To free a node, free both the data and reference to data - free_string(temp); + // To free a node, free both the data and reference to data + free_string(temp); free(temp); } From 7d3c16a4008f03ee805bafd31a8a9042b6dc9540 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 11:26:36 -0400 Subject: [PATCH 13/25] Update list.c Fixing indent --- src/util/list.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 3f87234..1f37bad 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -36,8 +36,8 @@ list_t *create_list(size_t elementSize, freeFunction freeFn) list->logicalLength = 0; list->elementSize = elementSize; list->head = list->tail = NULL; - list->freeFn = freeFn; - return list; + list->freeFn = freeFn; + return list; } void delete_list(list_t *list) From 06a90fd0632a4fdce296ea698897bbd8f4fa3074 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 11:34:37 -0400 Subject: [PATCH 14/25] Update test_list.cpp Updating file header to reflect proper attribution --- tests/util/test_list.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index eb656f3..f242106 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -2,9 +2,11 @@ ****************************************************************************** Project: OWA EPANET Version: 2.2 - Module: util/test_list.cpp - Description: Tests for util/list.c - Authors: see AUTHORS + Module: util/list.h + Description: Generic list + https://gist.github.com/pseudomuto/6334796#file-sample_app-c + Accessed: April 9, 2019 + Authors: David Muto, Modified by Michael E. Tryby Copyright: see AUTHORS License: see LICENSE Last Updated: 04/09/2019 From 669bdde12222c4a6ba6a2238a9a0e580570421e7 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 16:12:13 -0400 Subject: [PATCH 15/25] Expanding test Added test where data is a struct --- src/util/list.c | 27 ++++++++++++++---- src/util/list.h | 16 ++--------- tests/util/test_list.cpp | 60 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 1f37bad..96d4ad7 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -27,6 +27,21 @@ #include "list.h" +typedef struct list_node_s { + void *data; + list_node_t *next; +} list_node_t; + + +typedef struct list_s { + int logicalLength; + size_t elementSize; + list_node_t *head; + list_node_t *tail; + freeFunction freeFn; +} list_t; + + list_t *create_list(size_t elementSize, freeFunction freeFn) { list_t *list; @@ -42,7 +57,7 @@ list_t *create_list(size_t elementSize, freeFunction freeFn) void delete_list(list_t *list) { - listNode *current; + list_node_t *current; while(list->head != NULL) { current = list->head; @@ -59,7 +74,7 @@ void delete_list(list_t *list) void prepend_list(list_t *list, void *element) { - listNode *node = malloc(sizeof(listNode)); + list_node_t *node = malloc(sizeof(list_node_t)); node->data = malloc(list->elementSize); memcpy(node->data, element, list->elementSize); @@ -76,7 +91,7 @@ void prepend_list(list_t *list, void *element) void append_list(list_t *list, void *element) { - listNode *node = malloc(sizeof(listNode)); + list_node_t *node = malloc(sizeof(list_node_t)); node->data = malloc(list->elementSize); node->next = NULL; @@ -96,7 +111,7 @@ void for_each_list(list_t *list, listIterator iterator) { assert(iterator != NULL); - listNode *node = list->head; + list_node_t *node = list->head; bool result = true; while(node != NULL && result) { result = iterator(node->data); @@ -111,7 +126,7 @@ void *head_list(list_t *list, bool removeFromList) { assert(list->head != NULL); - listNode *node = list->head; + list_node_t *node = list->head; // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); @@ -137,7 +152,7 @@ void *tail_list(list_t *list) { assert(list->tail != NULL); - listNode *node = list->tail; + list_node_t *node = list->tail; // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); diff --git a/src/util/list.h b/src/util/list.h index 5a1ded7..7f4ed57 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -28,19 +28,9 @@ typedef void(*freeFunction)(void *); typedef bool (*listIterator)(void *); -typedef struct _listNode { - void *data; - struct _listNode *next; -} listNode; - - -typedef struct { - int logicalLength; - size_t elementSize; - listNode *head; - listNode *tail; - freeFunction freeFn; -} list_t; +// forward declarations +typedef struct list_node_s list_node_t; +typedef struct list_s list_t; /** diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index f242106..89ee0c4 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -129,4 +129,64 @@ BOOST_FIXTURE_TEST_CASE(test_tail_list, FixtureStrings) { } +typedef struct test_data_s { + int num; + char *name; +} test_data_t; + +test_data_t *create_test_data(int number, char *name){ + + test_data_t *data = (test_data_t *)malloc(sizeof(test_data_t)); + data->num = number; + if (name) + data->name = _strdup(name); + else + data->name = NULL; + + return data; +} + +void delete_test_data(void *data) { + + test_data_t *test_data = *(test_data_t **)data; + + if (test_data->name) + free(test_data->name); + + free(test_data); +} + +bool iterate_test_data(void *data) +{ + test_data_t *test_data = *(test_data_t **)data; + + printf("Found number: %i name: %s\n", + test_data->num, test_data->name); + return true; +} + +BOOST_AUTO_TEST_CASE(test_struct_list){ + + list_t *list = NULL; + list = create_list(sizeof(test_data_t *), delete_test_data); + + + test_data_t *data = create_test_data(1, "David"); + append_list(list, &data); + + data = create_test_data(2, "Kevin"); + append_list(list, &data); + + data = create_test_data(3, "Michael"); + append_list(list, &data); + + + BOOST_CHECK(size_list(list) == 3); + + for_each_list(list, iterate_test_data); + + delete_list(list); +} + + BOOST_AUTO_TEST_SUITE_END() From 6187bc112e792d94fae1fa72c52e380aa8d347ca Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 16:17:36 -0400 Subject: [PATCH 16/25] Fixing indent --- src/util/list.c | 20 +++++++++---------- tests/util/test_list.cpp | 43 ++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 96d4ad7..237ec1a 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -28,17 +28,17 @@ typedef struct list_node_s { - void *data; - list_node_t *next; + void *data; + list_node_t *next; } list_node_t; typedef struct list_s { - int logicalLength; - size_t elementSize; - list_node_t *head; - list_node_t *tail; - freeFunction freeFn; + int logicalLength; + size_t elementSize; + list_node_t *head; + list_node_t *tail; + freeFunction freeFn; } list_t; @@ -111,7 +111,7 @@ void for_each_list(list_t *list, listIterator iterator) { assert(iterator != NULL); - list_node_t *node = list->head; + list_node_t *node = list->head; bool result = true; while(node != NULL && result) { result = iterator(node->data); @@ -126,7 +126,7 @@ void *head_list(list_t *list, bool removeFromList) { assert(list->head != NULL); - list_node_t *node = list->head; + list_node_t *node = list->head; // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); @@ -152,7 +152,7 @@ void *tail_list(list_t *list) { assert(list->tail != NULL); - list_node_t *node = list->tail; + list_node_t *node = list->tail; // Allocating and copying pointer to node data void *element = (void *)malloc(list->elementSize); memcpy(element, node->data, list->elementSize); diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 89ee0c4..33bcd01 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -130,15 +130,15 @@ BOOST_FIXTURE_TEST_CASE(test_tail_list, FixtureStrings) { typedef struct test_data_s { - int num; - char *name; + int num; + char *name; } test_data_t; test_data_t *create_test_data(int number, char *name){ test_data_t *data = (test_data_t *)malloc(sizeof(test_data_t)); data->num = number; - if (name) + if (name) data->name = _strdup(name); else data->name = NULL; @@ -147,43 +147,42 @@ test_data_t *create_test_data(int number, char *name){ } void delete_test_data(void *data) { - - test_data_t *test_data = *(test_data_t **)data; + + test_data_t *test_data = *(test_data_t **)data; if (test_data->name) free(test_data->name); - + free(test_data); } bool iterate_test_data(void *data) { - test_data_t *test_data = *(test_data_t **)data; + test_data_t *test_data = *(test_data_t **)data; - printf("Found number: %i name: %s\n", - test_data->num, test_data->name); - return true; + printf("Found number: %i name: %s\n", test_data->num, test_data->name); + return true; } BOOST_AUTO_TEST_CASE(test_struct_list){ - - list_t *list = NULL; + + list_t *list = NULL; list = create_list(sizeof(test_data_t *), delete_test_data); - test_data_t *data = create_test_data(1, "David"); - append_list(list, &data); + test_data_t *data = create_test_data(1, "David"); + append_list(list, &data); - data = create_test_data(2, "Kevin"); - append_list(list, &data); - - data = create_test_data(3, "Michael"); - append_list(list, &data); + data = create_test_data(2, "Kevin"); + append_list(list, &data); - - BOOST_CHECK(size_list(list) == 3); + data = create_test_data(3, "Michael"); + append_list(list, &data); - for_each_list(list, iterate_test_data); + + BOOST_CHECK(size_list(list) == 3); + + for_each_list(list, iterate_test_data); delete_list(list); } From f10e36336f50f67e21557e13a7686d7c771ec8e1 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 10 Apr 2019 17:59:55 -0400 Subject: [PATCH 17/25] Work in progress --- src/util/list.c | 15 --------------- src/util/list.h | 18 ++++++++++++++---- tests/util/test_list.cpp | 12 +++++++++++- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 237ec1a..4bd8791 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -27,21 +27,6 @@ #include "list.h" -typedef struct list_node_s { - void *data; - list_node_t *next; -} list_node_t; - - -typedef struct list_s { - int logicalLength; - size_t elementSize; - list_node_t *head; - list_node_t *tail; - freeFunction freeFn; -} list_t; - - list_t *create_list(size_t elementSize, freeFunction freeFn) { list_t *list; diff --git a/src/util/list.h b/src/util/list.h index 7f4ed57..7ac11b6 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -25,12 +25,22 @@ extern "C" { // a common function used to free malloc'd objects typedef void(*freeFunction)(void *); -typedef bool (*listIterator)(void *); +typedef bool(*listIterator)(void *); -// forward declarations -typedef struct list_node_s list_node_t; -typedef struct list_s list_t; +typedef struct list_node_s { + void *data; + struct list_node_s *next; +} list_node_t; + + +typedef struct { + int logicalLength; + size_t elementSize; + list_node_t *head; + list_node_t *tail; + freeFunction freeFn; +} list_t; /** diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 33bcd01..34f27e7 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -164,6 +164,8 @@ bool iterate_test_data(void *data) return true; } + + BOOST_AUTO_TEST_CASE(test_struct_list){ list_t *list = NULL; @@ -182,10 +184,18 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ BOOST_CHECK(size_list(list) == 3); - for_each_list(list, iterate_test_data); + //for_each_list(list, iterate_test_data); + + // Expose list abstraction and loop over it + list_node_t *lnode; + for (lnode = list->head; lnode != NULL; lnode = lnode->next) { + test_data_t *test_data = *(test_data_t **)lnode->data; + printf("Found number: %i name: %s\n", test_data->num, test_data->name); + } delete_list(list); } +// TODO: search for an index and return data BOOST_AUTO_TEST_SUITE_END() From a7f8fc868e898be074cc0d9359adf6b55dbe5626 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 09:44:08 -0400 Subject: [PATCH 18/25] Reorganized to contain list abstraction --- src/util/list.c | 51 +++++++++++++++++++++++++++++++++++---- src/util/list.h | 47 ++++++++++++++++++++++-------------- tests/util/test_list.cpp | 52 +++++++++++++++++++++++++--------------- 3 files changed, 108 insertions(+), 42 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 4bd8791..1fe3fbc 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -6,7 +6,7 @@ Description: Generic list https://gist.github.com/pseudomuto/6334796#file-list-c Accessed: April 9, 2019 - Authors: David Muto, Modified by Michael E. Tryby + Authors: David Muto, Michael Tryby Copyright: see AUTHORS License: see LICENSE Last Updated: 04/09/2019 @@ -27,6 +27,21 @@ #include "list.h" +typedef struct list_node_s { + void *data; + struct list_node_s *next; +} list_node_t; + + +typedef struct list_s { + int logicalLength; + size_t elementSize; + list_node_t *head; + list_node_t *tail; + freeFunction freeFn; +} list_t; + + list_t *create_list(size_t elementSize, freeFunction freeFn) { list_t *list; @@ -59,7 +74,7 @@ void delete_list(list_t *list) void prepend_list(list_t *list, void *element) { - list_node_t *node = malloc(sizeof(list_node_t)); + list_node_t *node = malloc(sizeof(list_node_t)); node->data = malloc(list->elementSize); memcpy(node->data, element, list->elementSize); @@ -99,7 +114,7 @@ void for_each_list(list_t *list, listIterator iterator) list_node_t *node = list->head; bool result = true; while(node != NULL && result) { - result = iterator(node->data); + result = iterator(node); node = node->next; } } @@ -127,7 +142,7 @@ void *head_list(list_t *list, bool removeFromList) } // Now element points to data formerly pointed to by node. Caller // is responsible for freeing both pointer to data and data. - return element; + return element; } void *tail_list(list_t *list) @@ -144,10 +159,36 @@ void *tail_list(list_t *list) // Pointer to element data gets returned. Caller is responsible // for freeing pointer to data. - return element; + return element; } int size_list(list_t *list) { return list->logicalLength; } + +void *get_data(list_node_t *lnode) +{ + return lnode->data; +} + + +// +// Iterator operations +// http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Iterators.html +// Accessed on April 11, 2019 +// +list_node_t *first_list(list_t *list) +{ + return list->head; +} + +bool done_list(list_node_t *lnode) +{ + return lnode != NULL; +} + +list_node_t *next_list(list_node_t *lnode) +{ + return lnode->next; +} diff --git a/src/util/list.h b/src/util/list.h index 7ac11b6..fe6ffc7 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -6,7 +6,7 @@ Description: Generic list https://gist.github.com/pseudomuto/6334796#file-list-h Accessed: April 9, 2019 - Authors: David Muto, Modified by Michael E. Tryby + Authors: David Muto, Michael Tryby Copyright: see AUTHORS License: see LICENSE Last Updated: 04/09/2019 @@ -23,24 +23,13 @@ extern "C" { #endif -// a common function used to free malloc'd objects + +// Forward declarations +typedef struct list_node_s list_node_t; +typedef struct list_s list_t; + typedef void(*freeFunction)(void *); -typedef bool(*listIterator)(void *); - - -typedef struct list_node_s { - void *data; - struct list_node_s *next; -} list_node_t; - - -typedef struct { - int logicalLength; - size_t elementSize; - list_node_t *head; - list_node_t *tail; - freeFunction freeFn; -} list_t; +typedef bool(*listIterator)(list_node_t *); /** @@ -70,6 +59,12 @@ void append_list(list_t *list, void *element); */ int size_list(list_t *list); +/** +@brief Returns pointer to list node's data. +*/ +void *get_data(list_node_t *lnode); + + /** @brief Calls the supplied iterator function with the data element of each node (iterates over the list). @@ -87,6 +82,22 @@ void *head_list(list_t *list, bool removeFromList); void *tail_list(list_t *list); +/** +@brief Returns list head node. +*/ +list_node_t *first_list(list_t *list); + +/** +@brief Returns true if end of list false otherwise. +*/ +bool done_list(list_node_t *lnode); + +/** +@brief Returns next node in the list. +*/ +list_node_t *next_list(list_node_t *lnode); + + #if defined(__cplusplus) } #endif diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 34f27e7..aee21fc 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -28,24 +28,16 @@ boost::test_tools::predicate_result check_string(std::string test, std::string r return false; } +int *get_int_data(list_node_t *lnode) { + return (int *)get_data(lnode); +} -bool iterate_int(void *data) +bool iterate_int(list_node_t *lnode) { - printf("Found value: %d\n", *(int *)data); + printf("Found value: %d\n", *get_int_data(lnode)); return true; } -bool iterate_string(void *data) -{ - char *string = *(char **)data; - printf("Found string value: %s\n", string); - return true; -} - -void free_string(void *data) -{ - free(*(char **)data); -} BOOST_AUTO_TEST_SUITE(test_list) @@ -76,6 +68,23 @@ BOOST_AUTO_TEST_CASE(test_int_list){ delete_list(list); } + +inline char *get_string_data(list_node_t *lnode) +{ + return *(char **)get_data(lnode); +} + +bool iterate_string(list_node_t *lnode) +{ + printf("Found string value: %s\n", get_string_data(lnode)); + return true; +} + +void free_string(void *data) +{ + free(*(char **)data); +} + struct FixtureStrings{ FixtureStrings() { list = NULL; @@ -134,7 +143,7 @@ typedef struct test_data_s { char *name; } test_data_t; -test_data_t *create_test_data(int number, char *name){ +test_data_t *create_test_data(int number, const char *name){ test_data_t *data = (test_data_t *)malloc(sizeof(test_data_t)); data->num = number; @@ -156,9 +165,14 @@ void delete_test_data(void *data) { free(test_data); } -bool iterate_test_data(void *data) +inline test_data_t *get_test_data(list_node_t *lnode) { - test_data_t *test_data = *(test_data_t **)data; + return *(test_data_t **)get_data(lnode); +} + +bool iterate_test_data(list_node_t *lnode) +{ + test_data_t *test_data = get_test_data(lnode); printf("Found number: %i name: %s\n", test_data->num, test_data->name); return true; @@ -186,10 +200,10 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ //for_each_list(list, iterate_test_data); - // Expose list abstraction and loop over it list_node_t *lnode; - for (lnode = list->head; lnode != NULL; lnode = lnode->next) { - test_data_t *test_data = *(test_data_t **)lnode->data; + // Iterate over list while maintaining containment of abstraction + for (lnode = first_list(list); done_list(lnode); lnode = next_list(lnode)) { + test_data_t *test_data = get_test_data(lnode); printf("Found number: %i name: %s\n", test_data->num, test_data->name); } From af87edbafe90454bb93a0f9c75b1b44a862dc65b Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 09:48:43 -0400 Subject: [PATCH 19/25] Update list.c --- src/util/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/list.c b/src/util/list.c index 1fe3fbc..d7519b8 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -174,7 +174,7 @@ void *get_data(list_node_t *lnode) // -// Iterator operations +// Iterator first/done/next operations // http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Iterators.html // Accessed on April 11, 2019 // From 3f37fdbff489bfe5ba7c46b36cf5ece920fdd783 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 10:45:22 -0400 Subject: [PATCH 20/25] Refactoring head_list and tail_list Simplifying head and tail list. Adding delete_node() to list API. --- src/util/list.c | 48 +++++++++++++--------------------------- src/util/list.h | 10 +++++++-- tests/util/test_list.cpp | 22 +++++++++--------- 3 files changed, 34 insertions(+), 46 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index d7519b8..d3e41d8 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -62,12 +62,7 @@ void delete_list(list_t *list) while(list->head != NULL) { current = list->head; list->head = current->next; - - if (list->freeFn) - list->freeFn(current->data); - - free(current->data); - free(current); + delete_node(list, current); } free(list); } @@ -119,47 +114,26 @@ void for_each_list(list_t *list, listIterator iterator) } } -void *head_list(list_t *list, bool removeFromList) +list_node_t *head_list(list_t *list, bool removeFromList) // -// Warning: Caller is responsible for freeing the node->data returned. +// Warning: When node is removed caller is responsible for freeing it. // { assert(list->head != NULL); list_node_t *node = list->head; - // Allocating and copying pointer to node data - void *element = (void *)malloc(list->elementSize); - memcpy(element, node->data, list->elementSize); - if(removeFromList) { // Disconnecting head node list->head = node->next; list->logicalLength--; - - // Freeing pointer to node->data and node - free(node->data); - free(node); } - // Now element points to data formerly pointed to by node. Caller - // is responsible for freeing both pointer to data and data. - return element; + return node; } -void *tail_list(list_t *list) -// -// Warning: Caller is responsible for freeing the node->data returned. -// +list_node_t *tail_list(list_t *list) { assert(list->tail != NULL); - - list_node_t *node = list->tail; - // Allocating and copying pointer to node data - void *element = (void *)malloc(list->elementSize); - memcpy(element, node->data, list->elementSize); - - // Pointer to element data gets returned. Caller is responsible - // for freeing pointer to data. - return element; + return list->tail; } int size_list(list_t *list) @@ -172,9 +146,17 @@ void *get_data(list_node_t *lnode) return lnode->data; } +void delete_node(list_t *list, list_node_t *lnode) +{ + if (list->freeFn) + list->freeFn(lnode->data); + + free(lnode->data); + free(lnode); +} // -// Iterator first/done/next operations +// Iterator first/done/next operations provide containment for list abstraction // http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Iterators.html // Accessed on April 11, 2019 // diff --git a/src/util/list.h b/src/util/list.h index fe6ffc7..090fa4a 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -59,11 +59,17 @@ void append_list(list_t *list, void *element); */ int size_list(list_t *list); + /** @brief Returns pointer to list node's data. */ void *get_data(list_node_t *lnode); +/** +@brief Frees memory associated with a list node. +*/ +void delete_node(list_t *list, list_node_t *lnode); + /** @brief Calls the supplied iterator function with the data element of each @@ -74,12 +80,12 @@ void for_each_list(list_t *list, listIterator iterator); /** @brief Returns the head of the list (optionally removing it at the same time). */ -void *head_list(list_t *list, bool removeFromList); +list_node_t *head_list(list_t *list, bool removeFromList); /** @brief Returns the tail of the list. */ -void *tail_list(list_t *list); +list_node_t *tail_list(list_t *list); /** diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index aee21fc..df02886 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -116,25 +116,21 @@ BOOST_FIXTURE_TEST_CASE(test_string_list, FixtureStrings) { BOOST_FIXTURE_TEST_CASE(test_head_list, FixtureStrings) { - void *temp = head_list(list, true); + BOOST_CHECK(check_string(get_string_data(head_list(list, false)), "David")); + BOOST_CHECK(size_list(list) == 5); - BOOST_CHECK(check_string(*(char **)temp, "David")); + list_node_t *lnode = head_list(list, true); + BOOST_CHECK(check_string(get_string_data(lnode), "David")); BOOST_CHECK(size_list(list) == 4); - // To free a node, free both the data and reference to data - free_string(temp); - free(temp); + delete_node(list, lnode); } BOOST_FIXTURE_TEST_CASE(test_tail_list, FixtureStrings) { - void *temp = tail_list(list); - - BOOST_CHECK(check_string(*(char **)temp, "Jimi")); + BOOST_CHECK(check_string(get_string_data(tail_list(list)), "Jimi")); BOOST_CHECK(size_list(list) == 5); - - free(temp); } @@ -198,7 +194,8 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ BOOST_CHECK(size_list(list) == 3); - //for_each_list(list, iterate_test_data); + for_each_list(list, iterate_test_data); + list_node_t *lnode; // Iterate over list while maintaining containment of abstraction @@ -207,6 +204,9 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ printf("Found number: %i name: %s\n", test_data->num, test_data->name); } + lnode = head_list(list, true); + delete_node(list, lnode); + delete_list(list); } From d79c766b710d2e91f07b3b5e80f926ab820de02f Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 14:10:57 -0400 Subject: [PATCH 21/25] Update test_list.cpp --- tests/util/test_list.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index df02886..fb671f8 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -121,9 +121,10 @@ BOOST_FIXTURE_TEST_CASE(test_head_list, FixtureStrings) { list_node_t *lnode = head_list(list, true); BOOST_CHECK(check_string(get_string_data(lnode), "David")); - BOOST_CHECK(size_list(list) == 4); - delete_node(list, lnode); + + BOOST_CHECK(check_string(get_string_data(head_list(list, false)), "Kevin")); + BOOST_CHECK(size_list(list) == 4); } @@ -198,10 +199,12 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ list_node_t *lnode; - // Iterate over list while maintaining containment of abstraction + // Iterate over list while maintaining containment of list abstraction for (lnode = first_list(list); done_list(lnode); lnode = next_list(lnode)) { test_data_t *test_data = get_test_data(lnode); - printf("Found number: %i name: %s\n", test_data->num, test_data->name); + + if (test_data->num == 2) + printf("Found %s!\n", test_data->name); } lnode = head_list(list, true); From 57a5f6f1b0de8b5e0c581ed21e737cf2407044f9 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 14:28:43 -0400 Subject: [PATCH 22/25] Update test_list.cpp Fixing bug on gcc --- tests/util/test_list.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index fb671f8..cf72a3f 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -13,8 +13,9 @@ ****************************************************************************** */ -#define BOOST_TEST_MODULE list +#include +#define BOOST_TEST_MODULE list #include #include "util/list.h" From a81a8f4b96f2b5cb71caaa64bdb75972d45d311c Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 14:31:21 -0400 Subject: [PATCH 23/25] Fixing bug --- tests/util/test_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index cf72a3f..370ecb9 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -97,7 +97,7 @@ struct FixtureStrings{ char *name; for (int i = 0; i < numNames; i++) { - name = _strdup(names[i]); + name = strdup(names[i]); append_list(list, &name); } } From 7e83d2c4e1f77dfbe231bf84b8e39cef80ba0417 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 14:37:13 -0400 Subject: [PATCH 24/25] Fixing bug on gcc --- tests/util/test_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 370ecb9..7844e6e 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -146,7 +146,7 @@ test_data_t *create_test_data(int number, const char *name){ test_data_t *data = (test_data_t *)malloc(sizeof(test_data_t)); data->num = number; if (name) - data->name = _strdup(name); + data->name = strdup(name); else data->name = NULL; From 60fd6fa02096b943a0b319bf9e24320e6670aee8 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 11 Apr 2019 14:48:35 -0400 Subject: [PATCH 25/25] Update CMakeLists.txt Adding test_list to ctest --- tests/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3d63d97..61019ed 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -67,3 +67,6 @@ add_test(NAME test_filemanager add_test(NAME test_output COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_output WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/outfile/data) + +add_test(NAME test_list + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_list)