From 4d8ad4ac18498835107a26f1a442429ac9dcf50c Mon Sep 17 00:00:00 2001 From: David Steele Date: Sun, 26 Nov 2017 18:23:11 -0500 Subject: [PATCH] Add List and StringList objects to simplify list handling. --- doc/xml/release.xml | 4 + src/common/type.h | 2 + src/common/type/list.c | 99 +++++++++++++++++ src/common/type/list.h | 28 +++++ src/common/type/stringList.c | 95 ++++++++++++++++ src/common/type/stringList.h | 25 +++++ test/lib/pgBackRestTest/Common/DefineTest.pm | 11 ++ test/src/module/common/typeListTest.c | 108 +++++++++++++++++++ 8 files changed, 372 insertions(+) create mode 100644 src/common/type/list.c create mode 100644 src/common/type/list.h create mode 100644 src/common/type/stringList.c create mode 100644 src/common/type/stringList.h create mode 100644 test/src/module/common/typeListTest.c diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 6060118cb..6f5f733a8 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -26,6 +26,10 @@

Add String object to simplify string handling.

+ + +

Add List and StringList objects to simplify list handling.

+
diff --git a/src/common/type.h b/src/common/type.h index f54081647..6b7de0f50 100644 --- a/src/common/type.h +++ b/src/common/type.h @@ -32,6 +32,8 @@ typedef int64_t int64; /*********************************************************************************************************************************** Include all header files in type directory for convenience ***********************************************************************************************************************************/ +#include "common/type/list.h" #include "common/type/string.h" +#include "common/type/stringList.h" #endif diff --git a/src/common/type/list.c b/src/common/type/list.c new file mode 100644 index 000000000..1e7853b84 --- /dev/null +++ b/src/common/type/list.c @@ -0,0 +1,99 @@ +/*********************************************************************************************************************************** +List Handler +***********************************************************************************************************************************/ +#include +#include +#include + +#include "common/memContext.h" +#include "common/type/list.h" + +/*********************************************************************************************************************************** +Contains information about the list +***********************************************************************************************************************************/ +struct List +{ + size_t itemSize; + unsigned int listSize; + unsigned int listSizeMax; + unsigned char *list; +}; + +/*********************************************************************************************************************************** +Create a new list +***********************************************************************************************************************************/ +List * +lstNew(size_t itemSize) +{ + // Create object + List *this = memNew(sizeof(List)); + this->itemSize = itemSize; + + // Return buffer + return this; +} + +/*********************************************************************************************************************************** +Add an item to the end of the list +***********************************************************************************************************************************/ +List * +lstAdd(List *this, const void *item) +{ + // If list size = max then allocate more space + if (this->listSize == this->listSizeMax) + { + // If nothing has been allocated yet + if (this->listSizeMax == 0) + { + this->listSizeMax = LIST_INITIAL_SIZE; + this->list = memNewRaw(this->listSizeMax * this->itemSize); + } + // Else the list needs to be extended + else + { + this->listSizeMax *= 2; + this->list = memGrowRaw(this->list, this->listSize * this->itemSize); + } + } + + memcpy(this->list + (this->listSize * this->itemSize), item, this->itemSize); + this->listSize++; + + // Return list + return this; +} + +/*********************************************************************************************************************************** +Get an item from the list +***********************************************************************************************************************************/ +void * +lstGet(const List *this, unsigned int listIdx) +{ + // Ensure list index is in range + if (listIdx >= this->listSize) + THROW(AssertError, "cannot get index %d from list with %d value(s)", listIdx, this->listSize); + + // Return pointer to list item + return this->list + (listIdx * this->itemSize); +} + +/*********************************************************************************************************************************** +Return list size +***********************************************************************************************************************************/ +unsigned int +lstSize(const List *this) +{ + return this->listSize; +} + +/*********************************************************************************************************************************** +Free the string +***********************************************************************************************************************************/ +void +lstFree(List *this) +{ + if (this->list != NULL) + memFree(this->list); + + memFree(this); +} diff --git a/src/common/type/list.h b/src/common/type/list.h new file mode 100644 index 000000000..360192126 --- /dev/null +++ b/src/common/type/list.h @@ -0,0 +1,28 @@ +/*********************************************************************************************************************************** +List Handler +***********************************************************************************************************************************/ +#ifndef COMMON_TYPE_LIST_H +#define COMMON_TYPE_LIST_H + +#include "common/type/string.h" + +/*********************************************************************************************************************************** +Define initial size of a list +***********************************************************************************************************************************/ +#define LIST_INITIAL_SIZE 8 + +/*********************************************************************************************************************************** +List type +***********************************************************************************************************************************/ +typedef struct List List; + +/*********************************************************************************************************************************** +Functions +***********************************************************************************************************************************/ +List *lstNew(size_t itemSize); +List *lstAdd(List *this, const void *item); +void *lstGet(const List *this, unsigned int listIdx); +unsigned int lstSize(const List *this); +void lstFree(List *this); + +#endif diff --git a/src/common/type/stringList.c b/src/common/type/stringList.c new file mode 100644 index 000000000..e53a1f306 --- /dev/null +++ b/src/common/type/stringList.c @@ -0,0 +1,95 @@ +/*********************************************************************************************************************************** +String List Handler +***********************************************************************************************************************************/ +#include +#include +#include + +#include "common/memContext.h" +#include "common/type/list.h" +#include "common/type/stringList.h" + +/*********************************************************************************************************************************** +Wrapper for lstNew() +***********************************************************************************************************************************/ +StringList * +strLstNew() +{ + return (StringList *)lstNew(sizeof(String *)); +} + +/*********************************************************************************************************************************** +Wrapper for lstAdd() +***********************************************************************************************************************************/ +StringList * +strLstAdd(StringList *this, String *string) +{ + return (StringList *)lstAdd((List *)this, &string); +} + +/*********************************************************************************************************************************** +Wrapper for lstGet() +***********************************************************************************************************************************/ +String * +strLstGet(const StringList *this, unsigned int listIdx) +{ + return *(String **)lstGet((List *)this, listIdx); +} + +/*********************************************************************************************************************************** +Concatenate a list of strings into a single string using the specified separator +***********************************************************************************************************************************/ +String *strLstCat(StringList *this, const char *separator) +{ + String *join = strNew(""); + + for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++) + { + if (listIdx != 0) + strCat(join, separator); + + if (strLstGet(this, listIdx) == NULL) + strCat(join, "[NULL]"); + else + strCat(join, strPtr(strLstGet(this, listIdx))); + } + + return join; +} + +/*********************************************************************************************************************************** +Return an array of pointers to the zero-terminated strings in this list. DO NOT override const and modify any of the strings in +this array, though it is OK to modify the array itself. +***********************************************************************************************************************************/ +const char ** +strLstPtr(const StringList *this) +{ + const char **list = memNew(strLstSize(this) * sizeof(char *)); + + for (unsigned int listIdx = 0; listIdx < strLstSize(this); listIdx++) + { + if (strLstGet(this, listIdx) == NULL) + list[listIdx] = NULL; + else + list[listIdx] = strPtr(strLstGet(this, listIdx)); + } + + return list; +} + +/*********************************************************************************************************************************** +Wrapper for lstSize() +***********************************************************************************************************************************/ +unsigned int +strLstSize(const StringList *this) +{ + return lstSize((List *)this); +} + +/*********************************************************************************************************************************** +Wrapper for lstFree() +***********************************************************************************************************************************/ +void strLstFree(StringList *this) +{ + lstFree((List *)this); +} diff --git a/src/common/type/stringList.h b/src/common/type/stringList.h new file mode 100644 index 000000000..044e8b27b --- /dev/null +++ b/src/common/type/stringList.h @@ -0,0 +1,25 @@ +/*********************************************************************************************************************************** +String List Handler +***********************************************************************************************************************************/ +#ifndef COMMON_TYPE_STRING_LIST_H +#define COMMON_TYPE_STRING_LIST_H + +#include "common/type/string.h" + +/*********************************************************************************************************************************** +String list type +***********************************************************************************************************************************/ +typedef struct StringList StringList; + +/*********************************************************************************************************************************** +Functions +***********************************************************************************************************************************/ +StringList *strLstNew(); +StringList *strLstAdd(StringList *this, String *string); +String *strLstGet(const StringList *this, unsigned int listIdx); +String *strLstCat(StringList *this, const char *separator); +const char **strLstPtr(const StringList *this); +unsigned int strLstSize(const StringList *this); +void strLstFree(StringList *this); + +#endif diff --git a/test/lib/pgBackRestTest/Common/DefineTest.pm b/test/lib/pgBackRestTest/Common/DefineTest.pm index 0f88bbb82..330fa2020 100644 --- a/test/lib/pgBackRestTest/Common/DefineTest.pm +++ b/test/lib/pgBackRestTest/Common/DefineTest.pm @@ -125,6 +125,17 @@ my $oTestDef = 'common/memContext' => TESTDEF_COVERAGE_FULL, }, }, + { + &TESTDEF_NAME => 'type-list', + &TESTDEF_TOTAL => 3, + &TESTDEF_C => true, + + &TESTDEF_COVERAGE => + { + 'common/type/list' => TESTDEF_COVERAGE_FULL, + 'common/type/stringList' => TESTDEF_COVERAGE_FULL, + }, + }, { &TESTDEF_NAME => 'type-string', &TESTDEF_TOTAL => 2, diff --git a/test/src/module/common/typeListTest.c b/test/src/module/common/typeListTest.c new file mode 100644 index 000000000..6e4629ad3 --- /dev/null +++ b/test/src/module/common/typeListTest.c @@ -0,0 +1,108 @@ +/*********************************************************************************************************************************** +Test Lists +***********************************************************************************************************************************/ + +/*********************************************************************************************************************************** +Test Run +***********************************************************************************************************************************/ +void testRun() +{ + // ***************************************************************************************************************************** + if (testBegin("lstNew() and lstFree()")) + { + List *list = lstNew(sizeof(void *)); + + TEST_RESULT_INT(list->itemSize, sizeof(void *), "item size"); + TEST_RESULT_INT(list->listSize, 0, "list size"); + TEST_RESULT_INT(list->listSizeMax, 0, "list size max"); + + void *ptr = NULL; + TEST_RESULT_PTR(lstAdd(list, &ptr), list, "add item"); + + lstFree(list); + } + + // ***************************************************************************************************************************** + if (testBegin("lstAdd() and lstSize()")) + { + List *list = lstNew(sizeof(int)); + + // Add ints to the list + for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++) + TEST_RESULT_PTR(lstAdd(list, &listIdx), list, "add item %d", listIdx); + + TEST_RESULT_INT(lstSize(list), 9, "list size"); + + // Read them back and check values + for (unsigned int listIdx = 0; listIdx < lstSize(list); listIdx++) + { + int *item = lstGet(list, listIdx); + TEST_RESULT_INT(*item, listIdx, "check item %d", listIdx); + } + + TEST_ERROR(lstGet(list, lstSize(list)), AssertError, "cannot get index 9 from list with 9 value(s)"); + } + + // ***************************************************************************************************************************** + if (testBegin("StringList")) + { + StringList *list = strLstNew(); + + // Add strings to the list + // ------------------------------------------------------------------------------------------------------------------------- + for (int listIdx = 0; listIdx <= LIST_INITIAL_SIZE; listIdx++) + { + if (listIdx == 0) + { + TEST_RESULT_PTR(strLstAdd(list, NULL), list, "add null item"); + } + else + TEST_RESULT_PTR(strLstAdd(list, strNewFmt("STR%02d", listIdx)), list, "add item %d", listIdx); + } + + TEST_RESULT_INT(strLstSize(list), 9, "list size"); + + // Read them back and check values + // ------------------------------------------------------------------------------------------------------------------------- + for (unsigned int listIdx = 0; listIdx < strLstSize(list); listIdx++) + { + if (listIdx == 0) + { + TEST_RESULT_PTR(strLstGet(list, listIdx), NULL, "check null item"); + } + else + TEST_RESULT_STR(strPtr(strLstGet(list, listIdx)), strPtr(strNewFmt("STR%02d", listIdx)), "check item %d", listIdx); + } + + // Check pointer + // ------------------------------------------------------------------------------------------------------------------------- + const char **szList = strLstPtr(list); + + for (unsigned int listIdx = 0; listIdx < strLstSize(list); listIdx++) + { + if (listIdx == 0) + { + TEST_RESULT_PTR(szList[listIdx], NULL, "check null item"); + } + else + TEST_RESULT_STR(szList[listIdx], strPtr(strNewFmt("STR%02d", listIdx)), "check item %d", listIdx); + } + + // strLstCat() + // ------------------------------------------------------------------------------------------------------------------------- + list = strLstNew(); + + TEST_RESULT_STR(strPtr(strLstCat(list, ", ")), "", "empty list"); + + strLstAdd(list, strNew("item1")); + strLstAdd(list, strNew("item2")); + + TEST_RESULT_STR(strPtr(strLstCat(list, ", ")), "item1, item2", "empty list"); + + strLstAdd(list, NULL); + + TEST_RESULT_STR(strPtr(strLstCat(list, ", ")), "item1, item2, [NULL]", "empty list"); + + strLstFree(list); + } +}