diff --git a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc index 6f95a4a6d..6dd99e2b4 100644 --- a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc @@ -160,3 +160,18 @@ TEST_F(ArrayListErrorInjectionTestSuite, CopyArrayListFailureTest) { // And a celix_err is expected EXPECT_EQ(3, celix_err_getErrorCount()); } + + +TEST_F(ArrayListErrorInjectionTestSuite, InitialCapacityOptionUsed) { + celix_array_list_create_options_t opts{}; + opts.elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING; + opts.initialCapacity = 1; // smaller than number of elements we will add + celix_autoptr(celix_array_list_t) list = celix_arrayList_createWithOptions(&opts); + + // First add fits in initial capacity + EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addString(list, "v1")); + + // Fail the next realloc to verify that a second add triggers a reallocation + celix_ei_expect_realloc((void*)celix_arrayList_addString, 2, nullptr, 1); + EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addString(list, "v2")); +} diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index c9219b9fb..b35b0a235 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -507,3 +507,15 @@ TEST_F(ArrayListTestSuite, ElementTypeToStringTest) { EXPECT_STREQ("Undefined", celix_arrayList_elementTypeToString((celix_array_list_element_type_t)100 /*non existing*/)); } + +TEST_F(ArrayListTestSuite, InitialCapacityOptionTest) { + celix_array_list_create_options_t opts{}; + opts.elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING; + opts.initialCapacity = 1; // smaller than number of elements we will add + celix_autoptr(celix_array_list_t) list = celix_arrayList_createWithOptions(&opts); + + // First add fits in initial capacity + EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addString(list, "v1")); + // Second add requires realloc + EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addString(list, "v2")); +} diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index 8393bc238..bc78b216a 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -20,9 +20,9 @@ #include #include "celix_array_list_type.h" -#include "celix_utils_export.h" #include "celix_cleanup.h" #include "celix_errno.h" +#include "celix_utils_export.h" #include "celix_version_type.h" #ifndef CELIX_ARRAY_LIST_H_ @@ -32,12 +32,13 @@ * Init macro so that the opts are correctly initialized for C++ compilers */ #ifdef __cplusplus -#define CELIX_OPTS_INIT {} +#define CELIX_OPTS_INIT \ + { \ + } #else #define CELIX_OPTS_INIT #endif - #ifdef __cplusplus extern "C" { #endif @@ -57,7 +58,7 @@ typedef enum celix_array_list_element_type { CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING = 2, /**< Represents a string element type where the array list is the owner */ CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG = 3, /**< Represents a long integer element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE = 4, /**< Represents a double element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL = 5, /**< Represents a boolean element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL = 5, /**< Represents a boolean element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION = 6, /**< Represents a celix_version_t* element type. */ } celix_array_list_element_type_t; @@ -75,10 +76,10 @@ typedef union celix_array_list_entry { CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ long int longVal; /**< A long integer value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ - double doubleVal; /**< A double value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE or - CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ - bool boolVal; /**< A boolean value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL or - CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ + double doubleVal; /**< A double value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE or + CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ + bool boolVal; /**< A boolean value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL or + CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ const celix_version_t* versionVal; /**< A celix_version_t* value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ } celix_array_list_entry_t; @@ -252,9 +253,14 @@ typedef struct celix_array_list_create_options { */ #define CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS \ { \ - .elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, .simpleRemovedCallback = NULL, \ - .removedCallbackData = NULL, .removedCallback = NULL, .equalsCallback = NULL, \ - .compareCallback = NULL, .copyCallback = NULL, \ + .elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, \ + .simpleRemovedCallback = NULL, \ + .removedCallbackData = NULL, \ + .removedCallback = NULL, \ + .equalsCallback = NULL, \ + .compareCallback = NULL, \ + .copyCallback = NULL, \ + .initialCapacity = 0, \ } #endif @@ -280,7 +286,7 @@ celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_cre * @note If a (simple) removed callback is configured, the callback will be called for every array list entry. */ CELIX_UTILS_EXPORT -void celix_arrayList_destroy(celix_array_list_t *list); +void celix_arrayList_destroy(celix_array_list_t* list); CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_array_list_t, celix_arrayList_destroy) @@ -288,13 +294,13 @@ CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_array_list_t, celix_arrayList_destroy) * @brief Return the element type of the array list. */ CELIX_UTILS_EXPORT -celix_array_list_element_type_t celix_arrayList_getElementType(const celix_array_list_t *list); +celix_array_list_element_type_t celix_arrayList_getElementType(const celix_array_list_t* list); /** * @brief Returns the size of the array list. */ CELIX_UTILS_EXPORT -int celix_arrayList_size(const celix_array_list_t *list); +int celix_arrayList_size(const celix_array_list_t* list); /** * @brief Returns the value for the provided index. @@ -307,7 +313,7 @@ int celix_arrayList_size(const celix_array_list_t *list); * @return Returns the pointer value for the index. Returns NULL if index is out of bound. */ CELIX_UTILS_EXPORT -void* celix_arrayList_get(const celix_array_list_t *list, int index); +void* celix_arrayList_get(const celix_array_list_t* list, int index); /** * @brief Returns the value for the provided index. @@ -320,7 +326,7 @@ void* celix_arrayList_get(const celix_array_list_t *list, int index); * @return Returns the string value for the index. Returns NULL if index is out of bound. */ CELIX_UTILS_EXPORT -const char* celix_arrayList_getString(const celix_array_list_t *list, int index); +const char* celix_arrayList_getString(const celix_array_list_t* list, int index); /** * @brief Returns the value for the provided index. @@ -333,7 +339,7 @@ const char* celix_arrayList_getString(const celix_array_list_t *list, int index) * @return Returns the long value for the index. Returns 0 if index is out of bound. */ CELIX_UTILS_EXPORT -long int celix_arrayList_getLong(const celix_array_list_t *list, int index); +long int celix_arrayList_getLong(const celix_array_list_t* list, int index); /** * @brief Returns the value for the provided index. @@ -346,7 +352,7 @@ long int celix_arrayList_getLong(const celix_array_list_t *list, int index); * @return Returns the double value for the index. Returns 0 if index is out of bound. */ CELIX_UTILS_EXPORT -double celix_arrayList_getDouble(const celix_array_list_t *list, int index); +double celix_arrayList_getDouble(const celix_array_list_t* list, int index); /** * @brief Returns the value for the provided index. @@ -359,7 +365,7 @@ double celix_arrayList_getDouble(const celix_array_list_t *list, int index); * @return Returns the bool value for the index. Returns false if index is out of bound. */ CELIX_UTILS_EXPORT -bool celix_arrayList_getBool(const celix_array_list_t *list, int index); +bool celix_arrayList_getBool(const celix_array_list_t* list, int index); /** * @brief Returns the value for the provided index. @@ -372,7 +378,7 @@ bool celix_arrayList_getBool(const celix_array_list_t *list, int index); * @return Returns the version value for the index. Returns NULL if index is out of bound. */ CELIX_UTILS_EXPORT -const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t *list, int index); +const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t* list, int index); /** * @brief Returns the entry for the provided index. @@ -382,7 +388,7 @@ const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t *list * @return Returns the entry for the index. Returns NULL if index is out of bound. */ CELIX_UTILS_EXPORT -celix_array_list_entry_t celix_arrayList_getEntry(const celix_array_list_t *list, int index); +celix_array_list_entry_t celix_arrayList_getEntry(const celix_array_list_t* list, int index); /** * @brief add pointer entry to the back of the array list. @@ -529,14 +535,14 @@ celix_status_t celix_arrayList_assignVersion(celix_array_list_t* list, celix_ver * @return The index of the entry or -1 if the entry is not found. */ CELIX_UTILS_EXPORT -int celix_arrayList_indexOf(celix_array_list_t *list, celix_array_list_entry_t entry); +int celix_arrayList_indexOf(celix_array_list_t* list, celix_array_list_entry_t entry); /** * @brief Removes an entry at the provided index. * If the provided index < 0 or out of bound, nothing will be removed. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeAt(celix_array_list_t *list, int index); +void celix_arrayList_removeAt(celix_array_list_t* list, int index); /** * @brief Clear all entries in the array list. @@ -544,7 +550,7 @@ void celix_arrayList_removeAt(celix_array_list_t *list, int index); * @note If a (simple) removed callback is configured, the callback will be called for every array list entry. */ CELIX_UTILS_EXPORT -void celix_arrayList_clear(celix_array_list_t *list); +void celix_arrayList_clear(celix_array_list_t* list); /** * @brief Remove the first entry from array list which matches the provided value. @@ -556,7 +562,7 @@ void celix_arrayList_clear(celix_array_list_t *list); * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeEntry(celix_array_list_t *list, celix_array_list_entry_t entry); +void celix_arrayList_removeEntry(celix_array_list_t* list, celix_array_list_entry_t entry); /** * @brief Remove the first pointer entry from array list which matches the provided value. @@ -634,14 +640,14 @@ void celix_arrayList_removeVersion(celix_array_list_t* list, const celix_version * @brief Sort the array list using the provided sort function. */ CELIX_UTILS_EXPORT -void celix_arrayList_sortEntries(celix_array_list_t *list, celix_array_list_compare_entries_fp compare); +void celix_arrayList_sortEntries(celix_array_list_t* list, celix_array_list_compare_entries_fp compare); /** * @brief Sort the array list using the array list configured compare function. * Note that undefined the array list compare function can be NULL and in that case the array list will not be sorted. */ CELIX_UTILS_EXPORT -void celix_arrayList_sort(celix_array_list_t *list); +void celix_arrayList_sort(celix_array_list_t* list); /** * @brief Check if the array list are equal. diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index 361525f2e..ea49c85ce 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -41,7 +41,7 @@ struct celix_array_list { celix_array_list_entry_t* elementData; size_t size; size_t capacity; - celix_arrayList_equals_fp equalsCallback; + celix_arrayList_equals_fp equalsCallback; celix_array_list_compare_entries_fp compareCallback; celix_array_list_copy_entry_fp copyCallback; void (*simpleRemovedCallback)(void* value); @@ -101,7 +101,8 @@ static bool celix_arrayList_versionEquals(celix_array_list_entry_t a, celix_arra return celix_arrayList_compareVersionEntries(a, b) == 0; } -inline static bool celix_arrayList_equalsForElement(celix_array_list_t *list, celix_array_list_entry_t a, celix_array_list_entry_t b) { +inline static bool +celix_arrayList_equalsForElement(celix_array_list_t* list, celix_array_list_entry_t a, celix_array_list_entry_t b) { // by class invariant, equalsCallback is never NULL return list->equalsCallback(a, b); } @@ -129,7 +130,7 @@ static void celix_arrayList_destroyVersion(void* v) { celix_version_destroy(version); } -static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int index) { +static void celix_arrayList_callRemovedCallback(celix_array_list_t* list, int index) { celix_array_list_entry_t entry = list->elementData[index]; if (list->simpleRemovedCallback != NULL) { list->simpleRemovedCallback(entry.voidPtrVal); @@ -139,7 +140,7 @@ static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int in } static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, size_t capacity) { - celix_array_list_entry_t *newList; + celix_array_list_entry_t* newList; size_t oldCapacity = list->capacity; if (capacity > oldCapacity) { size_t newCapacity = (oldCapacity * 3) / 2 + 1; @@ -192,13 +193,14 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { } celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_create_options_t* opts) { - celix_autofree celix_array_list_t *list = calloc(1, sizeof(*list)); + celix_autofree celix_array_list_t* list = calloc(1, sizeof(*list)); if (!list) { celix_err_push("Failed to allocate memory for list"); return NULL; } - list->capacity = 10; + size_t initialCap = opts->initialCapacity > 0 ? opts->initialCapacity : 10; + list->capacity = initialCap; list->elementData = calloc(list->capacity, sizeof(celix_array_list_entry_t)); if (!list->elementData) { celix_err_push("Failed to allocate memory for elementData"); @@ -208,7 +210,7 @@ celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_cre list->elementType = opts->elementType; celix_arrayList_setTypeSpecificCallbacks(list); - //if opts contains callbacks, use them and override the default ones + // if opts contains callbacks, use them and override the default ones if (opts->simpleRemovedCallback) { list->simpleRemovedCallback = opts->simpleRemovedCallback; } @@ -262,7 +264,7 @@ celix_array_list_t* celix_arrayList_createVersionArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); } -void celix_arrayList_destroy(celix_array_list_t *list) { +void celix_arrayList_destroy(celix_array_list_t* list) { if (list != NULL) { celix_arrayList_clear(list); free(list->elementData); @@ -270,15 +272,13 @@ void celix_arrayList_destroy(celix_array_list_t *list) { } } -celix_array_list_element_type_t celix_arrayList_getElementType(const celix_array_list_t *list) { +celix_array_list_element_type_t celix_arrayList_getElementType(const celix_array_list_t* list) { return list->elementType; } -int celix_arrayList_size(const celix_array_list_t *list) { - return (int)list->size; -} +int celix_arrayList_size(const celix_array_list_t* list) { return (int)list->size; } -static celix_array_list_entry_t arrayList_getEntry(const celix_array_list_t *list, int index) { +static celix_array_list_entry_t arrayList_getEntry(const celix_array_list_t* list, int index) { celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); if (index < list->size) { @@ -287,7 +287,7 @@ static celix_array_list_entry_t arrayList_getEntry(const celix_array_list_t *lis return entry; } -celix_array_list_entry_t celix_arrayList_getEntry(const celix_array_list_t *list, int index) { +celix_array_list_entry_t celix_arrayList_getEntry(const celix_array_list_t* list, int index) { return arrayList_getEntry(list, index); } @@ -429,11 +429,11 @@ celix_status_t celix_arrayList_assignVersion(celix_array_list_t* list, celix_ver return celix_arrayList_addEntry(list, entry); } -int celix_arrayList_indexOf(celix_array_list_t *list, celix_array_list_entry_t entry) { +int celix_arrayList_indexOf(celix_array_list_t* list, celix_array_list_entry_t entry) { size_t size = celix_arrayList_size(list); int i; int index = -1; - for (i = 0 ; i < size ; ++i) { + for (i = 0; i < size; ++i) { bool eq = celix_arrayList_equalsForElement(list, entry, list->elementData[i]); if (eq) { index = i; @@ -442,16 +442,16 @@ int celix_arrayList_indexOf(celix_array_list_t *list, celix_array_list_entry_t e } return index; } -void celix_arrayList_removeAt(celix_array_list_t *list, int index) { +void celix_arrayList_removeAt(celix_array_list_t* list, int index) { if (index >= 0 && index < list->size) { celix_arrayList_callRemovedCallback(list, index); size_t numMoved = list->size - index - 1; - memmove(list->elementData+index, list->elementData+index+1, sizeof(celix_array_list_entry_t) * numMoved); + memmove(list->elementData + index, list->elementData + index + 1, sizeof(celix_array_list_entry_t) * numMoved); memset(&list->elementData[--list->size], 0, sizeof(celix_array_list_entry_t)); } } -void celix_arrayList_removeEntry(celix_array_list_t *list, celix_array_list_entry_t entry) { +void celix_arrayList_removeEntry(celix_array_list_t* list, celix_array_list_entry_t entry) { int index = celix_arrayList_indexOf(list, entry); celix_arrayList_removeAt(list, index); } @@ -510,7 +510,7 @@ void celix_arrayList_removeVersion(celix_array_list_t* list, const celix_version celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_clear(celix_array_list_t *list) { +void celix_arrayList_clear(celix_array_list_t* list) { for (int i = 0; i < list->size; ++i) { celix_arrayList_callRemovedCallback(list, i); memset(&list->elementData[i], 0, sizeof(celix_array_list_entry_t)); @@ -529,7 +529,7 @@ static int celix_arrayList_compareEntries(const void* voidA, const void* voidB, return compare(*a, *b); } -void celix_arrayList_sort(celix_array_list_t *list) { +void celix_arrayList_sort(celix_array_list_t* list) { if (list->compareCallback) { celix_arrayList_sortEntries(list, list->compareCallback); } @@ -592,7 +592,7 @@ celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { return NULL; } } else { - entry = list->elementData[i]; //shallow copy + entry = list->elementData[i]; // shallow copy } (void)celix_arrayList_addEntry(copy, entry); // Cannot fail, because ensureCapacity is already called to @@ -602,7 +602,7 @@ celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { return celix_steal_ptr(copy); } -void celix_arrayList_sortEntries(celix_array_list_t *list, celix_array_list_compare_entries_fp compare) { +void celix_arrayList_sortEntries(celix_array_list_t* list, celix_array_list_compare_entries_fp compare) { #if defined(__APPLE__) qsort_r(list->elementData, list->size, sizeof(celix_array_list_entry_t), compare, celix_arrayList_compareEntries); #else