From b4df54cc4626309d11b6e4337f9581d35c07dfac Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 4 Feb 2024 19:05:47 +0100 Subject: [PATCH 01/11] #674 Fix in push stream for gcc 13 --- libs/pushstreams/api/celix/impl/BufferedPushStream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/pushstreams/api/celix/impl/BufferedPushStream.h b/libs/pushstreams/api/celix/impl/BufferedPushStream.h index 5172f42ed..6a2d1e6fd 100644 --- a/libs/pushstreams/api/celix/impl/BufferedPushStream.h +++ b/libs/pushstreams/api/celix/impl/BufferedPushStream.h @@ -98,10 +98,10 @@ void celix::BufferedPushStream::startWorker() { std::weak_ptr>>> weak{queue}; auto lk = weak.lock(); if (lk) { - std::unique_ptr> event = std::move(popQueue()); + std::unique_ptr> event = popQueue(); while (event != nullptr) { this->nextEvent.accept(*event); - event = std::move(popQueue()); + event = popQueue(); } cv.notify_all(); } From ba42e664ca5eff9e43a2d0df1400538161cac2d7 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 4 Feb 2024 19:07:24 +0100 Subject: [PATCH 02/11] #674 Refactor array list compare in ctx, reg and rsa --- .../discovery_common/src/endpoint_discovery_poller.c | 8 ++++++-- .../rsa_common/src/remote_interceptors_handler.c | 10 +++++----- libs/framework/include_deprecated/service_registry.h | 2 +- libs/framework/src/bundle_context.c | 4 ++-- libs/framework/src/service_registry.c | 10 +++++----- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/bundles/remote_services/discovery_common/src/endpoint_discovery_poller.c b/bundles/remote_services/discovery_common/src/endpoint_discovery_poller.c index edf560fca..567ff84b1 100644 --- a/bundles/remote_services/discovery_common/src/endpoint_discovery_poller.c +++ b/bundles/remote_services/discovery_common/src/endpoint_discovery_poller.c @@ -195,7 +195,9 @@ celix_status_t endpointDiscoveryPoller_addDiscoveryEndpoint(endpoint_discovery_p // Avoid memory leaks when adding an already existing URL... celix_array_list_t* endpoints = hashMap_get(poller->entries, url); if (endpoints == NULL) { - endpoints = celix_arrayList_createWithEquals(endpointDiscoveryPoller_endpointDescriptionEquals); + celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; + opts.equalsCallback = endpointDiscoveryPoller_endpointDescriptionEquals; + endpoints = celix_arrayList_createWithOptions(&opts); if (endpoints) { celix_logHelper_debug(*poller->loghelper, "ENDPOINT_POLLER: add new discovery endpoint with url %s", url); @@ -253,7 +255,9 @@ celix_status_t endpointDiscoveryPoller_removeDiscoveryEndpoint(endpoint_discover celix_status_t endpointDiscoveryPoller_poll(endpoint_discovery_poller_t* poller, char* url, celix_array_list_t* currentEndpoints) { // create an arraylist with a custom equality test to ensure we can find endpoints properly... - celix_array_list_t* updatedEndpoints = celix_arrayList_createWithEquals(endpointDiscoveryPoller_endpointDescriptionEquals); + celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; + opts.equalsCallback = endpointDiscoveryPoller_endpointDescriptionEquals; + celix_array_list_t* updatedEndpoints = celix_arrayList_createWithOptions(&opts); if (!updatedEndpoints) { return CELIX_ENOMEM; } diff --git a/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c b/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c index 65c25207c..591e73227 100644 --- a/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c +++ b/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c @@ -42,7 +42,7 @@ struct remote_interceptors_handler { celix_thread_mutex_t lock; }; -static int referenceCompare(const void *a, const void *b); +static int referenceCompare(celix_array_list_entry_t a, celix_array_list_entry_t b); static void remoteInterceptorsHandler_addInterceptor(void *handle, void *svc, const celix_properties_t *props); static void remoteInterceptorsHandler_removeInterceptor(void *handle, void *svc, const celix_properties_t *props); @@ -104,7 +104,7 @@ void remoteInterceptorsHandler_addInterceptor(void *handle, void *svc, const cel entry->interceptor = svc; celix_arrayList_add(handler->interceptors, entry); - celix_arrayList_sort(handler->interceptors, referenceCompare); + celix_arrayList_sortEntries(handler->interceptors, referenceCompare); } celixThreadMutex_unlock(&handler->lock); @@ -197,9 +197,9 @@ void remoteInterceptorHandler_invokePostProxyCall(remote_interceptors_handler_t celixThreadMutex_unlock(&handler->lock); } -int referenceCompare(const void *a, const void *b) { - const entry_t *aEntry = a; - const entry_t *bEntry = b; +int referenceCompare(celix_array_list_entry_t a, celix_array_list_entry_t b) { + const entry_t *aEntry = a.voidPtrVal; + const entry_t *bEntry = b.voidPtrVal; long servIdA = celix_properties_getAsLong(aEntry->properties, CELIX_FRAMEWORK_SERVICE_ID, 0); long servIdB = celix_properties_getAsLong(bEntry->properties, CELIX_FRAMEWORK_SERVICE_ID, 0); diff --git a/libs/framework/include_deprecated/service_registry.h b/libs/framework/include_deprecated/service_registry.h index 84a551041..7cdb785d7 100644 --- a/libs/framework/include_deprecated/service_registry.h +++ b/libs/framework/include_deprecated/service_registry.h @@ -152,7 +152,7 @@ CELIX_FRAMEWORK_EXPORT char* celix_serviceRegistry_createFilterFor( * Find services and return a array list of service ids (long). * Caller is responsible for freeing the returned array list. */ -CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_serviceRegisrty_findServices(celix_service_registry_t* registry, const char* filter); +CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_serviceRegistry_findServices(celix_service_registry_t* registry, const char* filterStr); #ifdef __cplusplus diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c index 0f0bc3441..e1075e71b 100644 --- a/libs/framework/src/bundle_context.c +++ b/libs/framework/src/bundle_context.c @@ -1365,7 +1365,7 @@ long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, con long result = -1L; char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter); if (filter != NULL) { - celix_array_list_t *svcIds = celix_serviceRegisrty_findServices(ctx->framework->registry, filter); + celix_array_list_t *svcIds = celix_serviceRegistry_findServices(ctx->framework->registry, filter); if (svcIds != NULL && celix_arrayList_size(svcIds) > 0) { result = celix_arrayList_getLong(svcIds, 0); } @@ -1388,7 +1388,7 @@ celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_con celix_array_list_t* result = NULL; char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter); if (filter != NULL) { - result = celix_serviceRegisrty_findServices(ctx->framework->registry, filter); + result = celix_serviceRegistry_findServices(ctx->framework->registry, filter); free(filter); } return result; diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c index 467925bb2..0afcd4ae4 100644 --- a/libs/framework/src/service_registry.c +++ b/libs/framework/src/service_registry.c @@ -843,9 +843,9 @@ char* celix_serviceRegistry_createFilterFor(celix_service_registry_t* registry, return filter; } -static int celix_serviceRegistry_compareRegistrations(const void *a, const void *b) { - const service_registration_t* regA = a; - const service_registration_t* regB = b; +static int celix_serviceRegistry_compareRegistrations(celix_array_list_entry_t a, celix_array_list_entry_t b) { + const service_registration_t* regA = a.voidPtrVal; + const service_registration_t* regB = b.voidPtrVal; celix_properties_t* propsA = NULL; celix_properties_t* propsB = NULL; @@ -861,7 +861,7 @@ static int celix_serviceRegistry_compareRegistrations(const void *a, const void return celix_utils_compareServiceIdsAndRanking(servIdA, servRankingA, servIdB, servRankingB); } -celix_array_list_t* celix_serviceRegisrty_findServices( +celix_array_list_t* celix_serviceRegistry_findServices( celix_service_registry_t* registry, const char* filterStr) { @@ -892,7 +892,7 @@ celix_array_list_t* celix_serviceRegisrty_findServices( //sort matched registration and add the svc id to the result list. if (celix_arrayList_size(matchedRegistrations) > 1) { - celix_arrayList_sort(matchedRegistrations, celix_serviceRegistry_compareRegistrations); + celix_arrayList_sortEntries(matchedRegistrations, celix_serviceRegistry_compareRegistrations); } for (int i = 0; i < celix_arrayList_size(matchedRegistrations); ++i) { service_registration_t* reg = celix_arrayList_get(matchedRegistrations, i); From 21f379de8a0ef8923e64453b851747add74ebdc6 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 4 Feb 2024 19:07:44 +0100 Subject: [PATCH 03/11] #674 Add initial element type support for array list --- .../logging/log_admin/src/celix_log_admin.c | 14 +- libs/utils/gtest/src/ArrayListTestSuite.cc | 2 +- libs/utils/include/celix_array_list.h | 453 +++++++++++++++-- libs/utils/src/array_list.c | 465 +++++++++++++++--- libs/utils/src/array_list_private.h | 41 -- 5 files changed, 813 insertions(+), 162 deletions(-) delete mode 100644 libs/utils/src/array_list_private.h diff --git a/bundles/logging/log_admin/src/celix_log_admin.c b/bundles/logging/log_admin/src/celix_log_admin.c index 5b983ef1a..6b1be0f5a 100644 --- a/bundles/logging/log_admin/src/celix_log_admin.c +++ b/bundles/logging/log_admin/src/celix_log_admin.c @@ -429,12 +429,12 @@ static size_t celix_logAdmin_setSinkEnabled(void *handle, const char* select, bo static celix_array_list_t* celix_logAdmin_currentLogServices(void *handle) { celix_log_admin_t* admin = handle; - celix_array_list_t* loggers = celix_arrayList_create(); + celix_array_list_t* loggers = celix_arrayList_createStringArray(); celixThreadRwlock_readLock(&admin->lock); hash_map_iterator_t iter = hashMapIterator_construct(admin->loggers); while (hashMapIterator_hasNext(&iter)) { celix_log_service_entry_t* visit = hashMapIterator_nextValue(&iter); - celix_arrayList_add(loggers, celix_utils_strdup(visit->name)); + celix_arrayList_addString(loggers, visit->name); } celixThreadRwlock_unlock(&admin->lock); return loggers; @@ -442,12 +442,12 @@ static celix_array_list_t* celix_logAdmin_currentLogServices(void *handle) { static celix_array_list_t* celix_logAdmin_currentSinks(void *handle) { celix_log_admin_t* admin = handle; - celix_array_list_t* sinks = celix_arrayList_create(); + celix_array_list_t* sinks = celix_arrayList_createStringArray(); celixThreadRwlock_readLock(&admin->lock); hash_map_iterator_t iter = hashMapIterator_construct(admin->sinks); while (hashMapIterator_hasNext(&iter)) { celix_log_sink_entry_t* entry = hashMapIterator_nextValue(&iter); - celix_arrayList_add(sinks, celix_utils_strdup(entry->name)); + celix_arrayList_addString(sinks, entry->name); } celixThreadRwlock_unlock(&admin->lock); return sinks; @@ -539,8 +539,8 @@ static void celix_logAdmin_setSinkEnabledCmd(celix_log_admin_t* admin, const cha static void celix_logAdmin_InfoCmd(celix_log_admin_t* admin, FILE* outStream, FILE* errorStream CELIX_UNUSED) { celix_array_list_t* logServices = celix_logAdmin_currentLogServices(admin); celix_array_list_t* sinks = celix_logAdmin_currentSinks(admin); - celix_arrayList_sort(logServices, (void*)strcmp); - celix_arrayList_sort(sinks, (void*)strcmp); + celix_arrayList_sort(logServices); + celix_arrayList_sort(sinks); fprintf(outStream, "Log Admin provided log services:\n"); for (int i = 0 ; i < celix_arrayList_size(logServices); ++i) { @@ -552,7 +552,6 @@ static void celix_logAdmin_InfoCmd(celix_log_admin_t* admin, FILE* outStream, FI fprintf(outStream, " |- %i) Log Service %20s, active log level %s, %s\n", i+1, name, celix_logUtils_logLevelToString(level), detailed ? "detailed" : "brief"); } - free(name); } celix_arrayList_destroy(logServices); @@ -565,7 +564,6 @@ static void celix_logAdmin_InfoCmd(celix_log_admin_t* admin, FILE* outStream, FI if (found) { fprintf(outStream, " |- %i) Log Sink %20s, %s\n", i+1, name, enabled ? "enabled" : "disabled"); } - free(name); } } else { fprintf(outStream, "Log Admin has found 0 log sinks\n"); diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 5a0e60c38..488f069f2 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -219,7 +219,7 @@ TEST_F(ArrayListTestSuite, TestSortForArrayList) { EXPECT_EQ(celix_arrayList_getInt(list, 3), 4); - celix_array_list_sort_entries_fp sort = [](celix_array_list_entry_t a, celix_array_list_entry_t b) -> int { + celix_array_list_compare_entries_fp sort = [](celix_array_list_entry_t a, celix_array_list_entry_t b) -> int { return a.intVal - b.intVal; }; celix_arrayList_sortEntries(list, sort); diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index b38772b8f..25925c891 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -22,6 +22,7 @@ #include "celix_cleanup.h" #include "celix_errno.h" #include "celix_utils_export.h" +#include "celix_version.h" #ifndef CELIX_ARRAY_LIST_H_ #define CELIX_ARRAY_LIST_H_ @@ -40,36 +41,83 @@ extern "C" { #endif +/** + * @enum celix_array_list_element_type_t + * @brief An enumeration of the types of elements that can be stored in a Celix array list. + */ +typedef enum celix_array_list_element_type { + CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED = 0, /**< Represents an undefined element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER = 1, /**< Represents a pointer 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_STRING_REF = + 3, /**< Represents a string element type where the array list is not the owner */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_INT = 4, /**< Represents an integer element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG = 5, /**< Represents a long integer element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT = 6, /**< Represents an unsigned integer element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG = 7, /**< Represents an unsigned long integer element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT = 8, /**< Represents a float element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE = 9, /**< Represents a double element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL = 10, /**< Represents a boolean element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE = 11, /**< Represents a size_t element type. */ + CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION = 12 /**< Represents a celix_version_t* element type. */ +} celix_array_list_element_type_t; + +/** + * @union celix_array_list_entry + * @brief A union representing an entry in a Celix array list. + * + * This union can hold different types of values, including pointers, strings, integers, long integers, + * unsigned integers, unsigned long integers, doubles, floats, booleans, and size_t values. + */ typedef union celix_array_list_entry { - void *voidPtrVal; - int intVal; - long int longVal; - unsigned int uintVal; - unsigned long ulongVal; - double doubleVal; - float floatVal; - bool boolVal; - size_t sizeVal; + void* voidPtrVal; /**< A pointer value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_PTR or + CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ + const char* stringVal; /**< A string value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, + CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ + int intVal; /**< An integer value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_INT 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. */ + unsigned int uintVal; /**< An unsigned integer value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or + CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ + unsigned long ulongVal; /**< An unsigned long integer value when the element type is + CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG 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. */ + float floatVal; /**< A float value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT 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. */ + size_t sizeVal; /**< A size_t value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE 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; +/** + * @brief A celix array list, which can store a list of undefined elements. + */ typedef struct celix_array_list celix_array_list_t; +/** + * @brief Equals function for array list entries, can be provided when creating a array list. + */ typedef bool (*celix_arrayList_equals_fp)(celix_array_list_entry_t, celix_array_list_entry_t); -typedef int (*celix_arrayList_sort_fp)(const void *, const void *); - /** * @brief Compare function for array list entries, which can be used to sort a array list. */ typedef int (*celix_array_list_compare_entries_fp)(celix_array_list_entry_t a, celix_array_list_entry_t b); -typedef celix_array_list_compare_entries_fp celix_array_list_sort_entries_fp __attribute__((deprecated("Use celix_arrayList_compare_entries_fp instead"))); - - /** * Additional create options when creating a array list. */ typedef struct celix_array_list_create_options { + /** + * The element type of the array list. Default is CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + */ + celix_array_list_element_type_t elementType CELIX_OPTS_INIT; + /** * A simple removed callback, which if provided will be called if a entry is removed * from the array list. The removed entry is provided as pointer. @@ -104,7 +152,12 @@ typedef struct celix_array_list_create_options { /** * Equals callback used when trying to find a array list entry. */ - bool (*equalsCallback)(celix_array_list_entry_t a, celix_array_list_entry_t b) CELIX_OPTS_INIT; + celix_arrayList_equals_fp equalsCallback CELIX_OPTS_INIT; + + /** + * Compare callback used when sorting the array list. + */ + celix_array_list_compare_entries_fp compareCallback CELIX_OPTS_INIT; } celix_array_list_create_options_t; @@ -112,30 +165,137 @@ typedef struct celix_array_list_create_options { /** * @brief C Macro to create a empty string_hash_map_create_options_t type. */ -#define CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS { \ - .simpleRemovedCallback = NULL, \ - .removedCallbackData = NULL, \ - .removedCallback = NULL, \ - .equalsCallback = NULL \ -} +#define CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS \ + { \ + .elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, .simpleRemovedCallback = NULL, \ + .removedCallbackData = NULL, .removedCallback = NULL, .equalsCallback = NULL, .compareCallback = NULL \ + } #endif /** - * @brief Creates a new empty array list. + * @brief Creates a new empty array list with an undefined element type. + * + * The remove, equals and compare callback will be NULL. + * + * @deprecated Use celix_arrayList_createWithOptions instead. + */ +CELIX_UTILS_DEPRECATED_EXPORT +celix_array_list_t* celix_arrayList_create() __attribute__((deprecated("use create typed array list instead"))); + +/** + * @brief Creates a new empty array list with a pointer element type where the array list is not the owner of the + * pointers. + * + * The remove, equals and compare callback will be NULL. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createPointerArray(); + +/** + * @brief Creates a new empty array list with a string element type where the array list is the owner of the strings. + * + * The remove callback will be configured to free the string, and equals and compare callback will be configured for + * string comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createStringArray(); + +/** + * @brief Creates a new empty array list with a string element type where the array list is **not** the owner of the + * strings. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * string comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createStringRefArray(); + +/** + * @brief Creates a new empty array list with an integer element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * integer comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createIntArray(); + +/** + * @brief Creates a new empty array list with a long integer element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * integer comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createLongArray(); + +/** + * @brief Creates a new empty array list with an unsigned integer element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * unsigned integer comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createUIntArray(); + +/** + * @brief Creates a new empty array list with an unsigned long integer element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * unsigned integer comparison. */ CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_create(); +celix_array_list_t* celix_arrayList_createULongArray(); /** - * @brief Creates a new empty array list, which uses the provided equals to check whether entries - * are equal. - * @deprecated This functions is deprecated, use celix_arrayList_createWithOptions instead. + * @brief Creates a new empty array list with a float element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * float comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createFloatArray(); + +/** + * @brief Creates a new empty array list with a double element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * double comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createDoubleArray(); + +/** + * @brief Creates a new empty array list with a boolean element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * boolean comparison. */ CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createWithEquals(celix_arrayList_equals_fp equals); +celix_array_list_t* celix_arrayList_createBoolArray(); /** - * @brief Creates a new empty array listusing using the provided array list create options. + * @brief Creates a new empty array list with a size_t element type. + * + * The remove callback will be configured to NULL, and equals and compare callback will be configured for + * unsigned integer comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createSizeArray(); + +/** + * @brief Creates a new empty array list with a celix_version_t* element type. + * + * The remove callback will be configured to free a celix version, and equals and compare callback will be configured + * for celix version comparison. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_createVersionArray(); + +/** + * @brief Creates a new empty array list using using the provided array list create options. + * + * The underlying element type will be undefined, until the first element is added. + * * @param opts The create options, only used during the creation of the array list. */ CELIX_UTILS_EXPORT @@ -160,6 +320,9 @@ int celix_arrayList_size(const celix_array_list_t *list); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the pointer value for the index. Returns NULL if index is out of bound. @@ -170,6 +333,22 @@ void* celix_arrayList_get(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, + * CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * + * @param list The array list. + * @param index The entry index to return. + * @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); + +/** + * @brief Returns the value for the provided index. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the int value for the index. Returns 0 if index is out of bound. @@ -180,6 +359,9 @@ int celix_arrayList_getInt(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the long value for the index. Returns 0 if index is out of bound. @@ -190,6 +372,9 @@ long int celix_arrayList_getLong(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the unsigned int value for the index. Returns 0 if index is out of bound. @@ -200,6 +385,9 @@ unsigned int celix_arrayList_getUInt(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the unsigned long value for the index. Returns 0 if index is out of bound. @@ -210,6 +398,9 @@ unsigned long int celix_arrayList_getULong(const celix_array_list_t *list, int i /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the float value for the index. Returns 0 if index is out of bound. @@ -220,6 +411,9 @@ float celix_arrayList_getFloat(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the double value for the index. Returns 0 if index is out of bound. @@ -230,6 +424,9 @@ double celix_arrayList_getDouble(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the bool value for the index. Returns false if index is out of bound. @@ -240,6 +437,9 @@ bool celix_arrayList_getBool(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param index The entry index to return. * @return Returns the size_t value for the index. Returns 0 if index is out of bound. @@ -247,95 +447,197 @@ bool celix_arrayList_getBool(const celix_array_list_t *list, int index); CELIX_UTILS_EXPORT size_t celix_arrayList_getSize(const celix_array_list_t *list, int index); +/** + * @brief Returns the value for the provided index. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, + * or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * + * @param list The array list. + * @param index The entry index to return. + * @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); + /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The pointer value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_add(celix_array_list_t *list, void* value); +celix_status_t celix_arrayList_add(celix_array_list_t* list, void* value); + +/** + * @brief Add a string entry to the back of the array list. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, + * CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * + * If the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, the string will be copied, but + * if the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, the string will be added as reference (as-is). + * + * @param list The array list. + * @param value The string value to add to the array list. + * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. + */ +CELIX_UTILS_EXPORT +celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* value); + +/** + * @brief Add a string entry to the back of a string array list. + * + * The string will not be copied and the array list will take ownership of the string. + * + * Can only be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING. + * + * @param list The array list. + * @param value The string value to add to the array list. + * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. + */ +CELIX_UTILS_EXPORT +celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The int value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addInt(celix_array_list_t *list, int value); +celix_status_t celix_arrayList_addInt(celix_array_list_t* list, int value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The long value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addLong(celix_array_list_t *list, long value); +celix_status_t celix_arrayList_addLong(celix_array_list_t* list, long value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The unsigned int value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addUInt(celix_array_list_t *list, unsigned int value); +celix_status_t celix_arrayList_addUInt(celix_array_list_t* list, unsigned int value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The unsigned long value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addULong(celix_array_list_t *list, unsigned long value); +celix_status_t celix_arrayList_addULong(celix_array_list_t* list, unsigned long value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The float value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addFloat(celix_array_list_t *list, float value); +celix_status_t celix_arrayList_addFloat(celix_array_list_t* list, float value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The double value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addDouble(celix_array_list_t *list, double value); +celix_status_t celix_arrayList_addDouble(celix_array_list_t* list, double value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The bool value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addBool(celix_array_list_t *list, bool value); +celix_status_t celix_arrayList_addBool(celix_array_list_t* list, bool value); /** * @brief add pointer entry to the back of the array list. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * @param map The array list. * @param value The size_t value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addSize(celix_array_list_t *list, size_t value); +celix_status_t celix_arrayList_addSize(celix_array_list_t* list, size_t value); + +/** + * @brief Add a version entry to the back of the version array list. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, + * or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * + * If the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, the version will be copied, but + * if the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, + * the string will be added as reference (as-is). + * + * @param list The array list. + * @param value The version value to add to the array list. + * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. + */ +CELIX_UTILS_EXPORT +celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_version_t* value); + +/** + * @brief Add a version entry to the back of a version array list. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION. + * The version will not be copied and the array list will take ownership of the version. + * + * + * @param list The array list. + * @param value The version value to add to the array list. + * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. + */ +CELIX_UTILS_EXPORT +celix_status_t celix_arrayList_assignVersion(celix_array_list_t* list, celix_version_t* value); /** * @brief Returns the index of the provided entry, if found. @@ -383,83 +685,134 @@ void celix_arrayList_removeEntry(celix_array_list_t *list, celix_array_list_entr /** * @brief Remove the first pointer entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * + * The equals callback provided when the array list was created will be used to find the entry. + * If there was no equals callback provided a direct memory compare will be done. + */ +CELIX_UTILS_EXPORT +void celix_arrayList_remove(celix_array_list_t* list, void* value); + +/** + * @brief Remove the first string entry from array list which matches the provided value. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, + * CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF and CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_remove(celix_array_list_t *list, void *value); +void celix_arrayList_removeString(celix_array_list_t* list, const char* value); /** * @brief Remove the first int entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeInt(celix_array_list_t *list, int value); +void celix_arrayList_removeInt(celix_array_list_t* list, int value); /** * @brief Remove the first long entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeLong(celix_array_list_t *list, long value); +void celix_arrayList_removeLong(celix_array_list_t* list, long value); /** * @brief Remove the first unsigned int entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeUInt(celix_array_list_t *list, unsigned int value); +void celix_arrayList_removeUInt(celix_array_list_t* list, unsigned int value); /** * @brief Remove the first unsigned long entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeULong(celix_array_list_t *list, unsigned long value); +void celix_arrayList_removeULong(celix_array_list_t* list, unsigned long value); /** * @brief Remove the first float entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeFloat(celix_array_list_t *list, float value); +void celix_arrayList_removeFloat(celix_array_list_t* list, float value); /** * @brief Remove the first double entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeDouble(celix_array_list_t *list, double value); +void celix_arrayList_removeDouble(celix_array_list_t* list, double value); /** * @brief Remove the first bool entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeBool(celix_array_list_t *list, bool value); +void celix_arrayList_removeBool(celix_array_list_t* list, bool value); /** * @brief Remove the first size entry from array list which matches the provided value. * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * * The equals callback provided when the array list was created will be used to find the entry. * If there was no equals callback provided a direct memory compare will be done. */ CELIX_UTILS_EXPORT -void celix_arrayList_removeSize(celix_array_list_t *list, size_t value); +void celix_arrayList_removeSize(celix_array_list_t* list, size_t value); + +/** + * @brief Remove the first version entry from array list which matches the provided value. + * + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION and + * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * + * The equals callback provided when the array list was created will be used to find the entry. + * If there was no equals callback provided a direct memory compare will be done. + */ +CELIX_UTILS_EXPORT +void celix_arrayList_removeVersion(celix_array_list_t* list, const celix_version_t* value); /** * @brief Sort the array list using the provided sort function. @@ -468,11 +821,11 @@ CELIX_UTILS_EXPORT void celix_arrayList_sortEntries(celix_array_list_t *list, celix_array_list_compare_entries_fp compare); /** - * @warning Never use this function with array of doubles, since on some 32-bit platform (sizeof(double)==8 && sizeof(void*)==4) - * @deprecated This function is deprecated, use celix_arrayList_sortEntries instead. + * @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_DEPRECATED_EXPORT -void celix_arrayList_sort(celix_array_list_t *list, celix_arrayList_sort_fp sortFp); +CELIX_UTILS_EXPORT +void celix_arrayList_sort(celix_array_list_t *list); #ifdef __cplusplus } diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index 5b7a16e28..807d21b29 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -24,26 +24,135 @@ * \copyright Apache License, Version 2.0 */ -#include +#include +#include #include +#include #include #include "celix_array_list.h" -#include "array_list_private.h" #include "celix_build_assert.h" - -static bool celix_arrayList_defaultEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { +#include "celix_err.h" +#include "celix_stdlib_cleanup.h" +#include "celix_utils.h" + +struct celix_array_list { + celix_array_list_element_type_t elementType; + celix_array_list_entry_t* elementData; + size_t size; + size_t capacity; + unsigned int modCount; + celix_arrayList_equals_fp equalsCallback; + celix_array_list_compare_entries_fp compareCallback; + void (*simpleRemovedCallback)(void* value); + void* removedCallbackData; + void (*removedCallback)(void* data, celix_array_list_entry_t entry); +}; + +static bool celix_arrayList_undefinedEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { return memcmp(&a, &b, sizeof(a)) == 0; } +static int celix_arrayList_comparePtrEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + uintptr_t ptrA = (uintptr_t)a.voidPtrVal; + uintptr_t ptrB = (uintptr_t)b.voidPtrVal; + return (int)(ptrA - ptrB); +} + +static bool celix_arrayList_PtrEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_comparePtrEntries(a, b) == 0; +} + +static int celix_arrayList_compareStringEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return strcmp(a.stringVal, b.stringVal); +} + +static bool celix_arrayList_stringEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareStringEntries(a, b) == 0; +} + +static int celix_arrayList_compareIntEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.intVal - b.intVal; +} + +static bool celix_arrayList_intEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareIntEntries(a, b) == 0; +} + +static int celix_arrayList_compareLongEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.longVal > b.longVal ? 1 : (a.longVal < b.longVal ? -1 : 0); +} + +static bool celix_arrayList_longEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareLongEntries(a, b) == 0; +} + +static int celix_arrayList_compareUIntEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.uintVal > b.uintVal ? 1 : (a.uintVal < b.uintVal ? -1 : 0); +} + +static bool celix_arrayList_uintEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareUIntEntries(a, b) == 0; +} + +static int celix_arrayList_compareULongEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.ulongVal > b.ulongVal ? 1 : (a.ulongVal < b.ulongVal ? -1 : 0); +} + +static bool celix_arrayList_ulongEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareULongEntries(a, b) == 0; +} + +static int celix_arrayList_compareFloatEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.floatVal > b.floatVal ? 1 : (a.floatVal < b.floatVal ? -1 : 0); +} + +static bool celix_arrayList_floatEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareFloatEntries(a, b) == 0; +} + +static int celix_arrayList_compareDoubleEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.doubleVal > b.doubleVal ? 1 : (a.doubleVal < b.doubleVal ? -1 : 0); +} + +static bool celix_arrayList_doubleEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareDoubleEntries(a, b) == 0; +} + +static int celix_arrayList_compareBoolEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.boolVal - b.boolVal; +} + +static bool celix_arrayList_boolEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareBoolEntries(a, b) == 0; +} + +static int celix_arrayList_compareSizeEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return a.sizeVal > b.sizeVal ? 1 : (a.sizeVal < b.sizeVal ? -1 : 0); +} + +static bool celix_arrayList_sizeEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareSizeEntries(a, b) == 0; +} + +static int celix_arrayList_compareVersionEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_version_compareTo(a.versionVal, b.versionVal); +} + +static bool celix_arrayList_versionEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { + return celix_arrayList_compareVersionEntries(a, b) == 0; +} + static bool celix_arrayList_equalsForElement(celix_array_list_t *list, celix_array_list_entry_t a, celix_array_list_entry_t b) { - bool equals = false; - if (list != NULL) { - if (list->equals != NULL) { - equals = list->equals(a, b); - } + if (list && list->equalsCallback != NULL) { + return list->equalsCallback(a, b); } - return equals; + return false; +} + +static void celix_arrayList_destroyVersion(void* v) { + celix_version_t* version = v; + celix_version_destroy(version); } static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int index) { @@ -75,24 +184,139 @@ static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, i return status; } +static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { + switch (list->elementType) { + case CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER: + list->equalsCallback = celix_arrayList_PtrEquals; + list->compareCallback = celix_arrayList_comparePtrEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING: + list->simpleRemovedCallback = free; + list->equalsCallback = celix_arrayList_stringEquals; + list->compareCallback = celix_arrayList_compareStringEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_INT: + list->equalsCallback = celix_arrayList_intEquals; + list->compareCallback = celix_arrayList_compareIntEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG: + list->equalsCallback = celix_arrayList_longEquals; + list->compareCallback = celix_arrayList_compareLongEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT: + list->equalsCallback = celix_arrayList_uintEquals; + list->compareCallback = celix_arrayList_compareUIntEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG: + list->equalsCallback = celix_arrayList_ulongEquals; + list->compareCallback = celix_arrayList_compareULongEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT: + list->equalsCallback = celix_arrayList_floatEquals; + list->compareCallback = celix_arrayList_compareFloatEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE: + list->equalsCallback = celix_arrayList_doubleEquals; + list->compareCallback = celix_arrayList_compareDoubleEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL: + list->equalsCallback = celix_arrayList_boolEquals; + list->compareCallback = celix_arrayList_compareBoolEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE: + list->equalsCallback = celix_arrayList_sizeEquals; + list->compareCallback = celix_arrayList_compareSizeEntries; + break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION: + list->simpleRemovedCallback = celix_arrayList_destroyVersion; + list->equalsCallback = celix_arrayList_versionEquals; + list->compareCallback = celix_arrayList_compareVersionEntries; + break; + default: + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + list->equalsCallback = celix_arrayList_undefinedEquals; + break; + } +} + celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_create_options_t* opts) { - celix_array_list_t *list = calloc(1, sizeof(*list)); - if (list != NULL) { + celix_autofree celix_array_list_t *list = calloc(1, sizeof(*list)); + if (list) { list->capacity = 10; list->elementData = malloc(sizeof(celix_array_list_entry_t) * list->capacity); - list->equals = opts->equalsCallback == NULL ? celix_arrayList_defaultEquals : opts->equalsCallback; - list->simpleRemovedCallback = opts->simpleRemovedCallback; - list->removedCallbackData = opts->removedCallbackData; - list->removedCallback = opts->removedCallback; + if (!list->elementData) { + celix_err_push("Failed to allocate memory for elementData"); + return NULL; + } + + list->elementType = opts->elementType; + celix_arrayList_setTypeSpecificCallbacks(list); + + if (opts->simpleRemovedCallback) { + list->simpleRemovedCallback = opts->simpleRemovedCallback; + } + if (opts->removedCallback) { + list->removedCallback = opts->removedCallback; + list->removedCallbackData = opts->removedCallbackData; + } } - return list; + return celix_steal_ptr(list); } -celix_array_list_t* celix_arrayList_create() { +static celix_array_list_t* celix_arrayList_createTypedArray(celix_array_list_element_type_t type) { celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; + opts.elementType = type; return celix_arrayList_createWithOptions(&opts); } +celix_array_list_t* celix_arrayList_create() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); +} + +celix_array_list_t* celix_arrayList_createPointerArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER); +} + +celix_array_list_t* celix_arrayList_createStringArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING); +} + +celix_array_list_t* celix_arrayList_createStringRefArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF); +} + +celix_array_list_t* celix_arrayList_createIntArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_INT); +} + +celix_array_list_t* celix_arrayList_createLongArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG); +} + +celix_array_list_t* celix_arrayList_createUIntArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT); +} + +celix_array_list_t* celix_arrayList_createULongArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG); +} + +celix_array_list_t* celix_arrayList_createFloatArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT); +} + +celix_array_list_t* celix_arrayList_createDoubleArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE); +} + +celix_array_list_t* celix_arrayList_createBoolArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL); +} + +celix_array_list_t* celix_arrayList_createSizeArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE); +} + celix_array_list_t* celix_arrayList_createWithEquals(celix_arrayList_equals_fp equals) { celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; opts.equalsCallback = equals; @@ -108,7 +332,7 @@ void celix_arrayList_destroy(celix_array_list_t *list) { } int celix_arrayList_size(const celix_array_list_t *list) { - return list->size; + return (int)list->size; } static celix_array_list_entry_t arrayList_getEntry(const celix_array_list_t *list, int index) { @@ -120,41 +344,73 @@ static celix_array_list_entry_t arrayList_getEntry(const celix_array_list_t *lis return entry; } -void* celix_arrayList_get(const celix_array_list_t *list, int index) { +void* celix_arrayList_get(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).voidPtrVal; } -int celix_arrayList_getInt(const celix_array_list_t* list, int index) { return arrayList_getEntry(list, index).intVal; } +const char* celix_arrayList_getString(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + return arrayList_getEntry(list, index).stringVal; +} + +int celix_arrayList_getInt(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_INT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + return arrayList_getEntry(list, index).intVal; +} long int celix_arrayList_getLong(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).longVal; } unsigned int celix_arrayList_getUInt(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).uintVal; } unsigned long int celix_arrayList_getULong(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).ulongVal; } float celix_arrayList_getFloat(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).floatVal; } double celix_arrayList_getDouble(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).doubleVal; } bool celix_arrayList_getBool(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).boolVal; } size_t celix_arrayList_getSize(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).sizeVal; } -static celix_status_t celix_arrayList_addEntry(celix_array_list_t *list, celix_array_list_entry_t entry) { +const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t* list, int index) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); + return arrayList_getEntry(list, index).versionVal; +} + +static celix_status_t celix_arrayList_addEntry(celix_array_list_t* list, celix_array_list_entry_t entry) { celix_status_t status = celix_arrayList_ensureCapacity(list, (int)list->size + 1); if (status == CELIX_SUCCESS) { list->elementData[list->size++] = entry; @@ -162,69 +418,139 @@ static celix_status_t celix_arrayList_addEntry(celix_array_list_t *list, celix_a return status; } -celix_status_t celix_arrayList_add(celix_array_list_t *list, void * element) { +celix_status_t celix_arrayList_add(celix_array_list_t* list, void* element) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.voidPtrVal = element; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addInt(celix_array_list_t *list, int val) { +celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + celix_array_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { + entry.stringVal = celix_utils_strdup(val); + if (entry.stringVal == NULL) { + return CELIX_ENOMEM; + } + } else { + entry.stringVal = val; + } + return celix_arrayList_addEntry(list, entry); +} + +celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* value) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING); + celix_array_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + entry.stringVal = celix_utils_strdup(value); + if (entry.stringVal == NULL) { + return CELIX_ENOMEM; + } + return celix_arrayList_addEntry(list, entry); +} + +celix_status_t celix_arrayList_addInt(celix_array_list_t* list, int val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_INT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.intVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addLong(celix_array_list_t *list, long val) { +celix_status_t celix_arrayList_addLong(celix_array_list_t* list, long val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.longVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addUInt(celix_array_list_t *list, unsigned int val) { +celix_status_t celix_arrayList_addUInt(celix_array_list_t* list, unsigned int val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.uintVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addULong(celix_array_list_t *list, unsigned long val) { +celix_status_t celix_arrayList_addULong(celix_array_list_t* list, unsigned long val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.ulongVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addDouble(celix_array_list_t *list, double val) { +celix_status_t celix_arrayList_addDouble(celix_array_list_t* list, double val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.doubleVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addFloat(celix_array_list_t *list, float val) { +celix_status_t celix_arrayList_addFloat(celix_array_list_t* list, float val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.floatVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addBool(celix_array_list_t *list, bool val) { +celix_status_t celix_arrayList_addBool(celix_array_list_t* list, bool val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.boolVal = val; return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addSize(celix_array_list_t *list, size_t val) { +celix_status_t celix_arrayList_addSize(celix_array_list_t* list, size_t val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.sizeVal = val; return celix_arrayList_addEntry(list, entry); } +celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_version_t* value) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + celix_array_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { + entry.versionVal = celix_version_copy(value); + if (entry.versionVal == NULL) { + return CELIX_ENOMEM; + } + } else { + entry.versionVal = value; + } + return celix_arrayList_addEntry(list, entry); +} + +celix_status_t celix_arrayList_assignVersion(celix_array_list_t* list, celix_version_t* value) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); + celix_array_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + entry.versionVal = value; + return celix_arrayList_addEntry(list, 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; @@ -253,70 +579,106 @@ void celix_arrayList_removeEntry(celix_array_list_t *list, celix_array_list_entr celix_arrayList_removeAt(list, index); } - -void celix_arrayList_remove(celix_array_list_t *list, void *ptr) { +void celix_arrayList_remove(celix_array_list_t* list, void* ptr) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.voidPtrVal = ptr; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeInt(celix_array_list_t *list, int val) { +void celix_arrayList_removeString(celix_array_list_t* list, const char* val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + celix_array_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + entry.stringVal = val; + celix_arrayList_removeEntry(list, entry); +} + +void celix_arrayList_removeInt(celix_array_list_t* list, int val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_INT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.intVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeLong(celix_array_list_t *list, long val) { +void celix_arrayList_removeLong(celix_array_list_t* list, long val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.longVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeUInt(celix_array_list_t *list, unsigned int val) { +void celix_arrayList_removeUInt(celix_array_list_t* list, unsigned int val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.uintVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeULong(celix_array_list_t *list, unsigned long val) { +void celix_arrayList_removeULong(celix_array_list_t* list, unsigned long val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.ulongVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeFloat(celix_array_list_t *list, float val) { +void celix_arrayList_removeFloat(celix_array_list_t* list, float val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.floatVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeDouble(celix_array_list_t *list, double val) { +void celix_arrayList_removeDouble(celix_array_list_t* list, double val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.doubleVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeBool(celix_array_list_t *list, bool val) { +void celix_arrayList_removeBool(celix_array_list_t* list, bool val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.boolVal = val; celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeSize(celix_array_list_t *list, size_t val) { +void celix_arrayList_removeSize(celix_array_list_t* list, size_t val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); entry.sizeVal = val; celix_arrayList_removeEntry(list, entry); } +void celix_arrayList_removeVersion(celix_array_list_t* list, const celix_version_t* val) { + assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION || + list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); + celix_array_list_entry_t entry; + memset(&entry, 0, sizeof(entry)); + entry.versionVal = val; + celix_arrayList_removeEntry(list, entry); +} + void celix_arrayList_clear(celix_array_list_t *list) { list->modCount++; for (int i = 0; i < list->size; ++i) { @@ -344,24 +706,3 @@ void celix_arrayList_sortEntries(celix_array_list_t *list, celix_array_list_comp qsort_r(list->elementData, list->size, sizeof(celix_array_list_entry_t), celix_arrayList_compareEntries, compare); #endif } - -#if defined(__APPLE__) -static int celix_arrayList_compare(void *arg, const void * a, const void *b) { -#else -static int celix_arrayList_compare(const void * a, const void *b, void *arg) { -#endif - const celix_array_list_entry_t *aEntry = a; - const celix_array_list_entry_t *bEntry = b; - - celix_arrayList_sort_fp sort = arg; - - return sort(aEntry->voidPtrVal, bEntry->voidPtrVal); -} - -void celix_arrayList_sort(celix_array_list_t *list, celix_arrayList_sort_fp sortFp) { -#if defined(__APPLE__) - qsort_r(list->elementData, list->size, sizeof(celix_array_list_entry_t), sortFp, celix_arrayList_compare); -#else - qsort_r(list->elementData, list->size, sizeof(celix_array_list_entry_t), celix_arrayList_compare, sortFp); -#endif -} diff --git a/libs/utils/src/array_list_private.h b/libs/utils/src/array_list_private.h deleted file mode 100644 index 1746202d7..000000000 --- a/libs/utils/src/array_list_private.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -/** - * array_list_private.h - * - * \date Aug 4, 2010 - * \author Apache Celix Project Team - * \copyright Apache License, Version 2.0 - */ - -#ifndef array_list_t_PRIVATE_H_ -#define array_list_t_PRIVATE_H_ - -struct celix_array_list { - celix_array_list_entry_t* elementData; - size_t size; - size_t capacity; - unsigned int modCount; - celix_arrayList_equals_fp equals; - void (*simpleRemovedCallback)(void* value); - void* removedCallbackData; - void (*removedCallback)(void* data, celix_array_list_entry_t entry); -}; - -#endif /* array_list_t_PRIVATE_H_ */ From f0ff9d94eb83ba3589e644988c338086db251b18 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 4 Feb 2024 23:32:00 +0100 Subject: [PATCH 04/11] #674 Add array list element type testing --- .../log_admin/gtest/src/LogAdminTestSuite.cc | 8 - .../logging/log_admin/src/celix_log_admin.c | 4 +- .../include/celix_log_control.h | 12 + libs/utils/gtest/CMakeLists.txt | 2 +- libs/utils/gtest/src/ArrayListTestSuite.cc | 351 ++++++++++++++---- libs/utils/include/celix_array_list.h | 10 +- libs/utils/src/array_list.c | 40 +- 7 files changed, 330 insertions(+), 97 deletions(-) diff --git a/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc b/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc index 859a24a72..fe11a78f5 100644 --- a/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc +++ b/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc @@ -208,10 +208,6 @@ TEST_F(LogBundleTestSuite, SinkLogControl) { auto *list = control->currentSinks(control->handle); EXPECT_EQ(3, celix_arrayList_size(list)); - for (int i = 0; i < celix_arrayList_size(list); ++i) { - auto *item = celix_arrayList_get(list, i); - free(item); - } celix_arrayList_destroy(list); @@ -277,10 +273,6 @@ TEST_F(LogBundleTestSuite, LogServiceControl) { auto *list = control->currentLogServices(control->handle); EXPECT_EQ(4, celix_arrayList_size(list)); - for (int i = 0; i < celix_arrayList_size(list); ++i) { - auto *item = celix_arrayList_get(list, i); - free(item); - } celix_arrayList_destroy(list); celix_bundleContext_stopTracker(ctx.get(), trkId1); diff --git a/bundles/logging/log_admin/src/celix_log_admin.c b/bundles/logging/log_admin/src/celix_log_admin.c index 6b1be0f5a..5ed38d53d 100644 --- a/bundles/logging/log_admin/src/celix_log_admin.c +++ b/bundles/logging/log_admin/src/celix_log_admin.c @@ -544,7 +544,7 @@ static void celix_logAdmin_InfoCmd(celix_log_admin_t* admin, FILE* outStream, FI fprintf(outStream, "Log Admin provided log services:\n"); for (int i = 0 ; i < celix_arrayList_size(logServices); ++i) { - char *name = celix_arrayList_get(logServices, i); + const char *name = celix_arrayList_getString(logServices, i); celix_log_level_e level; bool detailed; bool found = celix_logAdmin_logServiceInfoEx(admin, name, &level, &detailed); @@ -558,7 +558,7 @@ static void celix_logAdmin_InfoCmd(celix_log_admin_t* admin, FILE* outStream, FI if (celix_arrayList_size(sinks) > 0) { fprintf(outStream, "Log Admin found log sinks:\n"); for (int i = 0 ; i < celix_arrayList_size(sinks); ++i) { - char *name = celix_arrayList_get(sinks, i); + const char *name = celix_arrayList_getString(sinks, i); bool enabled; bool found = celix_logAdmin_sinkInfo(admin, name, &enabled); if (found) { diff --git a/bundles/logging/log_service_api/include/celix_log_control.h b/bundles/logging/log_service_api/include/celix_log_control.h index 5f3d82f34..98c9a31da 100644 --- a/bundles/logging/log_service_api/include/celix_log_control.h +++ b/bundles/logging/log_service_api/include/celix_log_control.h @@ -44,8 +44,20 @@ typedef struct celix_log_control { size_t (*setSinkEnabled)(void *handle, const char* select, bool enabled); + /** + * @brief Get a list of names for the log service provided by the log service. + * @param handle The service handle. + * @return A string array list. + * The array list is owned by the caller and should be destroyed by calling celix_arrayList_destroy. + */ celix_array_list_t* (*currentLogServices)(void *handle); + /** + * @brief Get a list of sinks names used by the log service. + * @param handle The service handle. + * @return A string array list. + * The array list is owned by the caller and should be destroyed by calling celix_arrayList_destroy. + */ celix_array_list_t* (*currentSinks)(void *handle); bool (*logServiceInfo)(void *handle, const char* loggerName, celix_log_level_e* outActiveLogLevel); diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index e1e22ef7e..db39b9035 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -34,6 +34,7 @@ add_executable(test_utils src/ThreadsTestSuite.cc src/CelixErrnoTestSuite.cc src/CelixUtilsAutoCleanupTestSuite.cc + src/ArrayListTestSuite.cc src/DeprecatedHashmapTestSuite.cc ) @@ -45,7 +46,6 @@ configure_file(resources/properties.txt ${CMAKE_CURRENT_BINARY_DIR}/resources-te if (CELIX_CXX17) add_library(test_utils_cxx17tests OBJECT - src/ArrayListTestSuite.cc #Uses constexpr src/HashMapTestSuite.cc #Uses constexpr ) target_link_libraries(test_utils_cxx17tests PRIVATE utils_cut Celix::utils GTest::gtest) diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 488f069f2..6a5081886 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -83,76 +83,26 @@ TEST_F(ArrayListTestSuite, TestArrayListWithEquals) { } template -void testArrayListForTemplateType(int nrEntries) { - auto* list = celix_arrayList_create(); +void testArrayListForTemplateType(const std::vector& entries, + const std::function& create, + const std::function& add, + const std::function& get, + const std::function& remove) { + auto* list = create(); //fill - for (int i = 0; i < nrEntries; ++i) { - if constexpr (std::is_same_v) { - celix_arrayList_add(list, (void*)(intptr_t )i); - } else if constexpr (std::is_same_v) { - celix_arrayList_addInt(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_addLong(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_addUInt(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_addULong(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_addFloat(list, i + 0.0f); - } else if constexpr (std::is_same_v) { - celix_arrayList_addDouble(list, i + 0.0); - } else if constexpr (std::is_same_v) { - celix_arrayList_addBool(list, i % 2 == 0); - } else if constexpr (std::is_same_v) { - celix_arrayList_addSize(list, i); - } + for (const auto& entry : entries) { + add(list, entry); } - EXPECT_EQ(celix_arrayList_size(list), nrEntries); + EXPECT_EQ(celix_arrayList_size(list), entries.size()); //get - for (int i = 0; i < nrEntries; ++i) { - if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_get(list, i), (void*)(intptr_t )i); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getInt(list, i), i); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getLong(list, i), i); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getUInt(list, i), i); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getULong(list, i), i); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getFloat(list, i), i + 0.0); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getDouble(list, i), i + 0.0); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getBool(list, i), i % 2 == 0); - } else if constexpr (std::is_same_v) { - EXPECT_EQ(celix_arrayList_getSize(list, i), i); - } + for (int i = 0; i < (int)entries.size(); ++i) { + EXPECT_EQ(get(list, i), entries[i]); } //remove - for (int i = 0; i < nrEntries; ++i) { - if constexpr (std::is_same_v) { - celix_arrayList_remove(list, (void*)(intptr_t)i); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeInt(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeLong(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeUInt(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeULong(list, i); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeFloat(list, i + 0.0); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeDouble(list, i + 0.0); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeBool(list, i % 2 == 0); - } else if constexpr (std::is_same_v) { - celix_arrayList_removeSize(list, i); - } + for (int i = 0; i < (int)entries.size(); ++i) { + remove(list, entries[i]); } EXPECT_EQ(celix_arrayList_size(list), 0); @@ -160,15 +110,270 @@ void testArrayListForTemplateType(int nrEntries) { } TEST_F(ArrayListTestSuite, TestDifferentEntyTypesForArrayList) { - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); - testArrayListForTemplateType(10); + std::vector intEntries{1, 2, 3, 4, 5}; + testArrayListForTemplateType(intEntries, + celix_arrayList_createIntArray, + celix_arrayList_addInt, + celix_arrayList_getInt, + celix_arrayList_removeInt); + + std::vector longEntries{1L, 2L, 3L, 4L, 5L}; + testArrayListForTemplateType(longEntries, + celix_arrayList_createLongArray, + celix_arrayList_addLong, + celix_arrayList_getLong, + celix_arrayList_removeLong); + + std::vector floatEntries{1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; + testArrayListForTemplateType(floatEntries, + celix_arrayList_createFloatArray, + celix_arrayList_addFloat, + celix_arrayList_getFloat, + celix_arrayList_removeFloat); + + std::vector doubleEntries{1.0, 2.0, 3.0, 4.0, 5.0}; + testArrayListForTemplateType(doubleEntries, + celix_arrayList_createDoubleArray, + celix_arrayList_addDouble, + celix_arrayList_getDouble, + celix_arrayList_removeDouble); + + std::vector boolEntries{true, false, true, false, true}; + testArrayListForTemplateType(boolEntries, + celix_arrayList_createBoolArray, + celix_arrayList_addBool, + celix_arrayList_getBool, + celix_arrayList_removeBool); + + std::vector voidPtrEntries{(void*)0x11, (void*)0x22, (void*)0x33, (void*)0x44, (void*)0x55}; + testArrayListForTemplateType(voidPtrEntries, + celix_arrayList_createPointerArray, + celix_arrayList_add, + celix_arrayList_get, + celix_arrayList_remove); + + std::vector uintEntries{1, 2, 3, 4, 5}; + testArrayListForTemplateType(uintEntries, + celix_arrayList_createUIntArray, + celix_arrayList_addUInt, + celix_arrayList_getUInt, + celix_arrayList_removeUInt); + + std::vector ulongEntries{1, 2, 3, 4, 5}; + testArrayListForTemplateType(ulongEntries, + celix_arrayList_createULongArray, + celix_arrayList_addULong, + celix_arrayList_getULong, + celix_arrayList_removeULong); + + std::vector sizeEntries{1, 2, 3, 4, 5}; + testArrayListForTemplateType(sizeEntries, + celix_arrayList_createSizeArray, + celix_arrayList_addSize, + celix_arrayList_getSize, + celix_arrayList_removeSize); +} + +TEST_F(ArrayListTestSuite, StringArrayList) { + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + const char* str1 = "1"; + celix_arrayList_addString(stringList, str1); + celix_arrayList_addString(stringList, "2"); + celix_arrayList_assignString(stringList, strdup("3")); + + EXPECT_EQ(3, celix_arrayList_size(stringList)); + EXPECT_STREQ("1", celix_arrayList_getString(stringList, 0)); + EXPECT_NE((void*)str1, (void*)celix_arrayList_getString(stringList, 0)); //string is added as copy + EXPECT_STREQ("2", celix_arrayList_getString(stringList, 1)); + EXPECT_STREQ("3", celix_arrayList_getString(stringList, 2)); + + celix_arrayList_removeString(stringList, "2"); + EXPECT_EQ(2, celix_arrayList_size(stringList)); + + celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray(); + celix_arrayList_addString(stringRefList, str1); + celix_arrayList_addString(stringRefList, "2"); + celix_arrayList_addString(stringRefList, "3"); + + EXPECT_EQ(3, celix_arrayList_size(stringRefList)); + EXPECT_STREQ("1", celix_arrayList_getString(stringRefList, 0)); + EXPECT_EQ((void*)str1, (void*)celix_arrayList_getString(stringRefList, 0)); //string is added as reference + EXPECT_STREQ("2", celix_arrayList_getString(stringRefList, 1)); + + celix_arrayList_removeString(stringRefList, "2"); + EXPECT_EQ(2, celix_arrayList_size(stringRefList)); +} + +TEST_F(ArrayListTestSuite, VersionArrayList) { + celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); + celix_version_t* v1 = celix_version_create(1, 2, 3, "a"); + celix_arrayList_addVersion(versionList, v1); //copy + celix_arrayList_assignVersion(versionList, v1); //transfer ownership + celix_arrayList_assignVersion(versionList, celix_version_create(2, 3, 4, "b")); + + EXPECT_EQ(3, celix_arrayList_size(versionList)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 0), 1, 2)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 1), 1, 2)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 2), 2, 3)); + + EXPECT_NE((void*)v1, (void*)celix_arrayList_getVersion(versionList, 0)); //version is added as copy + EXPECT_EQ((void*)v1, (void*)celix_arrayList_getVersion(versionList, 1)); //version is added as reference + + celix_autoptr(celix_version_t) vRef = celix_version_create(1, 2, 3, "a"); + celix_arrayList_removeVersion(versionList, vRef); + EXPECT_EQ(2, celix_arrayList_size(versionList)); +} + +TEST_F(ArrayListTestSuite, SortTypedArrayLists) { + // Given a ptr, string, int, long, uint, ulong, float, double, bool, size and version list + // with unsorted values (including duplicates) + celix_autoptr(celix_array_list_t) ptrList = celix_arrayList_createPointerArray(); + celix_arrayList_add(ptrList, (void*)0x33); + celix_arrayList_add(ptrList, (void*)0x11); + celix_arrayList_add(ptrList, (void*)0x22); + celix_arrayList_add(ptrList, (void*)0x11); + + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + celix_arrayList_addString(stringList, "3"); + celix_arrayList_addString(stringList, "1"); + celix_arrayList_addString(stringList, "2"); + celix_arrayList_addString(stringList, "1"); + + celix_autoptr(celix_array_list_t) intList = celix_arrayList_createIntArray(); + celix_arrayList_addInt(intList, 3); + celix_arrayList_addInt(intList, 1); + celix_arrayList_addInt(intList, 2); + celix_arrayList_addInt(intList, 1); + + celix_autoptr(celix_array_list_t) longList = celix_arrayList_createLongArray(); + celix_arrayList_addLong(longList, 3L); + celix_arrayList_addLong(longList, 1L); + celix_arrayList_addLong(longList, 2L); + celix_arrayList_addLong(longList, 1L); + + celix_autoptr(celix_array_list_t) uintList = celix_arrayList_createUIntArray(); + celix_arrayList_addUInt(uintList, 3U); + celix_arrayList_addUInt(uintList, 1U); + celix_arrayList_addUInt(uintList, 2U); + celix_arrayList_addUInt(uintList, 1U); + + celix_autoptr(celix_array_list_t) ulongList = celix_arrayList_createULongArray(); + celix_arrayList_addULong(ulongList, 3UL); + celix_arrayList_addULong(ulongList, 1UL); + celix_arrayList_addULong(ulongList, 2UL); + celix_arrayList_addULong(ulongList, 1UL); + + celix_autoptr(celix_array_list_t) floatList = celix_arrayList_createFloatArray(); + celix_arrayList_addFloat(floatList, 3.0f); + celix_arrayList_addFloat(floatList, 1.0f); + celix_arrayList_addFloat(floatList, 2.0f); + celix_arrayList_addFloat(floatList, 1.0f); + + celix_autoptr(celix_array_list_t) doubleList = celix_arrayList_createDoubleArray(); + celix_arrayList_addDouble(doubleList, 3.0); + celix_arrayList_addDouble(doubleList, 1.0); + celix_arrayList_addDouble(doubleList, 2.0); + celix_arrayList_addDouble(doubleList, 1.0); + + celix_autoptr(celix_array_list_t) boolList = celix_arrayList_createBoolArray(); + celix_arrayList_addBool(boolList, false); + celix_arrayList_addBool(boolList, true); + celix_arrayList_addBool(boolList, false); + + celix_autoptr(celix_array_list_t) sizeList = celix_arrayList_createSizeArray(); + celix_arrayList_addSize(sizeList, 3); + celix_arrayList_addSize(sizeList, 1); + celix_arrayList_addSize(sizeList, 2); + celix_arrayList_addSize(sizeList, 1); + + celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); + celix_arrayList_assignVersion(versionList, celix_version_create(2, 1, 0, "")); + celix_arrayList_assignVersion(versionList, celix_version_create(3, 2, 1, "")); + celix_arrayList_assignVersion(versionList, celix_version_create(2, 1, 0, "")); + celix_arrayList_assignVersion(versionList, celix_version_create(1, 0, 0, "b")); + celix_arrayList_assignVersion(versionList, celix_version_create(1, 0, 0, "a")); + + // Then the element type is correctly set + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER, celix_arrayList_getElementType(ptrList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, celix_arrayList_getElementType(stringList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_INT, celix_arrayList_getElementType(intList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG, celix_arrayList_getElementType(longList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT, celix_arrayList_getElementType(uintList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG, celix_arrayList_getElementType(ulongList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT, celix_arrayList_getElementType(floatList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE, celix_arrayList_getElementType(doubleList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL, celix_arrayList_getElementType(boolList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE, celix_arrayList_getElementType(sizeList)); + EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, celix_arrayList_getElementType(versionList)); + + // When sorting the lists + celix_arrayList_sort(ptrList); + celix_arrayList_sort(stringList); + celix_arrayList_sort(intList); + celix_arrayList_sort(longList); + celix_arrayList_sort(uintList); + celix_arrayList_sort(ulongList); + celix_arrayList_sort(floatList); + celix_arrayList_sort(doubleList); + celix_arrayList_sort(boolList); + celix_arrayList_sort(sizeList); + celix_arrayList_sort(versionList); + + // Then the lists are sorted + EXPECT_EQ((void*)0x11, celix_arrayList_get(ptrList, 0)); + EXPECT_EQ((void*)0x11, celix_arrayList_get(ptrList, 1)); + EXPECT_EQ((void*)0x22, celix_arrayList_get(ptrList, 2)); + EXPECT_EQ((void*)0x33, celix_arrayList_get(ptrList, 3)); + + EXPECT_STREQ("1", celix_arrayList_getString(stringList, 0)); + EXPECT_STREQ("1", celix_arrayList_getString(stringList, 1)); + EXPECT_STREQ("2", celix_arrayList_getString(stringList, 2)); + EXPECT_STREQ("3", celix_arrayList_getString(stringList, 3)); + + EXPECT_EQ(1, celix_arrayList_getInt(intList, 0)); + EXPECT_EQ(1, celix_arrayList_getInt(intList, 1)); + EXPECT_EQ(2, celix_arrayList_getInt(intList, 2)); + EXPECT_EQ(3, celix_arrayList_getInt(intList, 3)); + + EXPECT_EQ(1L, celix_arrayList_getLong(longList, 0)); + EXPECT_EQ(1L, celix_arrayList_getLong(longList, 1)); + EXPECT_EQ(2L, celix_arrayList_getLong(longList, 2)); + EXPECT_EQ(3L, celix_arrayList_getLong(longList, 3)); + + EXPECT_EQ(1U, celix_arrayList_getUInt(uintList, 0)); + EXPECT_EQ(1U, celix_arrayList_getUInt(uintList, 1)); + EXPECT_EQ(2U, celix_arrayList_getUInt(uintList, 2)); + EXPECT_EQ(3U, celix_arrayList_getUInt(uintList, 3)); + + EXPECT_EQ(1UL, celix_arrayList_getULong(ulongList, 0)); + EXPECT_EQ(1UL, celix_arrayList_getULong(ulongList, 1)); + EXPECT_EQ(2UL, celix_arrayList_getULong(ulongList, 2)); + EXPECT_EQ(3UL, celix_arrayList_getULong(ulongList, 3)); + + EXPECT_FLOAT_EQ(1.0f, celix_arrayList_getFloat(floatList, 0)); + EXPECT_FLOAT_EQ(1.0f, celix_arrayList_getFloat(floatList, 1)); + EXPECT_FLOAT_EQ(2.0f, celix_arrayList_getFloat(floatList, 2)); + EXPECT_FLOAT_EQ(3.0f, celix_arrayList_getFloat(floatList, 3)); + + EXPECT_DOUBLE_EQ(1.0, celix_arrayList_getDouble(doubleList, 0)); + EXPECT_DOUBLE_EQ(1.0, celix_arrayList_getDouble(doubleList, 1)); + EXPECT_DOUBLE_EQ(2.0, celix_arrayList_getDouble(doubleList, 2)); + EXPECT_DOUBLE_EQ(3.0, celix_arrayList_getDouble(doubleList, 3)); + + EXPECT_FALSE(celix_arrayList_getBool(boolList, 0)); + EXPECT_FALSE(celix_arrayList_getBool(boolList, 1)); + EXPECT_TRUE(celix_arrayList_getBool(boolList, 2)); + + EXPECT_EQ(1, celix_arrayList_getSize(sizeList, 0)); + EXPECT_EQ(1, celix_arrayList_getSize(sizeList, 1)); + EXPECT_EQ(2, celix_arrayList_getSize(sizeList, 2)); + EXPECT_EQ(3, celix_arrayList_getSize(sizeList, 3)); + + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 0), 1, 0)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 1), 1, 0)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 2), 2, 1)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 3), 2, 1)); + EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 4), 3, 2)); } TEST_F(ArrayListTestSuite, TestSimpleRemovedCallbacksForArrayList) { @@ -261,4 +466,4 @@ TEST_F(ArrayListTestSuite, TestReturnStatusAddFunctions) { TEST_F(ArrayListTestSuite, AutoCleanupTest) { celix_autoptr(celix_array_list_t) list = celix_arrayList_create(); EXPECT_NE(nullptr, list); -} \ No newline at end of file +} diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index 25925c891..b4c2dc587 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -294,7 +294,9 @@ celix_array_list_t* celix_arrayList_createVersionArray(); /** * @brief Creates a new empty array list using using the provided array list create options. * - * The underlying element type will be undefined, until the first element is added. + * If the element type is set to something other than CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, the remove, equals, + * and compare callbacks will be set according to the corresponding celix_arrayList_create*Array function. + * The provided callbacks in the options will override the default callbacks. * * @param opts The create options, only used during the creation of the array list. */ @@ -311,6 +313,12 @@ void celix_arrayList_destroy(celix_array_list_t *list); 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); + /** * @brief Returns the size of the array list. */ diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index 807d21b29..cf6681504 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -16,13 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -/** - * array_list.c - * - * \date Aug 4, 2010 - * \author Apache Celix Project Team - * \copyright Apache License, Version 2.0 - */ #include #include @@ -50,7 +43,7 @@ struct celix_array_list { }; static bool celix_arrayList_undefinedEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return memcmp(&a, &b, sizeof(a)) == 0; + return memcmp(&a.voidPtrVal, &b.voidPtrVal, sizeof(a)) == 0; } static int celix_arrayList_comparePtrEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { @@ -195,6 +188,10 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { list->equalsCallback = celix_arrayList_stringEquals; list->compareCallback = celix_arrayList_compareStringEntries; break; + case CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF: + list->equalsCallback = celix_arrayList_stringEquals; + list->compareCallback = celix_arrayList_compareStringEntries; + break; case CELIX_ARRAY_LIST_ELEMENT_TYPE_INT: list->equalsCallback = celix_arrayList_intEquals; list->compareCallback = celix_arrayList_compareIntEntries; @@ -252,6 +249,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->simpleRemovedCallback) { list->simpleRemovedCallback = opts->simpleRemovedCallback; } @@ -259,6 +257,12 @@ celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_cre list->removedCallback = opts->removedCallback; list->removedCallbackData = opts->removedCallbackData; } + if (opts->equalsCallback) { + list->equalsCallback = opts->equalsCallback; + } + if (opts->compareCallback) { + list->compareCallback = opts->compareCallback; + } } return celix_steal_ptr(list); } @@ -317,6 +321,11 @@ celix_array_list_t* celix_arrayList_createSizeArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE); } +celix_array_list_t* celix_arrayList_createVersionArray() { + return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); +} + + celix_array_list_t* celix_arrayList_createWithEquals(celix_arrayList_equals_fp equals) { celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; opts.equalsCallback = equals; @@ -331,6 +340,10 @@ void celix_arrayList_destroy(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; } @@ -448,10 +461,7 @@ celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* valu assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); - entry.stringVal = celix_utils_strdup(value); - if (entry.stringVal == NULL) { - return CELIX_ENOMEM; - } + entry.stringVal = value; return celix_arrayList_addEntry(list, entry); } @@ -699,6 +709,12 @@ static int celix_arrayList_compareEntries(const void* voidA, const void* voidB, return compare(*a, *b); } +void celix_arrayList_sort(celix_array_list_t *list) { + if (list->compareCallback) { + celix_arrayList_sortEntries(list, list->compareCallback); + } +} + 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); From 1f324c5b2bb5ff20defaa9f2bdb32a66d1d33034 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 5 Feb 2024 19:56:44 +0100 Subject: [PATCH 05/11] #674 Add array list equal and copy function --- libs/utils/gtest/src/ArrayListTestSuite.cc | 61 ++++++++++++++++++ libs/utils/include/celix_array_list.h | 73 ++++++++++++++++------ libs/utils/src/array_list.c | 60 ++++++++++++++++++ 3 files changed, 175 insertions(+), 19 deletions(-) diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 6a5081886..18069db7f 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -376,6 +376,67 @@ TEST_F(ArrayListTestSuite, SortTypedArrayLists) { EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 4), 3, 2)); } +TEST_F(ArrayListTestSuite, EqualCheck) { + //Given a selection of long list and a double list + celix_autoptr(celix_array_list_t) list1 = celix_arrayList_createLongArray(); + celix_arrayList_addLong(list1, 1L); + celix_autoptr(celix_array_list_t) list2 = celix_arrayList_createLongArray(); //same as list1 + celix_arrayList_addLong(list2, 1L); + celix_autoptr(celix_array_list_t) list3 = celix_arrayList_createLongArray(); //different values than list1 + celix_arrayList_addLong(list3, 2L); + celix_autoptr(celix_array_list_t) list4 = celix_arrayList_createLongArray(); //different size than list1 + celix_arrayList_addLong(list4, 1L); + celix_arrayList_addLong(list4, 2L); + celix_autoptr(celix_array_list_t) list5 = celix_arrayList_createDoubleArray(); //different type than list1 + celix_arrayList_addDouble(list5, 1.0); + + //The lists can be checked for equality + EXPECT_TRUE(celix_arrayList_equals(list1, list2)); + EXPECT_TRUE(celix_arrayList_equals(list1, list1)); + EXPECT_TRUE(celix_arrayList_equals(nullptr, nullptr)); + + EXPECT_FALSE(celix_arrayList_equals(nullptr, list1)); + EXPECT_FALSE(celix_arrayList_equals(list1, nullptr)); + EXPECT_FALSE(celix_arrayList_equals(list1, list3)); + EXPECT_FALSE(celix_arrayList_equals(list1, list4)); + EXPECT_FALSE(celix_arrayList_equals(list1, list5)); +} + +TEST_F(ArrayListTestSuite, CopyArrayTest) { + // Given a long, string, string ref and version list + celix_autoptr(celix_array_list_t) longList = celix_arrayList_createLongArray(); + celix_arrayList_addLong(longList, 1L); + celix_arrayList_addLong(longList, 2L); + celix_arrayList_addLong(longList, 3L); + + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + celix_arrayList_addString(stringList, "1"); + celix_arrayList_addString(stringList, "2"); + celix_arrayList_addString(stringList, "3"); + + celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray(); + celix_arrayList_addString(stringRefList, "1"); + celix_arrayList_addString(stringRefList, "2"); + celix_arrayList_addString(stringRefList, "3"); + + celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); + celix_arrayList_assignVersion(versionList, celix_version_create(1, 0, 0, "")); + celix_arrayList_assignVersion(versionList, celix_version_create(2, 0, 0, "")); + celix_arrayList_assignVersion(versionList, celix_version_create(3, 0, 0, "")); + + // When copying the lists + celix_autoptr(celix_array_list_t) longListCopy = celix_arrayList_copy(longList); + celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList); + celix_autoptr(celix_array_list_t) stringRefListCopy = celix_arrayList_copy(stringRefList); + celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList); + + // Then the copied lists are equal to the original lists + EXPECT_TRUE(celix_arrayList_equals(longList, longListCopy)); + EXPECT_TRUE(celix_arrayList_equals(stringList, stringListCopy)); + EXPECT_TRUE(celix_arrayList_equals(stringRefList, stringRefListCopy)); + EXPECT_TRUE(celix_arrayList_equals(versionList, versionListCopy)); +} + TEST_F(ArrayListTestSuite, TestSimpleRemovedCallbacksForArrayList) { celix_array_list_create_options_t opts{}; opts.simpleRemovedCallback = free; diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index b4c2dc587..3a0b0ff93 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -163,7 +163,7 @@ typedef struct celix_array_list_create_options { #ifndef __cplusplus /** - * @brief C Macro to create a empty string_hash_map_create_options_t type. + * @brief C Macro to create a empty celix_array_list_create_options_t type. */ #define CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS \ { \ @@ -331,7 +331,7 @@ int celix_arrayList_size(const celix_array_list_t *list); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the pointer value for the index. Returns NULL if index is out of bound. */ @@ -357,7 +357,7 @@ const char* celix_arrayList_getString(const celix_array_list_t *list, int index) * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the int value for the index. Returns 0 if index is out of bound. */ @@ -370,7 +370,7 @@ int celix_arrayList_getInt(const celix_array_list_t *list, int index); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the long value for the index. Returns 0 if index is out of bound. */ @@ -383,7 +383,7 @@ long int celix_arrayList_getLong(const celix_array_list_t *list, int index); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the unsigned int value for the index. Returns 0 if index is out of bound. */ @@ -396,7 +396,7 @@ unsigned int celix_arrayList_getUInt(const celix_array_list_t *list, int index); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the unsigned long value for the index. Returns 0 if index is out of bound. */ @@ -409,7 +409,7 @@ unsigned long int celix_arrayList_getULong(const celix_array_list_t *list, int i * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the float value for the index. Returns 0 if index is out of bound. */ @@ -422,7 +422,7 @@ float celix_arrayList_getFloat(const celix_array_list_t *list, int index); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the double value for the index. Returns 0 if index is out of bound. */ @@ -435,7 +435,7 @@ double celix_arrayList_getDouble(const celix_array_list_t *list, int index); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the bool value for the index. Returns false if index is out of bound. */ @@ -448,7 +448,7 @@ bool celix_arrayList_getBool(const celix_array_list_t *list, int index); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param index The entry index to return. * @return Returns the size_t value for the index. Returns 0 if index is out of bound. */ @@ -474,7 +474,7 @@ const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t *list * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The pointer value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -518,7 +518,7 @@ celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* valu * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The int value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -531,7 +531,7 @@ celix_status_t celix_arrayList_addInt(celix_array_list_t* list, int value); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The long value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -544,7 +544,7 @@ celix_status_t celix_arrayList_addLong(celix_array_list_t* list, long value); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The unsigned int value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -557,7 +557,7 @@ celix_status_t celix_arrayList_addUInt(celix_array_list_t* list, unsigned int va * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The unsigned long value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -570,7 +570,7 @@ celix_status_t celix_arrayList_addULong(celix_array_list_t* list, unsigned long * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The float value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -583,7 +583,7 @@ celix_status_t celix_arrayList_addFloat(celix_array_list_t* list, float value); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The double value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -596,7 +596,7 @@ celix_status_t celix_arrayList_addDouble(celix_array_list_t* list, double value) * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The bool value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -609,7 +609,7 @@ celix_status_t celix_arrayList_addBool(celix_array_list_t* list, bool value); * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * - * @param map The array list. + * @param list The array list. * @param value The size_t value to add to the array list. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ @@ -835,6 +835,41 @@ void celix_arrayList_sortEntries(celix_array_list_t *list, celix_array_list_comp CELIX_UTILS_EXPORT void celix_arrayList_sort(celix_array_list_t *list); +/** + * @brief Check if the array list are equal. + * + * Equal is defined as: + * - The array list have the same size + * - The array list have the same element type + * - The array list have the same equals callback + * - The array list have the same values at the same index + * + * Note that the remove callback and compare callback are ignored. + * + * If both array list are NULL, they are considered equal. + * + * @param listA The first array list. + * @param listB The second array list. + * @return true if the array list are equal, false otherwise. + */ +CELIX_UTILS_EXPORT +bool celix_arrayList_equals(const celix_array_list_t* listA, const celix_array_list_t* listB); + +/** + * @Brief Copy the array list to a new array list. + * + * The new array list will have the same element type and the same callbacks as the original array list. + * If the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, the strings will be copied and + * if the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, the versions will be copied. + * For all other element types the values will be copied. + * + * @param[in] list The array list to copy. + * @return A new array list with the same element type and values as the original array list or NULL if the original + * array list is NULL or out of memory. + */ +CELIX_UTILS_EXPORT +celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list); + #ifdef __cplusplus } #endif diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index cf6681504..59108cf95 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -715,6 +715,66 @@ void celix_arrayList_sort(celix_array_list_t *list) { } } +bool celix_arrayList_equals(const celix_array_list_t* listA, const celix_array_list_t* listB) { + if (listA == listB) { + return true; + } + if (!listA || !listB) { + return false; + } + if (listA->size != listB->size) { + return false; + } + if (listA->equalsCallback != listB->equalsCallback) { + return false; + } + for (int i = 0; i < listA->size; ++i) { + if (!listA->equalsCallback(listA->elementData[i], listB->elementData[i])) { + return false; + } + } + return true; +} + +celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { + celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; + opts.elementType = list->elementType; + opts.equalsCallback = list->equalsCallback; + opts.compareCallback = list->compareCallback; + opts.removedCallback = list->removedCallback; + opts.removedCallbackData = list->removedCallbackData; + opts.simpleRemovedCallback = list->simpleRemovedCallback; + celix_autoptr(celix_array_list_t) copy = celix_arrayList_createWithOptions(&opts); + if (!copy) { + celix_err_push("Failed to create copy list. Out of memory."); + return NULL; + } + + for (int i = 0; i < celix_arrayList_size(list); ++i) { + celix_array_list_entry_t entry = list->elementData[i]; + if (copy->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { + entry.stringVal = celix_utils_strdup(entry.stringVal); + if (entry.stringVal == NULL) { + celix_err_push("Failed to copy string entry. Out of memory."); + return NULL; + } + } else if (copy->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { + entry.versionVal = celix_version_copy(entry.versionVal); + if (entry.versionVal == NULL) { + celix_err_push("Failed to copy version entry. Out of memory."); + return NULL; + } + } + celix_status_t status = celix_arrayList_addEntry(copy, entry); + if (status != CELIX_SUCCESS) { + celix_err_push("Failed to add entry to copy list."); + return NULL; + } + } + + return celix_steal_ptr(copy); +} + 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); From 210512347eef75d758386ed1dcd6305ed231e480 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 5 Feb 2024 23:14:23 +0100 Subject: [PATCH 06/11] #674 Add additional array list ei tests --- .../src/ArrayListErrorInjectionTestSuite.cc | 43 +++++++++++++++++++ libs/utils/gtest/src/ArrayListTestSuite.cc | 18 ++++---- libs/utils/include/celix_array_list.h | 2 + libs/utils/src/array_list.c | 25 +++-------- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc index 1d3d3a7d5..309d54d06 100644 --- a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc @@ -20,6 +20,10 @@ #include #include "celix_array_list.h" +#include "celix_array_list_ei.h" +#include "celix_err.h" +#include "celix_utils_ei.h" +#include "celix_version_ei.h" #include "malloc_ei.h" class ArrayListErrorInjectionTestSuite : public ::testing::Test { @@ -27,6 +31,9 @@ class ArrayListErrorInjectionTestSuite : public ::testing::Test { ArrayListErrorInjectionTestSuite() = default; ~ArrayListErrorInjectionTestSuite() noexcept override { celix_ei_expect_realloc(nullptr, 0, nullptr); + celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); + celix_ei_expect_celix_version_copy(nullptr, 0, nullptr); } }; @@ -49,3 +56,39 @@ TEST_F(ArrayListErrorInjectionTestSuite, TestAddFunctions) { celix_arrayList_destroy(list); } + +TEST_F(ArrayListErrorInjectionTestSuite, AddStringAndAddVersionFailureTest) { + // Given a string array list + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + // When an error is injected for celix_utils_strdup + celix_ei_expect_celix_utils_strdup((void*)celix_arrayList_addString, 0, nullptr); + // Then adding a string should fail + EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addString(stringList, "test")); + + // Given a version array list + celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); + // When an error is injected for celix_version_copy + celix_ei_expect_celix_version_copy((void*)celix_arrayList_addVersion, 0, nullptr); + // Then adding a version should fail + EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addVersion(versionList, NULL)); +} + +TEST_F(ArrayListErrorInjectionTestSuite, CopyArrayListFailureTest) { + // Given a string array list with 10 elements (whitebox knowledge) + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + celix_arrayList_addString(stringList, "test1"); + + // When an error is injected for calloc + celix_ei_expect_calloc((void*)celix_arrayList_copy, 1, nullptr); + // Then copying an array list should fail + EXPECT_EQ(nullptr, celix_arrayList_copy(stringList)); + // And a celix_err is expected + EXPECT_EQ(1, celix_err_getErrorCount()); + + // When an error is injected for celix_utils_strdup + celix_ei_expect_celix_utils_strdup((void*)celix_arrayList_addString, 0, nullptr); + // Then copying an array list should fail + EXPECT_EQ(nullptr, celix_arrayList_copy(stringList)); + // And a celix_err is expected + EXPECT_EQ(2, celix_err_getErrorCount()); +} diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 18069db7f..0bc61c26f 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -26,14 +26,14 @@ class ArrayListTestSuite : public ::testing::Test { public: }; -TEST_F(ArrayListTestSuite, TestCreateDestroyHashMap) { +TEST_F(ArrayListTestSuite, CreateDestroyArrayListTest) { auto* list = celix_arrayList_create(); EXPECT_TRUE(list != nullptr); EXPECT_EQ(0, celix_arrayList_size(list)); celix_arrayList_destroy(list); } -TEST_F(ArrayListTestSuite, TestArrayListWithEquals) { +TEST_F(ArrayListTestSuite, ArrayListWithEqualsTest) { celix_array_list_create_options_t opts{}; opts.equalsCallback = [](celix_array_list_entry_t a, celix_array_list_entry_t b) -> bool { const char* sa = (char*)a.voidPtrVal; @@ -109,7 +109,7 @@ void testArrayListForTemplateType(const std::vector& entries, celix_arrayList_destroy(list); } -TEST_F(ArrayListTestSuite, TestDifferentEntyTypesForArrayList) { +TEST_F(ArrayListTestSuite, TestDifferentEntyTypesForArrayListTest) { std::vector intEntries{1, 2, 3, 4, 5}; testArrayListForTemplateType(intEntries, celix_arrayList_createIntArray, @@ -224,7 +224,7 @@ TEST_F(ArrayListTestSuite, VersionArrayList) { EXPECT_EQ(2, celix_arrayList_size(versionList)); } -TEST_F(ArrayListTestSuite, SortTypedArrayLists) { +TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { // Given a ptr, string, int, long, uint, ulong, float, double, bool, size and version list // with unsorted values (including duplicates) celix_autoptr(celix_array_list_t) ptrList = celix_arrayList_createPointerArray(); @@ -376,7 +376,7 @@ TEST_F(ArrayListTestSuite, SortTypedArrayLists) { EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 4), 3, 2)); } -TEST_F(ArrayListTestSuite, EqualCheck) { +TEST_F(ArrayListTestSuite, EqualCheckTest) { //Given a selection of long list and a double list celix_autoptr(celix_array_list_t) list1 = celix_arrayList_createLongArray(); celix_arrayList_addLong(list1, 1L); @@ -437,7 +437,7 @@ TEST_F(ArrayListTestSuite, CopyArrayTest) { EXPECT_TRUE(celix_arrayList_equals(versionList, versionListCopy)); } -TEST_F(ArrayListTestSuite, TestSimpleRemovedCallbacksForArrayList) { +TEST_F(ArrayListTestSuite, SimpleRemovedCallbacksForArrayListTest) { celix_array_list_create_options_t opts{}; opts.simpleRemovedCallback = free; auto* list = celix_arrayList_createWithOptions(&opts); @@ -449,7 +449,7 @@ TEST_F(ArrayListTestSuite, TestSimpleRemovedCallbacksForArrayList) { celix_arrayList_destroy(list); //will call free for every entry } -TEST_F(ArrayListTestSuite, TestRemovedCallbacksForArrayList) { +TEST_F(ArrayListTestSuite, RemovedCallbacksForArrayListTest) { int count = 0 ; celix_array_list_create_options_t opts{}; opts.removedCallbackData = &count; @@ -473,7 +473,7 @@ TEST_F(ArrayListTestSuite, TestRemovedCallbacksForArrayList) { } -TEST_F(ArrayListTestSuite, TestSortForArrayList) { +TEST_F(ArrayListTestSuite, SortForArrayListTest) { auto* list = celix_arrayList_create(); celix_arrayList_addInt(list, 3); celix_arrayList_addInt(list, 2); @@ -497,7 +497,7 @@ TEST_F(ArrayListTestSuite, TestSortForArrayList) { celix_arrayList_destroy(list); } -TEST_F(ArrayListTestSuite, TestReturnStatusAddFunctions) { +TEST_F(ArrayListTestSuite, ReturnStatusAddFunctionsTest) { auto* list = celix_arrayList_create(); ASSERT_TRUE(list != nullptr); EXPECT_EQ(0, celix_arrayList_size(list)); diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index 3a0b0ff93..716aa1946 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -863,6 +863,8 @@ bool celix_arrayList_equals(const celix_array_list_t* listA, const celix_array_l * if the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, the versions will be copied. * For all other element types the values will be copied. * + * If a NULL is returned and the original array list is not NULL, a error message is logged to celix_err. + * * @param[in] list The array list to copy. * @return A new array list with the same element type and values as the original array list or NULL if the original * array list is NULL or out of memory. diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index 59108cf95..d35f40dfc 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -61,7 +61,7 @@ static int celix_arrayList_compareStringEntries(celix_array_list_entry_t a, celi } static bool celix_arrayList_stringEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return celix_arrayList_compareStringEntries(a, b) == 0; + return celix_utils_stringEquals(a.stringVal, b.stringVal); } static int celix_arrayList_compareIntEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { @@ -325,13 +325,6 @@ celix_array_list_t* celix_arrayList_createVersionArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); } - -celix_array_list_t* celix_arrayList_createWithEquals(celix_arrayList_equals_fp equals) { - celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; - opts.equalsCallback = equals; - return celix_arrayList_createWithOptions(&opts); -} - void celix_arrayList_destroy(celix_array_list_t *list) { if (list != NULL) { celix_arrayList_clear(list); @@ -752,20 +745,14 @@ celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { for (int i = 0; i < celix_arrayList_size(list); ++i) { celix_array_list_entry_t entry = list->elementData[i]; + celix_status_t status; if (copy->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { - entry.stringVal = celix_utils_strdup(entry.stringVal); - if (entry.stringVal == NULL) { - celix_err_push("Failed to copy string entry. Out of memory."); - return NULL; - } + status = celix_arrayList_addString(copy, entry.stringVal); } else if (copy->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { - entry.versionVal = celix_version_copy(entry.versionVal); - if (entry.versionVal == NULL) { - celix_err_push("Failed to copy version entry. Out of memory."); - return NULL; - } + status = celix_arrayList_addVersion(copy, entry.versionVal); + } else { + status = celix_arrayList_addEntry(copy, entry); } - celix_status_t status = celix_arrayList_addEntry(copy, entry); if (status != CELIX_SUCCESS) { celix_err_push("Failed to add entry to copy list."); return NULL; From 5097e4831f20dbe3c947c0fb327327a1ad3cd3e3 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Wed, 7 Feb 2024 19:25:38 +0100 Subject: [PATCH 07/11] #674 Add add/assign nullptr test for array list --- .../src/ArrayListErrorInjectionTestSuite.cc | 26 ++++++- libs/utils/gtest/src/ArrayListTestSuite.cc | 64 +++++++++++++++++ libs/utils/include/celix_array_list.h | 43 +++++++++++- libs/utils/src/array_list.c | 69 +++++++++---------- 4 files changed, 162 insertions(+), 40 deletions(-) diff --git a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc index 309d54d06..f808d3af8 100644 --- a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc @@ -20,7 +20,6 @@ #include #include "celix_array_list.h" -#include "celix_array_list_ei.h" #include "celix_err.h" #include "celix_utils_ei.h" #include "celix_version_ei.h" @@ -34,10 +33,28 @@ class ArrayListErrorInjectionTestSuite : public ::testing::Test { celix_ei_expect_calloc(nullptr, 0, nullptr); celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); celix_ei_expect_celix_version_copy(nullptr, 0, nullptr); + celix_err_resetErrors(); } }; -TEST_F(ArrayListErrorInjectionTestSuite, TestAddFunctions) { +TEST_F(ArrayListErrorInjectionTestSuite, CreateTest) { + //Given an error is injected for calloc (used for the array struct) + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 1, nullptr); + //Then creating an array list should fail + EXPECT_EQ(nullptr, celix_arrayList_create()); + //And an error is logged to the celix_err + EXPECT_EQ(1, celix_err_getErrorCount()); + + //Given an error is injected for malloc (used for the element data) + celix_ei_expect_malloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + //Then creating an array list should fail + EXPECT_EQ(nullptr, celix_arrayList_create()); + //And an error is logged to the celix_err + EXPECT_EQ(2, celix_err_getErrorCount()); +} + + +TEST_F(ArrayListErrorInjectionTestSuite, AddFunctionsTest) { //Given an array list with a capacity of 10 (whitebox knowledge) auto* list = celix_arrayList_create(); @@ -53,6 +70,8 @@ TEST_F(ArrayListErrorInjectionTestSuite, TestAddFunctions) { //Then adding an element should fail EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addInt(list, 10)); EXPECT_EQ(10, celix_arrayList_size(list)); + //And an error is logged to the celix_err + EXPECT_EQ(1, celix_err_getErrorCount()); celix_arrayList_destroy(list); } @@ -70,7 +89,8 @@ TEST_F(ArrayListErrorInjectionTestSuite, AddStringAndAddVersionFailureTest) { // When an error is injected for celix_version_copy celix_ei_expect_celix_version_copy((void*)celix_arrayList_addVersion, 0, nullptr); // Then adding a version should fail - EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addVersion(versionList, NULL)); + celix_autoptr(celix_version_t) version = celix_version_createVersionFromString("1.0.0"); + EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addVersion(versionList, version)); } TEST_F(ArrayListErrorInjectionTestSuite, CopyArrayListFailureTest) { diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 0bc61c26f..e820f714e 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -528,3 +528,67 @@ TEST_F(ArrayListTestSuite, AutoCleanupTest) { celix_autoptr(celix_array_list_t) list = celix_arrayList_create(); EXPECT_NE(nullptr, list); } + +TEST_F(ArrayListTestSuite, AddNullTest) { + // Given an undefined type, string, string ref and version list + celix_autoptr(celix_array_list_t) list = celix_arrayList_create(); + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray(); + celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); + + // When adding a null value to the lists + celix_arrayList_add(list, nullptr); + celix_arrayList_addString(stringList, nullptr); + celix_arrayList_addString(stringRefList, nullptr); + celix_arrayList_addVersion(versionList, nullptr); + + // Then the lists contain the null value + EXPECT_EQ(1, celix_arrayList_size(list)); + EXPECT_EQ(nullptr, celix_arrayList_get(list, 0)); + EXPECT_EQ(1, celix_arrayList_size(stringList)); + EXPECT_EQ(nullptr, celix_arrayList_getString(stringList, 0)); + EXPECT_EQ(1, celix_arrayList_size(stringRefList)); + EXPECT_EQ(nullptr, celix_arrayList_getString(stringRefList, 0)); + EXPECT_EQ(1, celix_arrayList_size(versionList)); + EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionList, 0)); + + // When copying the lists + celix_autoptr(celix_array_list_t) listCopy = celix_arrayList_copy(list); + celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList); + celix_autoptr(celix_array_list_t) stringRefListCopy = celix_arrayList_copy(stringRefList); + celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList); + + // Then the copied lists contain the null value + EXPECT_EQ(1, celix_arrayList_size(listCopy)); + EXPECT_EQ(nullptr, celix_arrayList_get(listCopy, 0)); + EXPECT_EQ(1, celix_arrayList_size(stringListCopy)); + EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0)); + EXPECT_EQ(1, celix_arrayList_size(stringRefListCopy)); + EXPECT_EQ(nullptr, celix_arrayList_getString(stringRefListCopy, 0)); + EXPECT_EQ(1, celix_arrayList_size(versionListCopy)); + EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionListCopy, 0)); +} + +TEST_F(ArrayListTestSuite, AssignNullTest) { + // Given a string and version list + celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); + celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); + + // When assigning a null value to the lists + celix_arrayList_assignString(stringList, nullptr); + celix_arrayList_assignVersion(versionList, nullptr); + + // Then the lists contain the null value + EXPECT_EQ(1, celix_arrayList_size(stringList)); + EXPECT_EQ(nullptr, celix_arrayList_getString(stringList, 0)); + EXPECT_EQ(1, celix_arrayList_size(versionList)); + EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionList, 0)); + + // When copying the lists + celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList); + celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList); + + // Then the copied lists contain the null value + EXPECT_EQ(1, celix_arrayList_size(stringListCopy)); + EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0)); +} diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index 716aa1946..a35d87a69 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -177,16 +177,20 @@ typedef struct celix_array_list_create_options { * * The remove, equals and compare callback will be NULL. * - * @deprecated Use celix_arrayList_createWithOptions instead. + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_DEPRECATED_EXPORT -celix_array_list_t* celix_arrayList_create() __attribute__((deprecated("use create typed array list instead"))); +celix_array_list_t* celix_arrayList_create(); /** * @brief Creates a new empty array list with a pointer element type where the array list is not the owner of the * pointers. * * The remove, equals and compare callback will be NULL. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createPointerArray(); @@ -196,6 +200,9 @@ celix_array_list_t* celix_arrayList_createPointerArray(); * * The remove callback will be configured to free the string, and equals and compare callback will be configured for * string comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createStringArray(); @@ -206,6 +213,9 @@ celix_array_list_t* celix_arrayList_createStringArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * string comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createStringRefArray(); @@ -215,6 +225,9 @@ celix_array_list_t* celix_arrayList_createStringRefArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * integer comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createIntArray(); @@ -224,6 +237,9 @@ celix_array_list_t* celix_arrayList_createIntArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * integer comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createLongArray(); @@ -233,6 +249,9 @@ celix_array_list_t* celix_arrayList_createLongArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * unsigned integer comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createUIntArray(); @@ -242,6 +261,9 @@ celix_array_list_t* celix_arrayList_createUIntArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * unsigned integer comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createULongArray(); @@ -251,6 +273,9 @@ celix_array_list_t* celix_arrayList_createULongArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * float comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createFloatArray(); @@ -260,6 +285,9 @@ celix_array_list_t* celix_arrayList_createFloatArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * double comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createDoubleArray(); @@ -269,6 +297,9 @@ celix_array_list_t* celix_arrayList_createDoubleArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * boolean comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createBoolArray(); @@ -278,6 +309,9 @@ celix_array_list_t* celix_arrayList_createBoolArray(); * * The remove callback will be configured to NULL, and equals and compare callback will be configured for * unsigned integer comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createSizeArray(); @@ -287,6 +321,9 @@ celix_array_list_t* celix_arrayList_createSizeArray(); * * The remove callback will be configured to free a celix version, and equals and compare callback will be configured * for celix version comparison. + * + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createVersionArray(); @@ -299,6 +336,8 @@ celix_array_list_t* celix_arrayList_createVersionArray(); * The provided callbacks in the options will override the default callbacks. * * @param opts The create options, only used during the creation of the array list. + * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message + * is logged to celix_err. */ CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_create_options_t* opts); diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index d35f40dfc..094a313cf 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -158,23 +158,20 @@ static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int in } static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, int capacity) { - celix_status_t status = CELIX_SUCCESS; celix_array_list_entry_t *newList; list->modCount++; size_t oldCapacity = list->capacity; if (capacity > oldCapacity) { size_t newCapacity = (oldCapacity * 3) / 2 + 1; - if (newCapacity < capacity) { - newCapacity = capacity; - } newList = realloc(list->elementData, sizeof(celix_array_list_entry_t) * newCapacity); - if (newList != NULL) { - list->capacity = newCapacity; - list->elementData = newList; + if (!newList) { + celix_err_push("Failed to reallocate memory for elementData"); + return CELIX_ENOMEM; } - status = newList == NULL ? CELIX_ENOMEM : CELIX_SUCCESS; + list->capacity = newCapacity; + list->elementData = newList; } - return status; + return CELIX_SUCCESS; } static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { @@ -238,31 +235,34 @@ 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)); - if (list) { - list->capacity = 10; - list->elementData = malloc(sizeof(celix_array_list_entry_t) * list->capacity); - if (!list->elementData) { - celix_err_push("Failed to allocate memory for elementData"); - return NULL; - } + if (!list) { + celix_err_push("Failed to allocate memory for list"); + return NULL; + } - list->elementType = opts->elementType; - celix_arrayList_setTypeSpecificCallbacks(list); + list->capacity = 10; + list->elementData = malloc(sizeof(celix_array_list_entry_t) * list->capacity); + if (!list->elementData) { + celix_err_push("Failed to allocate memory for elementData"); + return NULL; + } - //if opts contains callbacks, use them and override the default ones - if (opts->simpleRemovedCallback) { - list->simpleRemovedCallback = opts->simpleRemovedCallback; - } - if (opts->removedCallback) { - list->removedCallback = opts->removedCallback; - list->removedCallbackData = opts->removedCallbackData; - } - if (opts->equalsCallback) { - list->equalsCallback = opts->equalsCallback; - } - if (opts->compareCallback) { - list->compareCallback = opts->compareCallback; - } + list->elementType = opts->elementType; + celix_arrayList_setTypeSpecificCallbacks(list); + + //if opts contains callbacks, use them and override the default ones + if (opts->simpleRemovedCallback) { + list->simpleRemovedCallback = opts->simpleRemovedCallback; + } + if (opts->removedCallback) { + list->removedCallback = opts->removedCallback; + list->removedCallbackData = opts->removedCallbackData; + } + if (opts->equalsCallback) { + list->equalsCallback = opts->equalsCallback; + } + if (opts->compareCallback) { + list->compareCallback = opts->compareCallback; } return celix_steal_ptr(list); } @@ -439,7 +439,7 @@ celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* v list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); - if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { + if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING && val) { entry.stringVal = celix_utils_strdup(val); if (entry.stringVal == NULL) { return CELIX_ENOMEM; @@ -535,7 +535,7 @@ celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_ list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); - if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { + if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION && value) { entry.versionVal = celix_version_copy(value); if (entry.versionVal == NULL) { return CELIX_ENOMEM; @@ -739,7 +739,6 @@ celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { opts.simpleRemovedCallback = list->simpleRemovedCallback; celix_autoptr(celix_array_list_t) copy = celix_arrayList_createWithOptions(&opts); if (!copy) { - celix_err_push("Failed to create copy list. Out of memory."); return NULL; } From 86e3b7a4f35eecba69f4e0de3acc9b9a09477aad Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Wed, 7 Feb 2024 23:14:09 +0100 Subject: [PATCH 08/11] #674 Add test that triggers a realloc for the array list --- libs/utils/gtest/src/ArrayListTestSuite.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index e820f714e..2787376c9 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -592,3 +592,19 @@ TEST_F(ArrayListTestSuite, AssignNullTest) { EXPECT_EQ(1, celix_arrayList_size(stringListCopy)); EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0)); } + +TEST_F(ArrayListTestSuite, ReallocTest) { + // Given a list with more than 10 elements (whitebox knowledge that the initial capacity is 10) + celix_autoptr(celix_array_list_t) list = celix_arrayList_createIntArray(); + for (int i = 0; i < 20; ++i) { + celix_status_t status = celix_arrayList_addInt(list, i); + EXPECT_EQ(CELIX_SUCCESS, status); + } + // Then the size is 20 + EXPECT_EQ(20, celix_arrayList_size(list)); + + // And the elements are as expected + for (int i = 0; i < 20; ++i) { + EXPECT_EQ(i, celix_arrayList_getInt(list, i)); + } +} From 05047d54358bccb57b0778bc1dd45caa31cf59ae Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sat, 17 Feb 2024 16:05:21 +0100 Subject: [PATCH 09/11] gh-674: Refactor array list to not allow NULL entries. Also remove support for int, uint, ulong, float and size as array list element. This is now more aligned with hash map. --- CHANGES.md | 1 + .../celix_array_list/CMakeLists.txt | 7 +- .../include/celix_array_list_ei.h | 15 +- .../src/celix_array_list_ei.cc | 55 ++--- libs/utils/gtest/CMakeLists.txt | 24 +- .../src/ArrayListErrorInjectionTestSuite.cc | 11 +- libs/utils/gtest/src/ArrayListTestSuite.cc | 219 ++--------------- .../src/FilterErrorInjectionTestSuite.cc | 37 ++- libs/utils/include/celix_array_list.h | 221 +---------------- libs/utils/src/array_list.c | 229 ++---------------- libs/utils/src/filter.c | 25 +- 11 files changed, 146 insertions(+), 698 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4dd00c48d..5a8dda47a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -58,6 +58,7 @@ limitations under the License. - linked_list.h is removed and no longer supported. Use celix_array_list.h instead. - ip_utils.h is removed and no longer supported. - array_list.h is removed and no longer supported. Use celix_array_list.h instead. +- the celix_arrayList_add function no longer accepts a NULL value. ## New Features diff --git a/libs/utils/error_injector/celix_array_list/CMakeLists.txt b/libs/utils/error_injector/celix_array_list/CMakeLists.txt index 24fb126df..5497998b6 100644 --- a/libs/utils/error_injector/celix_array_list/CMakeLists.txt +++ b/libs/utils/error_injector/celix_array_list/CMakeLists.txt @@ -22,14 +22,13 @@ target_link_libraries(array_list_ei PUBLIC Celix::error_injector Celix::utils) target_link_options(array_list_ei INTERFACE LINKER:--wrap,celix_arrayList_create LINKER:--wrap,celix_arrayList_createWithOptions + LINKER:--wrap,celix_arrayList_createStringArray LINKER:--wrap,celix_arrayList_add LINKER:--wrap,celix_arrayList_addInt LINKER:--wrap,celix_arrayList_addLong - LINKER:--wrap,celix_arrayList_addUInt - LINKER:--wrap,celix_arrayList_addULong - LINKER:--wrap,celix_arrayList_addFloat LINKER:--wrap,celix_arrayList_addDouble LINKER:--wrap,celix_arrayList_addBool - LINKER:--wrap,celix_arrayList_addSize + LINKER:--wrap,celix_arrayList_addString + LINKER:--wrap,celix_arrayList_assignString ) add_library(Celix::array_list_ei ALIAS array_list_ei) diff --git a/libs/utils/error_injector/celix_array_list/include/celix_array_list_ei.h b/libs/utils/error_injector/celix_array_list/include/celix_array_list_ei.h index fb754682e..08ddfb818 100644 --- a/libs/utils/error_injector/celix_array_list/include/celix_array_list_ei.h +++ b/libs/utils/error_injector/celix_array_list/include/celix_array_list_ei.h @@ -30,23 +30,20 @@ CELIX_EI_DECLARE(celix_arrayList_create, celix_array_list_t*); CELIX_EI_DECLARE(celix_arrayList_createWithOptions, celix_array_list_t*); -CELIX_EI_DECLARE(celix_arrayList_add, celix_status_t); +CELIX_EI_DECLARE(celix_arrayList_createStringArray, celix_array_list_t*); -CELIX_EI_DECLARE(celix_arrayList_addInt, celix_status_t); +CELIX_EI_DECLARE(celix_arrayList_add, celix_status_t); CELIX_EI_DECLARE(celix_arrayList_addLong, celix_status_t); -CELIX_EI_DECLARE(celix_arrayList_addUInt, celix_status_t); - -CELIX_EI_DECLARE(celix_arrayList_addULong, celix_status_t); - -CELIX_EI_DECLARE(celix_arrayList_addFloat, celix_status_t); - CELIX_EI_DECLARE(celix_arrayList_addDouble, celix_status_t); CELIX_EI_DECLARE(celix_arrayList_addBool, celix_status_t); -CELIX_EI_DECLARE(celix_arrayList_addSize, celix_status_t); +CELIX_EI_DECLARE(celix_arrayList_addString, celix_status_t); + +CELIX_EI_DECLARE(celix_arrayList_assignString, celix_status_t); + #ifdef __cplusplus } diff --git a/libs/utils/error_injector/celix_array_list/src/celix_array_list_ei.cc b/libs/utils/error_injector/celix_array_list/src/celix_array_list_ei.cc index 9c1cc7864..e528718c2 100644 --- a/libs/utils/error_injector/celix_array_list/src/celix_array_list_ei.cc +++ b/libs/utils/error_injector/celix_array_list/src/celix_array_list_ei.cc @@ -18,6 +18,7 @@ */ #include "celix_array_list_ei.h" +#include "celix_stdlib_cleanup.h" extern "C" { @@ -35,6 +36,13 @@ void *__wrap_celix_arrayList_createWithOptions(const celix_array_list_create_opt return __real_celix_arrayList_createWithOptions(opts); } +void *__real_celix_arrayList_createStringArray(); +CELIX_EI_DEFINE(celix_arrayList_createStringArray, celix_array_list_t*) +void *__wrap_celix_arrayList_createStringArray() { + CELIX_EI_IMPL(celix_arrayList_createStringArray); + return __real_celix_arrayList_createStringArray(); +} + celix_status_t __real_celix_arrayList_add(celix_array_list_t* list, void* value); CELIX_EI_DEFINE(celix_arrayList_add, celix_status_t) celix_status_t __wrap_celix_arrayList_add(celix_array_list_t* list, void* value) { @@ -42,13 +50,6 @@ celix_status_t __wrap_celix_arrayList_add(celix_array_list_t* list, void* value) return __real_celix_arrayList_add(list, value); } -celix_status_t __real_celix_arrayList_addInt(celix_array_list_t* list, int value); -CELIX_EI_DEFINE(celix_arrayList_addInt, celix_status_t) -celix_status_t __wrap_celix_arrayList_addInt(celix_array_list_t* list, int value) { - CELIX_EI_IMPL(celix_arrayList_addInt); - return __real_celix_arrayList_addInt(list, value); -} - celix_status_t __real_celix_arrayList_addLong(celix_array_list_t* list, long value); CELIX_EI_DEFINE(celix_arrayList_addLong, celix_status_t) celix_status_t __wrap_celix_arrayList_addLong(celix_array_list_t* list, long value) { @@ -56,27 +57,6 @@ celix_status_t __wrap_celix_arrayList_addLong(celix_array_list_t* list, long val return __real_celix_arrayList_addLong(list, value); } -celix_status_t __real_celix_arrayList_addUInt(celix_array_list_t* list, unsigned int value); -CELIX_EI_DEFINE(celix_arrayList_addUInt, celix_status_t) -celix_status_t __wrap_celix_arrayList_addUInt(celix_array_list_t* list, unsigned int value) { - CELIX_EI_IMPL(celix_arrayList_addUInt); - return __real_celix_arrayList_addUInt(list, value); -} - -celix_status_t __real_celix_arrayList_addULong(celix_array_list_t* list, unsigned long value); -CELIX_EI_DEFINE(celix_arrayList_addULong, celix_status_t) -celix_status_t __wrap_celix_arrayList_addULong(celix_array_list_t* list, unsigned long value) { - CELIX_EI_IMPL(celix_arrayList_addULong); - return __real_celix_arrayList_addULong(list, value); -} - -celix_status_t __real_celix_arrayList_addFloat(celix_array_list_t* list, float value); -CELIX_EI_DEFINE(celix_arrayList_addFloat, celix_status_t) -celix_status_t __wrap_celix_arrayList_addFloat(celix_array_list_t* list, float value) { - CELIX_EI_IMPL(celix_arrayList_addFloat); - return __real_celix_arrayList_addFloat(list, value); -} - celix_status_t __real_celix_arrayList_addDouble(celix_array_list_t* list, double value); CELIX_EI_DEFINE(celix_arrayList_addDouble, celix_status_t) celix_status_t __wrap_celix_arrayList_addDouble(celix_array_list_t* list, double value) { @@ -91,11 +71,20 @@ celix_status_t __wrap_celix_arrayList_addBool(celix_array_list_t* list, bool val return __real_celix_arrayList_addBool(list, value); } -celix_status_t __real_celix_arrayList_addSize(celix_array_list_t* list, size_t value); -CELIX_EI_DEFINE(celix_arrayList_addSize, celix_status_t) -celix_status_t __wrap_celix_arrayList_addSize(celix_array_list_t* list, size_t value) { - CELIX_EI_IMPL(celix_arrayList_addSize); - return __real_celix_arrayList_addSize(list, value); +celix_status_t __real_celix_arrayList_addString(celix_array_list_t* list, const char* value); +CELIX_EI_DEFINE(celix_arrayList_addString, celix_status_t) +celix_status_t __wrap_celix_arrayList_addString(celix_array_list_t* list, const char* value) { + CELIX_EI_IMPL(celix_arrayList_addString); + return __real_celix_arrayList_addString(list, value); +} + +celix_status_t __real_celix_arrayList_assignString(celix_array_list_t* list, char* value); +CELIX_EI_DEFINE(celix_arrayList_assignString, celix_status_t) +celix_status_t __wrap_celix_arrayList_assignString(celix_array_list_t* list, char* value) { + celix_autofree char* tmp = value; //ensure that the value is freed when an error is injected + CELIX_EI_IMPL(celix_arrayList_assignString); + celix_steal_ptr(tmp); + return __real_celix_arrayList_assignString(list, value); } } diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index db39b9035..d04f9e30c 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -92,22 +92,36 @@ setup_target_for_coverage(test_utils SCAN_DIR ..) if (EI_TESTS) #Note testing celix err separated, otherwise celix err tss can already be initialized by another util function - add_executable(test_celix_err_with_ei + add_executable(test_utils_celix_err_with_ei src/ErrErrorInjectionTestSuite.cc ) - target_link_libraries(test_celix_err_with_ei PRIVATE + target_link_libraries(test_utils_celix_err_with_ei PRIVATE utils_cut Celix::malloc_ei Celix::threads_ei GTest::gtest GTest::gtest_main ) - add_test(NAME test_celix_err_with_ei COMMAND test_celix_err_with_ei) - setup_target_for_coverage(test_celix_err_with_ei SCAN_DIR ..) + add_test(NAME test_utils_celix_err_with_ei COMMAND test_utils_celix_err_with_ei) + setup_target_for_coverage(test_utils_celix_err_with_ei SCAN_DIR ..) + + + #Note testing array list seperated, otherwise array list calls are already wrapped + add_executable(test_utils_array_list_with_ei + src/ArrayListErrorInjectionTestSuite.cc + ) + target_link_libraries(test_utils_array_list_with_ei PRIVATE + utils_cut + Celix::malloc_ei + Celix::utils_ei + Celix::version_ei + GTest::gtest GTest::gtest_main + ) + add_test(NAME test_utils_array_list_with_ei COMMAND test_utils_array_list_with_ei) + setup_target_for_coverage(test_utils_array_list_with_ei SCAN_DIR ..) add_executable(test_utils_with_ei src/FileUtilsErrorInjectionTestSuite.cc src/ConvertUtilsErrorInjectionTestSuite.cc - src/ArrayListErrorInjectionTestSuite.cc src/PropertiesErrorInjectionTestSuite.cc src/VersionErrorInjectionTestSuite.cc src/HashMapErrorInjectionTestSuite.cc diff --git a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc index f808d3af8..0d6131a1f 100644 --- a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc @@ -46,7 +46,7 @@ TEST_F(ArrayListErrorInjectionTestSuite, CreateTest) { EXPECT_EQ(1, celix_err_getErrorCount()); //Given an error is injected for malloc (used for the element data) - celix_ei_expect_malloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); //Then creating an array list should fail EXPECT_EQ(nullptr, celix_arrayList_create()); //And an error is logged to the celix_err @@ -55,12 +55,13 @@ TEST_F(ArrayListErrorInjectionTestSuite, CreateTest) { TEST_F(ArrayListErrorInjectionTestSuite, AddFunctionsTest) { - //Given an array list with a capacity of 10 (whitebox knowledge) - auto* list = celix_arrayList_create(); + // Given an array list with a capacity of 10 (whitebox knowledge) and with an entry than needs to be freed when + // removed. + auto* list = celix_arrayList_createStringArray(); //When adding 10 elements, no error is expected for (int i = 0; i < 10; ++i) { - EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addInt(list, i)); + EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addString(list, "test")); } EXPECT_EQ(10, celix_arrayList_size(list)); @@ -68,7 +69,7 @@ TEST_F(ArrayListErrorInjectionTestSuite, AddFunctionsTest) { celix_ei_expect_realloc(CELIX_EI_UNKNOWN_CALLER, 1, nullptr); //Then adding an element should fail - EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addInt(list, 10)); + EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addString(list, "fail")); EXPECT_EQ(10, celix_arrayList_size(list)); //And an error is logged to the celix_err EXPECT_EQ(1, celix_err_getErrorCount()); diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 2787376c9..78e77b6f0 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -110,13 +110,6 @@ void testArrayListForTemplateType(const std::vector& entries, } TEST_F(ArrayListTestSuite, TestDifferentEntyTypesForArrayListTest) { - std::vector intEntries{1, 2, 3, 4, 5}; - testArrayListForTemplateType(intEntries, - celix_arrayList_createIntArray, - celix_arrayList_addInt, - celix_arrayList_getInt, - celix_arrayList_removeInt); - std::vector longEntries{1L, 2L, 3L, 4L, 5L}; testArrayListForTemplateType(longEntries, celix_arrayList_createLongArray, @@ -124,13 +117,6 @@ TEST_F(ArrayListTestSuite, TestDifferentEntyTypesForArrayListTest) { celix_arrayList_getLong, celix_arrayList_removeLong); - std::vector floatEntries{1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; - testArrayListForTemplateType(floatEntries, - celix_arrayList_createFloatArray, - celix_arrayList_addFloat, - celix_arrayList_getFloat, - celix_arrayList_removeFloat); - std::vector doubleEntries{1.0, 2.0, 3.0, 4.0, 5.0}; testArrayListForTemplateType(doubleEntries, celix_arrayList_createDoubleArray, @@ -151,27 +137,6 @@ TEST_F(ArrayListTestSuite, TestDifferentEntyTypesForArrayListTest) { celix_arrayList_add, celix_arrayList_get, celix_arrayList_remove); - - std::vector uintEntries{1, 2, 3, 4, 5}; - testArrayListForTemplateType(uintEntries, - celix_arrayList_createUIntArray, - celix_arrayList_addUInt, - celix_arrayList_getUInt, - celix_arrayList_removeUInt); - - std::vector ulongEntries{1, 2, 3, 4, 5}; - testArrayListForTemplateType(ulongEntries, - celix_arrayList_createULongArray, - celix_arrayList_addULong, - celix_arrayList_getULong, - celix_arrayList_removeULong); - - std::vector sizeEntries{1, 2, 3, 4, 5}; - testArrayListForTemplateType(sizeEntries, - celix_arrayList_createSizeArray, - celix_arrayList_addSize, - celix_arrayList_getSize, - celix_arrayList_removeSize); } TEST_F(ArrayListTestSuite, StringArrayList) { @@ -239,11 +204,6 @@ TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { celix_arrayList_addString(stringList, "2"); celix_arrayList_addString(stringList, "1"); - celix_autoptr(celix_array_list_t) intList = celix_arrayList_createIntArray(); - celix_arrayList_addInt(intList, 3); - celix_arrayList_addInt(intList, 1); - celix_arrayList_addInt(intList, 2); - celix_arrayList_addInt(intList, 1); celix_autoptr(celix_array_list_t) longList = celix_arrayList_createLongArray(); celix_arrayList_addLong(longList, 3L); @@ -251,24 +211,6 @@ TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { celix_arrayList_addLong(longList, 2L); celix_arrayList_addLong(longList, 1L); - celix_autoptr(celix_array_list_t) uintList = celix_arrayList_createUIntArray(); - celix_arrayList_addUInt(uintList, 3U); - celix_arrayList_addUInt(uintList, 1U); - celix_arrayList_addUInt(uintList, 2U); - celix_arrayList_addUInt(uintList, 1U); - - celix_autoptr(celix_array_list_t) ulongList = celix_arrayList_createULongArray(); - celix_arrayList_addULong(ulongList, 3UL); - celix_arrayList_addULong(ulongList, 1UL); - celix_arrayList_addULong(ulongList, 2UL); - celix_arrayList_addULong(ulongList, 1UL); - - celix_autoptr(celix_array_list_t) floatList = celix_arrayList_createFloatArray(); - celix_arrayList_addFloat(floatList, 3.0f); - celix_arrayList_addFloat(floatList, 1.0f); - celix_arrayList_addFloat(floatList, 2.0f); - celix_arrayList_addFloat(floatList, 1.0f); - celix_autoptr(celix_array_list_t) doubleList = celix_arrayList_createDoubleArray(); celix_arrayList_addDouble(doubleList, 3.0); celix_arrayList_addDouble(doubleList, 1.0); @@ -280,12 +222,6 @@ TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { celix_arrayList_addBool(boolList, true); celix_arrayList_addBool(boolList, false); - celix_autoptr(celix_array_list_t) sizeList = celix_arrayList_createSizeArray(); - celix_arrayList_addSize(sizeList, 3); - celix_arrayList_addSize(sizeList, 1); - celix_arrayList_addSize(sizeList, 2); - celix_arrayList_addSize(sizeList, 1); - celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); celix_arrayList_assignVersion(versionList, celix_version_create(2, 1, 0, "")); celix_arrayList_assignVersion(versionList, celix_version_create(3, 2, 1, "")); @@ -296,27 +232,17 @@ TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { // Then the element type is correctly set EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER, celix_arrayList_getElementType(ptrList)); EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, celix_arrayList_getElementType(stringList)); - EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_INT, celix_arrayList_getElementType(intList)); EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG, celix_arrayList_getElementType(longList)); - EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT, celix_arrayList_getElementType(uintList)); - EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG, celix_arrayList_getElementType(ulongList)); - EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT, celix_arrayList_getElementType(floatList)); EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE, celix_arrayList_getElementType(doubleList)); EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL, celix_arrayList_getElementType(boolList)); - EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE, celix_arrayList_getElementType(sizeList)); EXPECT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, celix_arrayList_getElementType(versionList)); // When sorting the lists celix_arrayList_sort(ptrList); celix_arrayList_sort(stringList); - celix_arrayList_sort(intList); celix_arrayList_sort(longList); - celix_arrayList_sort(uintList); - celix_arrayList_sort(ulongList); - celix_arrayList_sort(floatList); celix_arrayList_sort(doubleList); celix_arrayList_sort(boolList); - celix_arrayList_sort(sizeList); celix_arrayList_sort(versionList); // Then the lists are sorted @@ -330,31 +256,11 @@ TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { EXPECT_STREQ("2", celix_arrayList_getString(stringList, 2)); EXPECT_STREQ("3", celix_arrayList_getString(stringList, 3)); - EXPECT_EQ(1, celix_arrayList_getInt(intList, 0)); - EXPECT_EQ(1, celix_arrayList_getInt(intList, 1)); - EXPECT_EQ(2, celix_arrayList_getInt(intList, 2)); - EXPECT_EQ(3, celix_arrayList_getInt(intList, 3)); - EXPECT_EQ(1L, celix_arrayList_getLong(longList, 0)); EXPECT_EQ(1L, celix_arrayList_getLong(longList, 1)); EXPECT_EQ(2L, celix_arrayList_getLong(longList, 2)); EXPECT_EQ(3L, celix_arrayList_getLong(longList, 3)); - EXPECT_EQ(1U, celix_arrayList_getUInt(uintList, 0)); - EXPECT_EQ(1U, celix_arrayList_getUInt(uintList, 1)); - EXPECT_EQ(2U, celix_arrayList_getUInt(uintList, 2)); - EXPECT_EQ(3U, celix_arrayList_getUInt(uintList, 3)); - - EXPECT_EQ(1UL, celix_arrayList_getULong(ulongList, 0)); - EXPECT_EQ(1UL, celix_arrayList_getULong(ulongList, 1)); - EXPECT_EQ(2UL, celix_arrayList_getULong(ulongList, 2)); - EXPECT_EQ(3UL, celix_arrayList_getULong(ulongList, 3)); - - EXPECT_FLOAT_EQ(1.0f, celix_arrayList_getFloat(floatList, 0)); - EXPECT_FLOAT_EQ(1.0f, celix_arrayList_getFloat(floatList, 1)); - EXPECT_FLOAT_EQ(2.0f, celix_arrayList_getFloat(floatList, 2)); - EXPECT_FLOAT_EQ(3.0f, celix_arrayList_getFloat(floatList, 3)); - EXPECT_DOUBLE_EQ(1.0, celix_arrayList_getDouble(doubleList, 0)); EXPECT_DOUBLE_EQ(1.0, celix_arrayList_getDouble(doubleList, 1)); EXPECT_DOUBLE_EQ(2.0, celix_arrayList_getDouble(doubleList, 2)); @@ -364,11 +270,6 @@ TEST_F(ArrayListTestSuite, SortTypedArrayListsTest) { EXPECT_FALSE(celix_arrayList_getBool(boolList, 1)); EXPECT_TRUE(celix_arrayList_getBool(boolList, 2)); - EXPECT_EQ(1, celix_arrayList_getSize(sizeList, 0)); - EXPECT_EQ(1, celix_arrayList_getSize(sizeList, 1)); - EXPECT_EQ(2, celix_arrayList_getSize(sizeList, 2)); - EXPECT_EQ(3, celix_arrayList_getSize(sizeList, 3)); - EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 0), 1, 0)); EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 1), 1, 0)); EXPECT_EQ(0, celix_version_compareToMajorMinor(celix_arrayList_getVersion(versionList, 2), 2, 1)); @@ -455,15 +356,15 @@ TEST_F(ArrayListTestSuite, RemovedCallbacksForArrayListTest) { opts.removedCallbackData = &count; opts.removedCallback = [](void *data, celix_array_list_entry_t entry) { int* c = (int*)data; - if (entry.intVal == 1 || entry.intVal == 2 || entry.intVal == 3 || entry.intVal == 4) { + if (entry.longVal == 1 || entry.longVal == 2 || entry.longVal == 3 || entry.longVal == 4) { (*c)++; } }; auto* list = celix_arrayList_createWithOptions(&opts); - celix_arrayList_addInt(list, 1); - celix_arrayList_addInt(list, 2); - celix_arrayList_addInt(list, 3); - celix_arrayList_addInt(list, 4); + celix_arrayList_addLong(list, 1); + celix_arrayList_addLong(list, 2); + celix_arrayList_addLong(list, 3); + celix_arrayList_addLong(list, 4); EXPECT_EQ(celix_arrayList_size(list), 4); celix_arrayList_clear(list); //will call removed callback for every entry EXPECT_EQ(count, 4); @@ -475,24 +376,24 @@ TEST_F(ArrayListTestSuite, RemovedCallbacksForArrayListTest) { TEST_F(ArrayListTestSuite, SortForArrayListTest) { auto* list = celix_arrayList_create(); - celix_arrayList_addInt(list, 3); - celix_arrayList_addInt(list, 2); - celix_arrayList_addInt(list, 1); - celix_arrayList_addInt(list, 4); - EXPECT_EQ(celix_arrayList_getInt(list, 0), 3); - EXPECT_EQ(celix_arrayList_getInt(list, 1), 2); - EXPECT_EQ(celix_arrayList_getInt(list, 2), 1); - EXPECT_EQ(celix_arrayList_getInt(list, 3), 4); + celix_arrayList_addLong(list, 3); + celix_arrayList_addLong(list, 2); + celix_arrayList_addLong(list, 1); + celix_arrayList_addLong(list, 4); + EXPECT_EQ(celix_arrayList_getLong(list, 0), 3); + EXPECT_EQ(celix_arrayList_getLong(list, 1), 2); + EXPECT_EQ(celix_arrayList_getLong(list, 2), 1); + EXPECT_EQ(celix_arrayList_getLong(list, 3), 4); celix_array_list_compare_entries_fp sort = [](celix_array_list_entry_t a, celix_array_list_entry_t b) -> int { - return a.intVal - b.intVal; + return a.longVal - b.longVal; }; celix_arrayList_sortEntries(list, sort); - EXPECT_EQ(celix_arrayList_getInt(list, 0), 1); - EXPECT_EQ(celix_arrayList_getInt(list, 1), 2); - EXPECT_EQ(celix_arrayList_getInt(list, 2), 3); - EXPECT_EQ(celix_arrayList_getInt(list, 3), 4); + EXPECT_EQ(celix_arrayList_getLong(list, 0), 1); + EXPECT_EQ(celix_arrayList_getLong(list, 1), 2); + EXPECT_EQ(celix_arrayList_getLong(list, 2), 3); + EXPECT_EQ(celix_arrayList_getLong(list, 3), 4); celix_arrayList_destroy(list); } @@ -503,23 +404,17 @@ TEST_F(ArrayListTestSuite, ReturnStatusAddFunctionsTest) { EXPECT_EQ(0, celix_arrayList_size(list)); //no error, return status is CELIX_SUCCESS - EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addInt(list, 1)); - EXPECT_EQ(1, celix_arrayList_size(list)); - EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addLong(list, 2L)); - EXPECT_EQ(2, celix_arrayList_size(list)); - - EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addFloat(list, 3.0f)); - EXPECT_EQ(3, celix_arrayList_size(list)); + EXPECT_EQ(1, celix_arrayList_size(list)); EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addDouble(list, 4.0)); - EXPECT_EQ(4, celix_arrayList_size(list)); + EXPECT_EQ(2, celix_arrayList_size(list)); EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_addBool(list, true)); - EXPECT_EQ(5, celix_arrayList_size(list)); + EXPECT_EQ(3, celix_arrayList_size(list)); EXPECT_EQ(CELIX_SUCCESS, celix_arrayList_add(list, (void*)0x42)); - EXPECT_EQ(6, celix_arrayList_size(list)); + EXPECT_EQ(4, celix_arrayList_size(list)); celix_arrayList_destroy(list); } @@ -529,75 +424,11 @@ TEST_F(ArrayListTestSuite, AutoCleanupTest) { EXPECT_NE(nullptr, list); } -TEST_F(ArrayListTestSuite, AddNullTest) { - // Given an undefined type, string, string ref and version list - celix_autoptr(celix_array_list_t) list = celix_arrayList_create(); - celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); - celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray(); - celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); - - // When adding a null value to the lists - celix_arrayList_add(list, nullptr); - celix_arrayList_addString(stringList, nullptr); - celix_arrayList_addString(stringRefList, nullptr); - celix_arrayList_addVersion(versionList, nullptr); - - // Then the lists contain the null value - EXPECT_EQ(1, celix_arrayList_size(list)); - EXPECT_EQ(nullptr, celix_arrayList_get(list, 0)); - EXPECT_EQ(1, celix_arrayList_size(stringList)); - EXPECT_EQ(nullptr, celix_arrayList_getString(stringList, 0)); - EXPECT_EQ(1, celix_arrayList_size(stringRefList)); - EXPECT_EQ(nullptr, celix_arrayList_getString(stringRefList, 0)); - EXPECT_EQ(1, celix_arrayList_size(versionList)); - EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionList, 0)); - - // When copying the lists - celix_autoptr(celix_array_list_t) listCopy = celix_arrayList_copy(list); - celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList); - celix_autoptr(celix_array_list_t) stringRefListCopy = celix_arrayList_copy(stringRefList); - celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList); - - // Then the copied lists contain the null value - EXPECT_EQ(1, celix_arrayList_size(listCopy)); - EXPECT_EQ(nullptr, celix_arrayList_get(listCopy, 0)); - EXPECT_EQ(1, celix_arrayList_size(stringListCopy)); - EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0)); - EXPECT_EQ(1, celix_arrayList_size(stringRefListCopy)); - EXPECT_EQ(nullptr, celix_arrayList_getString(stringRefListCopy, 0)); - EXPECT_EQ(1, celix_arrayList_size(versionListCopy)); - EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionListCopy, 0)); -} - -TEST_F(ArrayListTestSuite, AssignNullTest) { - // Given a string and version list - celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); - celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); - - // When assigning a null value to the lists - celix_arrayList_assignString(stringList, nullptr); - celix_arrayList_assignVersion(versionList, nullptr); - - // Then the lists contain the null value - EXPECT_EQ(1, celix_arrayList_size(stringList)); - EXPECT_EQ(nullptr, celix_arrayList_getString(stringList, 0)); - EXPECT_EQ(1, celix_arrayList_size(versionList)); - EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionList, 0)); - - // When copying the lists - celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList); - celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList); - - // Then the copied lists contain the null value - EXPECT_EQ(1, celix_arrayList_size(stringListCopy)); - EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0)); -} - TEST_F(ArrayListTestSuite, ReallocTest) { // Given a list with more than 10 elements (whitebox knowledge that the initial capacity is 10) - celix_autoptr(celix_array_list_t) list = celix_arrayList_createIntArray(); + celix_autoptr(celix_array_list_t) list = celix_arrayList_createLongArray(); for (int i = 0; i < 20; ++i) { - celix_status_t status = celix_arrayList_addInt(list, i); + celix_status_t status = celix_arrayList_addLong(list, i); EXPECT_EQ(CELIX_SUCCESS, status); } // Then the size is 20 @@ -605,6 +436,6 @@ TEST_F(ArrayListTestSuite, ReallocTest) { // And the elements are as expected for (int i = 0; i < 20; ++i) { - EXPECT_EQ(i, celix_arrayList_getInt(list, i)); + EXPECT_EQ(i, celix_arrayList_getLong(list, i)); } } diff --git a/libs/utils/gtest/src/FilterErrorInjectionTestSuite.cc b/libs/utils/gtest/src/FilterErrorInjectionTestSuite.cc index 0714ef560..256bf64b3 100644 --- a/libs/utils/gtest/src/FilterErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/FilterErrorInjectionTestSuite.cc @@ -33,7 +33,10 @@ class FilterErrorInjectionTestSuite : public ::testing::Test { FilterErrorInjectionTestSuite() { celix_err_resetErrors(); celix_ei_expect_celix_arrayList_createWithOptions(nullptr, 0, nullptr); + celix_ei_expect_celix_arrayList_createStringArray(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_add(nullptr, 0, 0); + celix_ei_expect_celix_arrayList_addString(nullptr, 0, 0); + celix_ei_expect_celix_arrayList_assignString(nullptr, 0, 0); celix_ei_expect_calloc(nullptr, 0, nullptr); celix_ei_expect_open_memstream(nullptr, 0, nullptr); celix_ei_expect_fclose(nullptr, 0, 0); @@ -64,7 +67,7 @@ TEST_F(FilterErrorInjectionTestSuite, ErrorWithArrayListCreateTest) { EXPECT_EQ(nullptr, filter); //Given an error injection for celix_arrayList_create - celix_ei_expect_celix_arrayList_createWithOptions((void*)celix_filter_create, 4, nullptr); + celix_ei_expect_celix_arrayList_createStringArray((void*)celix_filter_create, 4, nullptr); //When creating a filter with a substring filterStr = "(key1=*val*)"; //Then the filter creation should fail, because it cannot create a children list for the substring filter node @@ -89,15 +92,29 @@ TEST_F(FilterErrorInjectionTestSuite, ErrorWithArrayListAddTest) { filter = celix_filter_create(filterStr); EXPECT_EQ(nullptr, filter); - for (int i = 0; i < 3; ++i) { - //Given an error injection for celix_arrayList_add - celix_ei_expect_celix_arrayList_add((void*)celix_filter_create, 4, CELIX_ENOMEM, i+1); - //When creating a filter with a substring - filterStr = "(key1=*val*)"; - //Then the filter creation should fail, because it cannot add a children to the substring filter node - filter = celix_filter_create(filterStr); - EXPECT_EQ(nullptr, filter); - } + //Given an error injection for celix_arrayList_addString for the initial "" string entry + celix_ei_expect_celix_arrayList_addString((void*)celix_filter_create, 4, CELIX_ENOMEM); + //When creating a filter with a substring + filterStr = "(key1=*val*)"; + //Then the filter creation should fail, because it cannot add a children to the substring filter node + filter = celix_filter_create(filterStr); + EXPECT_EQ(nullptr, filter); + + //Given an error injection for celix_arrayList_assignString for the sub "val" string entry + celix_ei_expect_celix_arrayList_assignString((void*)celix_filter_create, 4, CELIX_ENOMEM); + //When creating a filter with a substring + filterStr = "(key1=*val*)"; + //Then the filter creation should fail, because it cannot add a children to the substring filter node + filter = celix_filter_create(filterStr); + EXPECT_EQ(nullptr, filter); + + //Given an error injection for celix_arrayList_addString for the final "" string entry + celix_ei_expect_celix_arrayList_addString((void*)celix_filter_create, 4, CELIX_ENOMEM, 2); + //When creating a filter with a substring + filterStr = "(key1=*val*)"; + //Then the filter creation should fail, because it cannot add a children to the substring filter node + filter = celix_filter_create(filterStr); + EXPECT_EQ(nullptr, filter); } TEST_F(FilterErrorInjectionTestSuite, ErrorWithCallocTest) { diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index a35d87a69..a5de204e2 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -51,14 +51,9 @@ 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_STRING_REF = 3, /**< Represents a string element type where the array list is not the owner */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_INT = 4, /**< Represents an integer element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG = 5, /**< Represents a long integer element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT = 6, /**< Represents an unsigned integer element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG = 7, /**< Represents an unsigned long integer element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT = 8, /**< Represents a float element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE = 9, /**< Represents a double element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL = 10, /**< Represents a boolean element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE = 11, /**< Represents a size_t element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION = 12 /**< Represents a celix_version_t* element type. */ } celix_array_list_element_type_t; @@ -74,22 +69,12 @@ typedef union celix_array_list_entry { CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ const char* stringVal; /**< A string value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ - int intVal; /**< An integer value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_INT 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. */ - unsigned int uintVal; /**< An unsigned integer value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or - CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. */ - unsigned long ulongVal; /**< An unsigned long integer value when the element type is - CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG 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. */ - float floatVal; /**< A float value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT 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. */ - size_t sizeVal; /**< A size_t value when the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE 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; @@ -220,18 +205,6 @@ celix_array_list_t* celix_arrayList_createStringArray(); CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createStringRefArray(); -/** - * @brief Creates a new empty array list with an integer element type. - * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * integer comparison. - * - * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message - * is logged to celix_err. - */ -CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createIntArray(); - /** * @brief Creates a new empty array list with a long integer element type. * @@ -244,42 +217,6 @@ celix_array_list_t* celix_arrayList_createIntArray(); CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createLongArray(); -/** - * @brief Creates a new empty array list with an unsigned integer element type. - * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * unsigned integer comparison. - * - * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message - * is logged to celix_err. - */ -CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createUIntArray(); - -/** - * @brief Creates a new empty array list with an unsigned long integer element type. - * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * unsigned integer comparison. - * - * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message - * is logged to celix_err. - */ -CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createULongArray(); - -/** - * @brief Creates a new empty array list with a float element type. - * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * float comparison. - * - * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message - * is logged to celix_err. - */ -CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createFloatArray(); - /** * @brief Creates a new empty array list with a double element type. * @@ -304,18 +241,6 @@ celix_array_list_t* celix_arrayList_createDoubleArray(); CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createBoolArray(); -/** - * @brief Creates a new empty array list with a size_t element type. - * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * unsigned integer comparison. - * - * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message - * is logged to celix_err. - */ -CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createSizeArray(); - /** * @brief Creates a new empty array list with a celix_version_t* element type. * @@ -390,19 +315,6 @@ void* celix_arrayList_get(const celix_array_list_t *list, int index); CELIX_UTILS_EXPORT const char* celix_arrayList_getString(const celix_array_list_t *list, int index); -/** - * @brief Returns the value for the provided index. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param index The entry index to return. - * @return Returns the int value for the index. Returns 0 if index is out of bound. - */ -CELIX_UTILS_EXPORT -int celix_arrayList_getInt(const celix_array_list_t *list, int index); - /** * @brief Returns the value for the provided index. * @@ -416,45 +328,6 @@ int celix_arrayList_getInt(const celix_array_list_t *list, int index); CELIX_UTILS_EXPORT long int celix_arrayList_getLong(const celix_array_list_t *list, int index); -/** - * @brief Returns the value for the provided index. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param index The entry index to return. - * @return Returns the unsigned int value for the index. Returns 0 if index is out of bound. - */ -CELIX_UTILS_EXPORT -unsigned int celix_arrayList_getUInt(const celix_array_list_t *list, int index); - -/** - * @brief Returns the value for the provided index. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param index The entry index to return. - * @return Returns the unsigned long value for the index. Returns 0 if index is out of bound. - */ -CELIX_UTILS_EXPORT -unsigned long int celix_arrayList_getULong(const celix_array_list_t *list, int index); - -/** - * @brief Returns the value for the provided index. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param index The entry index to return. - * @return Returns the float value for the index. Returns 0 if index is out of bound. - */ -CELIX_UTILS_EXPORT -float celix_arrayList_getFloat(const celix_array_list_t *list, int index); - /** * @brief Returns the value for the provided index. * @@ -481,19 +354,6 @@ double celix_arrayList_getDouble(const celix_array_list_t *list, int index); CELIX_UTILS_EXPORT bool celix_arrayList_getBool(const celix_array_list_t *list, int index); -/** - * @brief Returns the value for the provided index. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param index The entry index to return. - * @return Returns the size_t value for the index. Returns 0 if index is out of bound. - */ -CELIX_UTILS_EXPORT -size_t celix_arrayList_getSize(const celix_array_list_t *list, int index); - /** * @brief Returns the value for the provided index. * @@ -514,7 +374,7 @@ const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t *list * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * * @param list The array list. - * @param value The pointer value to add to the array list. + * @param value The pointer value to add to the array list. Cannot be NULL. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT @@ -531,7 +391,7 @@ celix_status_t celix_arrayList_add(celix_array_list_t* list, void* value); * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, the string will be added as reference (as-is). * * @param list The array list. - * @param value The string value to add to the array list. + * @param value The string value to add to the array list. Cannot be NULL. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT @@ -545,25 +405,13 @@ celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* v * Can only be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING. * * @param list The array list. - * @param value The string value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. + * @param value The string value to add to the array list. Cannot be NULL. + * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. If an error is returned + * the provided value is not added to the array list, but the value will be freed using free. */ CELIX_UTILS_EXPORT celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* value); -/** - * @brief add pointer entry to the back of the array list. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param value The int value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. - */ -CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addInt(celix_array_list_t* list, int value); - /** * @brief add pointer entry to the back of the array list. * @@ -577,45 +425,6 @@ celix_status_t celix_arrayList_addInt(celix_array_list_t* list, int value); CELIX_UTILS_EXPORT celix_status_t celix_arrayList_addLong(celix_array_list_t* list, long value); -/** - * @brief add pointer entry to the back of the array list. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param value The unsigned int value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. - */ -CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addUInt(celix_array_list_t* list, unsigned int value); - -/** - * @brief add pointer entry to the back of the array list. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param value The unsigned long value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. - */ -CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addULong(celix_array_list_t* list, unsigned long value); - -/** - * @brief add pointer entry to the back of the array list. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param value The float value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. - */ -CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addFloat(celix_array_list_t* list, float value); - /** * @brief add pointer entry to the back of the array list. * @@ -642,19 +451,6 @@ celix_status_t celix_arrayList_addDouble(celix_array_list_t* list, double value) CELIX_UTILS_EXPORT celix_status_t celix_arrayList_addBool(celix_array_list_t* list, bool value); -/** - * @brief add pointer entry to the back of the array list. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * @param list The array list. - * @param value The size_t value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. - */ -CELIX_UTILS_EXPORT -celix_status_t celix_arrayList_addSize(celix_array_list_t* list, size_t value); - /** * @brief Add a version entry to the back of the version array list. * @@ -666,7 +462,7 @@ celix_status_t celix_arrayList_addSize(celix_array_list_t* list, size_t value); * the string will be added as reference (as-is). * * @param list The array list. - * @param value The version value to add to the array list. + * @param value The version value to add to the array list. Cannot be NULL. * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. */ CELIX_UTILS_EXPORT @@ -680,8 +476,9 @@ celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_ * * * @param list The array list. - * @param value The version value to add to the array list. - * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. + * @param value The version value to add to the array list. Cannot be NULL. + * @return CELIX_SUCCESS if the value is added, CELIX_ENOMEM if the array list is out of memory. If an error is + * returned, the provided value is not added to the array list, but the value will be freed using celix_version_destroy. */ CELIX_UTILS_EXPORT celix_status_t celix_arrayList_assignVersion(celix_array_list_t* list, celix_version_t* value); diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index 094a313cf..d70af3677 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -34,7 +34,6 @@ struct celix_array_list { celix_array_list_entry_t* elementData; size_t size; size_t capacity; - unsigned int modCount; celix_arrayList_equals_fp equalsCallback; celix_array_list_compare_entries_fp compareCallback; void (*simpleRemovedCallback)(void* value); @@ -47,12 +46,10 @@ static bool celix_arrayList_undefinedEquals(celix_array_list_entry_t a, celix_ar } static int celix_arrayList_comparePtrEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { - uintptr_t ptrA = (uintptr_t)a.voidPtrVal; - uintptr_t ptrB = (uintptr_t)b.voidPtrVal; - return (int)(ptrA - ptrB); + return a.voidPtrVal > b.voidPtrVal ? 1 : (a.voidPtrVal < b.voidPtrVal ? -1 : 0); } -static bool celix_arrayList_PtrEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { +static bool celix_arrayList_ptrEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { return celix_arrayList_comparePtrEntries(a, b) == 0; } @@ -64,14 +61,6 @@ static bool celix_arrayList_stringEquals(celix_array_list_entry_t a, celix_array return celix_utils_stringEquals(a.stringVal, b.stringVal); } -static int celix_arrayList_compareIntEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return a.intVal - b.intVal; -} - -static bool celix_arrayList_intEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return celix_arrayList_compareIntEntries(a, b) == 0; -} - static int celix_arrayList_compareLongEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { return a.longVal > b.longVal ? 1 : (a.longVal < b.longVal ? -1 : 0); } @@ -80,30 +69,6 @@ static bool celix_arrayList_longEquals(celix_array_list_entry_t a, celix_array_l return celix_arrayList_compareLongEntries(a, b) == 0; } -static int celix_arrayList_compareUIntEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return a.uintVal > b.uintVal ? 1 : (a.uintVal < b.uintVal ? -1 : 0); -} - -static bool celix_arrayList_uintEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return celix_arrayList_compareUIntEntries(a, b) == 0; -} - -static int celix_arrayList_compareULongEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return a.ulongVal > b.ulongVal ? 1 : (a.ulongVal < b.ulongVal ? -1 : 0); -} - -static bool celix_arrayList_ulongEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return celix_arrayList_compareULongEntries(a, b) == 0; -} - -static int celix_arrayList_compareFloatEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return a.floatVal > b.floatVal ? 1 : (a.floatVal < b.floatVal ? -1 : 0); -} - -static bool celix_arrayList_floatEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return celix_arrayList_compareFloatEntries(a, b) == 0; -} - static int celix_arrayList_compareDoubleEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { return a.doubleVal > b.doubleVal ? 1 : (a.doubleVal < b.doubleVal ? -1 : 0); } @@ -120,14 +85,6 @@ static bool celix_arrayList_boolEquals(celix_array_list_entry_t a, celix_array_l return celix_arrayList_compareBoolEntries(a, b) == 0; } -static int celix_arrayList_compareSizeEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return a.sizeVal > b.sizeVal ? 1 : (a.sizeVal < b.sizeVal ? -1 : 0); -} - -static bool celix_arrayList_sizeEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { - return celix_arrayList_compareSizeEntries(a, b) == 0; -} - static int celix_arrayList_compareVersionEntries(celix_array_list_entry_t a, celix_array_list_entry_t b) { return celix_version_compareTo(a.versionVal, b.versionVal); } @@ -159,7 +116,6 @@ static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int in static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, int capacity) { celix_array_list_entry_t *newList; - list->modCount++; size_t oldCapacity = list->capacity; if (capacity > oldCapacity) { size_t newCapacity = (oldCapacity * 3) / 2 + 1; @@ -177,7 +133,7 @@ static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, i static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { switch (list->elementType) { case CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER: - list->equalsCallback = celix_arrayList_PtrEquals; + list->equalsCallback = celix_arrayList_ptrEquals; list->compareCallback = celix_arrayList_comparePtrEntries; break; case CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING: @@ -189,26 +145,10 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { list->equalsCallback = celix_arrayList_stringEquals; list->compareCallback = celix_arrayList_compareStringEntries; break; - case CELIX_ARRAY_LIST_ELEMENT_TYPE_INT: - list->equalsCallback = celix_arrayList_intEquals; - list->compareCallback = celix_arrayList_compareIntEntries; - break; case CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG: list->equalsCallback = celix_arrayList_longEquals; list->compareCallback = celix_arrayList_compareLongEntries; break; - case CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT: - list->equalsCallback = celix_arrayList_uintEquals; - list->compareCallback = celix_arrayList_compareUIntEntries; - break; - case CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG: - list->equalsCallback = celix_arrayList_ulongEquals; - list->compareCallback = celix_arrayList_compareULongEntries; - break; - case CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT: - list->equalsCallback = celix_arrayList_floatEquals; - list->compareCallback = celix_arrayList_compareFloatEntries; - break; case CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE: list->equalsCallback = celix_arrayList_doubleEquals; list->compareCallback = celix_arrayList_compareDoubleEntries; @@ -217,10 +157,6 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { list->equalsCallback = celix_arrayList_boolEquals; list->compareCallback = celix_arrayList_compareBoolEntries; break; - case CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE: - list->equalsCallback = celix_arrayList_sizeEquals; - list->compareCallback = celix_arrayList_compareSizeEntries; - break; case CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION: list->simpleRemovedCallback = celix_arrayList_destroyVersion; list->equalsCallback = celix_arrayList_versionEquals; @@ -241,7 +177,7 @@ celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_cre } list->capacity = 10; - list->elementData = malloc(sizeof(celix_array_list_entry_t) * list->capacity); + list->elementData = calloc(list->capacity, sizeof(celix_array_list_entry_t)); if (!list->elementData) { celix_err_push("Failed to allocate memory for elementData"); return NULL; @@ -289,26 +225,10 @@ celix_array_list_t* celix_arrayList_createStringRefArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF); } -celix_array_list_t* celix_arrayList_createIntArray() { - return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_INT); -} - celix_array_list_t* celix_arrayList_createLongArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG); } -celix_array_list_t* celix_arrayList_createUIntArray() { - return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT); -} - -celix_array_list_t* celix_arrayList_createULongArray() { - return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG); -} - -celix_array_list_t* celix_arrayList_createFloatArray() { - return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT); -} - celix_array_list_t* celix_arrayList_createDoubleArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE); } @@ -317,10 +237,6 @@ celix_array_list_t* celix_arrayList_createBoolArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL); } -celix_array_list_t* celix_arrayList_createSizeArray() { - return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE); -} - celix_array_list_t* celix_arrayList_createVersionArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); } @@ -363,36 +279,12 @@ const char* celix_arrayList_getString(const celix_array_list_t* list, int index) return arrayList_getEntry(list, index).stringVal; } -int celix_arrayList_getInt(const celix_array_list_t* list, int index) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_INT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - return arrayList_getEntry(list, index).intVal; -} - long int celix_arrayList_getLong(const celix_array_list_t* list, int index) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).longVal; } -unsigned int celix_arrayList_getUInt(const celix_array_list_t* list, int index) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - return arrayList_getEntry(list, index).uintVal; -} - -unsigned long int celix_arrayList_getULong(const celix_array_list_t* list, int index) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - return arrayList_getEntry(list, index).ulongVal; -} - -float celix_arrayList_getFloat(const celix_array_list_t* list, int index) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - return arrayList_getEntry(list, index).floatVal; -} - double celix_arrayList_getDouble(const celix_array_list_t* list, int index) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -405,12 +297,6 @@ bool celix_arrayList_getBool(const celix_array_list_t* list, int index) { return arrayList_getEntry(list, index).boolVal; } -size_t celix_arrayList_getSize(const celix_array_list_t* list, int index) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - return arrayList_getEntry(list, index).sizeVal; -} - const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t* list, int index) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); return arrayList_getEntry(list, index).versionVal; @@ -420,11 +306,18 @@ static celix_status_t celix_arrayList_addEntry(celix_array_list_t* list, celix_a celix_status_t status = celix_arrayList_ensureCapacity(list, (int)list->size + 1); if (status == CELIX_SUCCESS) { list->elementData[list->size++] = entry; + } else { + if (list->simpleRemovedCallback) { + list->simpleRemovedCallback(entry.voidPtrVal); + } else if (list->removedCallback) { + list->removedCallback(list->removedCallbackData, entry); + } } return status; } celix_status_t celix_arrayList_add(celix_array_list_t* list, void* element) { + assert(element); assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; @@ -434,12 +327,13 @@ celix_status_t celix_arrayList_add(celix_array_list_t* list, void* element) { } celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* val) { + assert(val); assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); - if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING && val) { + if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { entry.stringVal = celix_utils_strdup(val); if (entry.stringVal == NULL) { return CELIX_ENOMEM; @@ -451,6 +345,7 @@ celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* v } celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* value) { + assert(value); assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); @@ -458,15 +353,6 @@ celix_status_t celix_arrayList_assignString(celix_array_list_t* list, char* valu return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addInt(celix_array_list_t* list, int val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_INT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.intVal = val; - return celix_arrayList_addEntry(list, entry); -} - celix_status_t celix_arrayList_addLong(celix_array_list_t* list, long val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -476,24 +362,6 @@ celix_status_t celix_arrayList_addLong(celix_array_list_t* list, long val) { return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addUInt(celix_array_list_t* list, unsigned int val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.uintVal = val; - return celix_arrayList_addEntry(list, entry); -} - -celix_status_t celix_arrayList_addULong(celix_array_list_t* list, unsigned long val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.ulongVal = val; - return celix_arrayList_addEntry(list, entry); -} - celix_status_t celix_arrayList_addDouble(celix_array_list_t* list, double val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -503,15 +371,6 @@ celix_status_t celix_arrayList_addDouble(celix_array_list_t* list, double val) { return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addFloat(celix_array_list_t* list, float val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.floatVal = val; - return celix_arrayList_addEntry(list, entry); -} - celix_status_t celix_arrayList_addBool(celix_array_list_t* list, bool val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -521,21 +380,13 @@ celix_status_t celix_arrayList_addBool(celix_array_list_t* list, bool val) { return celix_arrayList_addEntry(list, entry); } -celix_status_t celix_arrayList_addSize(celix_array_list_t* list, size_t val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.sizeVal = val; - return celix_arrayList_addEntry(list, entry); -} - celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_version_t* value) { + assert(value); assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); - if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION && value) { + if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { entry.versionVal = celix_version_copy(value); if (entry.versionVal == NULL) { return CELIX_ENOMEM; @@ -547,6 +398,7 @@ celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_ } celix_status_t celix_arrayList_assignVersion(celix_array_list_t* list, celix_version_t* value) { + assert(value); assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); @@ -570,7 +422,6 @@ int celix_arrayList_indexOf(celix_array_list_t *list, celix_array_list_entry_t e void celix_arrayList_removeAt(celix_array_list_t *list, int index) { if (index >= 0 && index < list->size) { celix_arrayList_callRemovedCallback(list, index); - list->modCount++; size_t numMoved = list->size - index - 1; 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)); @@ -601,15 +452,6 @@ void celix_arrayList_removeString(celix_array_list_t* list, const char* val) { celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeInt(celix_array_list_t* list, int val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_INT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.intVal = val; - celix_arrayList_removeEntry(list, entry); -} - void celix_arrayList_removeLong(celix_array_list_t* list, long val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -619,33 +461,6 @@ void celix_arrayList_removeLong(celix_array_list_t* list, long val) { celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeUInt(celix_array_list_t* list, unsigned int val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.uintVal = val; - celix_arrayList_removeEntry(list, entry); -} - -void celix_arrayList_removeULong(celix_array_list_t* list, unsigned long val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.ulongVal = val; - celix_arrayList_removeEntry(list, entry); -} - -void celix_arrayList_removeFloat(celix_array_list_t* list, float val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.floatVal = val; - celix_arrayList_removeEntry(list, entry); -} - void celix_arrayList_removeDouble(celix_array_list_t* list, double val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -664,15 +479,6 @@ void celix_arrayList_removeBool(celix_array_list_t* list, bool val) { celix_arrayList_removeEntry(list, entry); } -void celix_arrayList_removeSize(celix_array_list_t* list, size_t val) { - assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); - celix_array_list_entry_t entry; - memset(&entry, 0, sizeof(entry)); - entry.sizeVal = val; - celix_arrayList_removeEntry(list, entry); -} - void celix_arrayList_removeVersion(celix_array_list_t* list, const celix_version_t* val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -683,7 +489,6 @@ void celix_arrayList_removeVersion(celix_array_list_t* list, const celix_version } void celix_arrayList_clear(celix_array_list_t *list) { - list->modCount++; for (int i = 0; i < list->size; ++i) { celix_arrayList_callRemovedCallback(list, i); memset(&list->elementData[i], 0, sizeof(celix_array_list_entry_t)); diff --git a/libs/utils/src/filter.c b/libs/utils/src/filter.c index 733361476..4831ba4ec 100644 --- a/libs/utils/src/filter.c +++ b/libs/utils/src/filter.c @@ -455,9 +455,7 @@ static celix_status_t celix_filter_parseSubstringAny(const char* filterString, i * - (foo=bar*bar*) -> [bar, bar, NULL] */ static celix_array_list_t* celix_filter_parseSubstring(const char* filterString, int* pos) { - celix_array_list_create_options_t ops = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; - ops.simpleRemovedCallback = free; - celix_autoptr(celix_array_list_t) subs = celix_arrayList_createWithOptions(&ops); + celix_autoptr(celix_array_list_t) subs = celix_arrayList_createStringArray(); if (!subs) { celix_err_push("Filter Error: Failed to allocate memory."); return NULL; @@ -467,7 +465,7 @@ static celix_array_list_t* celix_filter_parseSubstring(const char* filterString, // initial substring is NULL // eat '*' (*pos)++; - if (celix_arrayList_add(subs, NULL) != CELIX_SUCCESS) { + if (celix_arrayList_addString(subs, "") != CELIX_SUCCESS) { celix_err_push("Filter Error: Failed to add element to array list."); return NULL; } @@ -481,8 +479,7 @@ static celix_array_list_t* celix_filter_parseSubstring(const char* filterString, return NULL; } if (element) { - if (celix_arrayList_add(subs, element) != CELIX_SUCCESS) { - free(element); + if (celix_arrayList_assignString(subs, element) != CELIX_SUCCESS) { celix_err_push("Filter Error: Failed to add element to array list."); return NULL; } @@ -491,7 +488,7 @@ static celix_array_list_t* celix_filter_parseSubstring(const char* filterString, // final substring is NULL (*pos)++; // eat '*' if (celix_filter_isNextNonWhiteSpaceChar(filterString, *pos, ')')) { - if (celix_arrayList_add(subs, NULL) != CELIX_SUCCESS) { + if (celix_arrayList_addString(subs, "") != CELIX_SUCCESS) { celix_err_push("Filter Error: Failed to add element to array list."); return NULL; } @@ -649,12 +646,12 @@ static bool celix_filter_matchSubString(const celix_filter_t* filter, const celi assert(filter->children && celix_arrayList_size(filter->children) >= 2); size_t strLen = celix_utils_strlen(entry->value); - const char* initial = celix_arrayList_get(filter->children, 0); - const char* final = celix_arrayList_get(filter->children, celix_arrayList_size(filter->children) - 1); + const char* initial = celix_arrayList_getString(filter->children, 0); + const char* final = celix_arrayList_getString(filter->children, celix_arrayList_size(filter->children) - 1); const char* currentValue = entry->value; - if (initial) { + if (!celix_utils_stringEquals(initial, "")) { const char* found = strstr(entry->value, initial); currentValue = found + celix_utils_strlen(initial); if (!found || found != entry->value) { @@ -663,7 +660,7 @@ static bool celix_filter_matchSubString(const celix_filter_t* filter, const celi } for (int i = 1; i < celix_arrayList_size(filter->children) - 1; i++) { - const char* substr = celix_arrayList_get(filter->children, i); + const char* substr = celix_arrayList_getString(filter->children, i); const char* found = strstr(currentValue, substr); if (!found) { return false; @@ -671,7 +668,7 @@ static bool celix_filter_matchSubString(const celix_filter_t* filter, const celi currentValue = found + celix_utils_strlen(substr); } - if (final) { + if (!celix_utils_stringEquals(final, "")) { const char* found = strstr(currentValue, final); if (!found || found + celix_utils_strlen(final) != entry->value + strLen) { return false; @@ -855,8 +852,8 @@ bool celix_filter_equals(const celix_filter_t* filter1, const celix_filter_t* fi if (sizeSrc == sizeDest) { int i; for (i = 0; i < celix_arrayList_size(filter1->children); i++) { - const char* srcPart = celix_arrayList_get(filter1->children, i); - const char* destPart = celix_arrayList_get(filter2->children, i); + const char* srcPart = celix_arrayList_getString(filter1->children, i); + const char* destPart = celix_arrayList_getString(filter2->children, i); if (!celix_utils_stringEquals(srcPart, destPart)) { break; } From a8937f1a3e964ba23df454c9ad6f38997f9c2e97 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 25 Feb 2024 14:00:46 +0100 Subject: [PATCH 10/11] gh-674: Add copy callback support for array list Also remove STRING_REF element type. --- .../src/ArrayListErrorInjectionTestSuite.cc | 20 +- libs/utils/gtest/src/ArrayListTestSuite.cc | 54 ++-- libs/utils/include/celix_array_list.h | 268 +++++++----------- libs/utils/src/array_list.c | 83 ++++-- 4 files changed, 205 insertions(+), 220 deletions(-) diff --git a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc index 0d6131a1f..177adba9d 100644 --- a/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc @@ -95,21 +95,31 @@ TEST_F(ArrayListErrorInjectionTestSuite, AddStringAndAddVersionFailureTest) { } TEST_F(ArrayListErrorInjectionTestSuite, CopyArrayListFailureTest) { - // Given a string array list with 10 elements (whitebox knowledge) + // Given a string array list with 11 elements (more than max initial capacity, whitebox knowledge) celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray(); - celix_arrayList_addString(stringList, "test1"); + for (int i = 0; i < 11; ++i) { + std::string str = "test" + std::to_string(i); + celix_arrayList_addString(stringList, str.c_str()); + } - // When an error is injected for calloc + // When an error is injected for calloc (create array list) celix_ei_expect_calloc((void*)celix_arrayList_copy, 1, nullptr); // Then copying an array list should fail EXPECT_EQ(nullptr, celix_arrayList_copy(stringList)); // And a celix_err is expected EXPECT_EQ(1, celix_err_getErrorCount()); - // When an error is injected for celix_utils_strdup - celix_ei_expect_celix_utils_strdup((void*)celix_arrayList_addString, 0, nullptr); + // And an error is injected for realloc (ensureCapacity) + celix_ei_expect_realloc((void*)celix_arrayList_copy, 1, nullptr); // Then copying an array list should fail EXPECT_EQ(nullptr, celix_arrayList_copy(stringList)); // And a celix_err is expected EXPECT_EQ(2, celix_err_getErrorCount()); + + // When an error is injected for celix_utils_strdup (used in string array list copy callback (whitebox knowledge)) + celix_ei_expect_celix_utils_strdup((void*)celix_arrayList_copy, 1, nullptr); + // Then copying an array list should fail + EXPECT_EQ(nullptr, celix_arrayList_copy(stringList)); + // And a celix_err is expected + EXPECT_EQ(3, celix_err_getErrorCount()); } diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 78e77b6f0..24c864a22 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -20,7 +20,9 @@ #include #include "celix_array_list.h" +#include "celix_version.h" #include "celix_utils.h" +#include "celix_filter.h" class ArrayListTestSuite : public ::testing::Test { public: @@ -154,19 +156,6 @@ TEST_F(ArrayListTestSuite, StringArrayList) { celix_arrayList_removeString(stringList, "2"); EXPECT_EQ(2, celix_arrayList_size(stringList)); - - celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray(); - celix_arrayList_addString(stringRefList, str1); - celix_arrayList_addString(stringRefList, "2"); - celix_arrayList_addString(stringRefList, "3"); - - EXPECT_EQ(3, celix_arrayList_size(stringRefList)); - EXPECT_STREQ("1", celix_arrayList_getString(stringRefList, 0)); - EXPECT_EQ((void*)str1, (void*)celix_arrayList_getString(stringRefList, 0)); //string is added as reference - EXPECT_STREQ("2", celix_arrayList_getString(stringRefList, 1)); - - celix_arrayList_removeString(stringRefList, "2"); - EXPECT_EQ(2, celix_arrayList_size(stringRefList)); } TEST_F(ArrayListTestSuite, VersionArrayList) { @@ -315,27 +304,50 @@ TEST_F(ArrayListTestSuite, CopyArrayTest) { celix_arrayList_addString(stringList, "2"); celix_arrayList_addString(stringList, "3"); - celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray(); - celix_arrayList_addString(stringRefList, "1"); - celix_arrayList_addString(stringRefList, "2"); - celix_arrayList_addString(stringRefList, "3"); - celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray(); celix_arrayList_assignVersion(versionList, celix_version_create(1, 0, 0, "")); celix_arrayList_assignVersion(versionList, celix_version_create(2, 0, 0, "")); celix_arrayList_assignVersion(versionList, celix_version_create(3, 0, 0, "")); + // And a custom pointer list configured for handling celix_filter_t + celix_array_list_create_options_t opts{}; + opts.elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER; + opts.simpleRemovedCallback = [](void* d) { celix_filter_destroy((celix_filter_t*)d); }; + opts.copyCallback = [](celix_array_list_entry_t src, celix_array_list_entry_t* dst) -> celix_status_t { + auto* filter = (celix_filter_t*)src.voidPtrVal; + dst->voidPtrVal = celix_filter_create(celix_filter_getFilterString(filter)); + return (dst->voidPtrVal) ? CELIX_SUCCESS : CELIX_ENOMEM; + }; + opts.equalsCallback = [](celix_array_list_entry_t a, celix_array_list_entry_t b) -> bool { + auto* fa = (celix_filter_t*)a.voidPtrVal; + auto* fb = (celix_filter_t*)b.voidPtrVal; + return celix_utils_stringEquals(celix_filter_getFilterString(fa), celix_filter_getFilterString(fb)); + }; + celix_autoptr(celix_array_list_t) ptrList = celix_arrayList_createWithOptions(&opts); + celix_filter_t* f1 = celix_filter_create("(a=1)"); + celix_filter_t* f2 = celix_filter_create("(a=2)"); + celix_filter_t* f3 = celix_filter_create("(a=3)"); + celix_arrayList_add(ptrList, f1); + celix_arrayList_add(ptrList, f2); + celix_arrayList_add(ptrList, f3); + // When copying the lists celix_autoptr(celix_array_list_t) longListCopy = celix_arrayList_copy(longList); celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList); - celix_autoptr(celix_array_list_t) stringRefListCopy = celix_arrayList_copy(stringRefList); celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList); + celix_autoptr(celix_array_list_t) ptrListCopy = celix_arrayList_copy(ptrList); + + // Then the size of the copied array list is 3 + EXPECT_EQ(3, celix_arrayList_size(longListCopy)); + EXPECT_EQ(3, celix_arrayList_size(stringListCopy)); + EXPECT_EQ(3, celix_arrayList_size(versionListCopy)); + EXPECT_EQ(3, celix_arrayList_size(ptrListCopy)); - // Then the copied lists are equal to the original lists + // And the copied lists are equal to the original lists EXPECT_TRUE(celix_arrayList_equals(longList, longListCopy)); EXPECT_TRUE(celix_arrayList_equals(stringList, stringListCopy)); - EXPECT_TRUE(celix_arrayList_equals(stringRefList, stringRefListCopy)); EXPECT_TRUE(celix_arrayList_equals(versionList, versionListCopy)); + EXPECT_TRUE(celix_arrayList_equals(ptrList, ptrListCopy)); } TEST_F(ArrayListTestSuite, SimpleRemovedCallbacksForArrayListTest) { diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index a5de204e2..b53c70e7e 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -19,10 +19,10 @@ #include +#include "celix_utils_export.h" #include "celix_cleanup.h" #include "celix_errno.h" -#include "celix_utils_export.h" -#include "celix_version.h" +#include "celix_version_type.h" #ifndef CELIX_ARRAY_LIST_H_ #define CELIX_ARRAY_LIST_H_ @@ -49,12 +49,10 @@ typedef enum celix_array_list_element_type { CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED = 0, /**< Represents an undefined element type. */ CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER = 1, /**< Represents a pointer 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_STRING_REF = - 3, /**< Represents a string element type where the array list is not the owner */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG = 5, /**< Represents a long integer element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE = 9, /**< Represents a double element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL = 10, /**< Represents a boolean element type. */ - CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION = 12 /**< Represents a celix_version_t* element type. */ + 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_VERSION = 6, /**< Represents a celix_version_t* element type. */ } celix_array_list_element_type_t; /** @@ -95,70 +93,14 @@ typedef bool (*celix_arrayList_equals_fp)(celix_array_list_entry_t, celix_array_ typedef int (*celix_array_list_compare_entries_fp)(celix_array_list_entry_t a, celix_array_list_entry_t b); /** - * Additional create options when creating a array list. - */ -typedef struct celix_array_list_create_options { - /** - * The element type of the array list. Default is CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - */ - celix_array_list_element_type_t elementType CELIX_OPTS_INIT; - - /** - * A simple removed callback, which if provided will be called if a entry is removed - * from the array list. The removed entry is provided as pointer. - * - * @note Assumes that the array list entries are pointer values. - * - * @note only simpleRemovedCallback or removedCallback should be configured, if both are configured, - * only the simpledRemoveCallback will be used. - * - * Default is NULL. - */ - void (*simpleRemovedCallback)(void* value) CELIX_OPTS_INIT; - - /** - * Optional callback data, which will be provided to the removedCallback callback. - * - * Default is NULL. - */ - void* removedCallbackData CELIX_OPTS_INIT; - - /** - * A removed callback, which if provided will be called if a entry is removed from the array list. - * The callback data pointer will be provided as first argument to the removed callback. - * - * @note only simpleRemovedCallback or removedCallback should be configured, if both are configured, - * only the simpledRemoveCallback will be used. - * - * Default is NULL. - */ - void (*removedCallback)(void* data, celix_array_list_entry_t entry) CELIX_OPTS_INIT; - - /** - * Equals callback used when trying to find a array list entry. - */ - celix_arrayList_equals_fp equalsCallback CELIX_OPTS_INIT; - - /** - * Compare callback used when sorting the array list. - */ - celix_array_list_compare_entries_fp compareCallback CELIX_OPTS_INIT; - -} celix_array_list_create_options_t; - -#ifndef __cplusplus -/** - * @brief C Macro to create a empty celix_array_list_create_options_t type. + * @brief Copy function for array list entries, which can be used to copy a array list entry. + * @return CELIX_SUCCESS if the entry is copied, CELIX_ENOMEM if the entry could not be copied. */ -#define CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS \ - { \ - .elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, .simpleRemovedCallback = NULL, \ - .removedCallbackData = NULL, .removedCallback = NULL, .equalsCallback = NULL, .compareCallback = NULL \ - } -#endif +typedef celix_status_t (*celix_array_list_copy_entry_fp)(celix_array_list_entry_t src, celix_array_list_entry_t* dst); /** * @brief Creates a new empty array list with an undefined element type. + * @deprecated Use celix_arrayList_createWithOptions or celix_arrayList_createArray instead. * * The remove, equals and compare callback will be NULL. * @@ -172,7 +114,7 @@ celix_array_list_t* celix_arrayList_create(); * @brief Creates a new empty array list with a pointer element type where the array list is not the owner of the * pointers. * - * The remove, equals and compare callback will be NULL. + * The remove, equals, compare and copy callback will be NULL. * * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message * is logged to celix_err. @@ -183,8 +125,8 @@ celix_array_list_t* celix_arrayList_createPointerArray(); /** * @brief Creates a new empty array list with a string element type where the array list is the owner of the strings. * - * The remove callback will be configured to free the string, and equals and compare callback will be configured for - * string comparison. + * The remove callback will be configured to free the string, the equals and compare callback will be configured for + * string comparison and the copy callback will be a callback to uses celix_utils_strdup. * * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message * is logged to celix_err. @@ -192,24 +134,11 @@ celix_array_list_t* celix_arrayList_createPointerArray(); CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createStringArray(); -/** - * @brief Creates a new empty array list with a string element type where the array list is **not** the owner of the - * strings. - * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * string comparison. - * - * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message - * is logged to celix_err. - */ -CELIX_UTILS_EXPORT -celix_array_list_t* celix_arrayList_createStringRefArray(); - /** * @brief Creates a new empty array list with a long integer element type. * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * integer comparison. + * The remove callback will be configured to NULL, the equals and compare callback will be configured for + * integer comparison and the copy callback will be configured to NULL. * * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message * is logged to celix_err. @@ -220,8 +149,8 @@ celix_array_list_t* celix_arrayList_createLongArray(); /** * @brief Creates a new empty array list with a double element type. * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * double comparison. + * The remove callback will be configured to NULL, the equals and compare callback will be configured for + * double comparison and the copy callback will be configured to NULL. * * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message * is logged to celix_err. @@ -232,8 +161,8 @@ celix_array_list_t* celix_arrayList_createDoubleArray(); /** * @brief Creates a new empty array list with a boolean element type. * - * The remove callback will be configured to NULL, and equals and compare callback will be configured for - * boolean comparison. + * The remove callback will be configured to NULL, the equals and compare callback will be configured for + * boolean comparison and the copy callback will be configured to NULL. * * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message * is logged to celix_err. @@ -244,8 +173,8 @@ celix_array_list_t* celix_arrayList_createBoolArray(); /** * @brief Creates a new empty array list with a celix_version_t* element type. * - * The remove callback will be configured to free a celix version, and equals and compare callback will be configured - * for celix version comparison. + * The remove callback will be configured to free a celix version, the equals and compare callback will be configured + * for celix version comparison and the copy callback will a callback that uses celix_version_copy. * * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message * is logged to celix_err. @@ -253,12 +182,84 @@ celix_array_list_t* celix_arrayList_createBoolArray(); CELIX_UTILS_EXPORT celix_array_list_t* celix_arrayList_createVersionArray(); +/** + * Additional create options when creating a array list. + */ +typedef struct celix_array_list_create_options { + /** + * The element type of the array list. Default is CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + */ + celix_array_list_element_type_t elementType CELIX_OPTS_INIT; + + /** + * A simple removed callback, which if provided will be called if a entry is removed + * from the array list. The removed entry is provided as pointer. + * + * @note Assumes that the array list entries are pointer values. + * + * @note only simpleRemovedCallback or removedCallback should be configured, if both are configured, + * only the simpledRemoveCallback will be used. + * + * Default is NULL. + */ + void (*simpleRemovedCallback)(void* value) CELIX_OPTS_INIT; + + /** + * Optional callback data, which will be provided to the removedCallback callback. + * + * Default is NULL. + */ + void* removedCallbackData CELIX_OPTS_INIT; + + /** + * A removed callback, which if provided will be called if a entry is removed from the array list. + * The callback data pointer will be provided as first argument to the removed callback. + * + * @note only simpleRemovedCallback or removedCallback should be configured, if both are configured, + * only the simpledRemoveCallback will be used. + * + * Default is NULL. + */ + void (*removedCallback)(void* data, celix_array_list_entry_t entry) CELIX_OPTS_INIT; + + /** + * Equals callback used when trying to find a array list entry. + */ + celix_arrayList_equals_fp equalsCallback CELIX_OPTS_INIT; + + /** + * Compare callback used when sorting the array list. + */ + celix_array_list_compare_entries_fp compareCallback CELIX_OPTS_INIT; + + /** + * The copy callback used to copy a array list entry. + * If callback is NULL, a celix_arrayList_copy will result in a shallow copy. + */ + celix_array_list_copy_entry_fp copyCallback CELIX_OPTS_INIT; + +} celix_array_list_create_options_t; + +#ifndef __cplusplus +/** + * @brief C Macro to create a empty celix_array_list_create_options_t type. + */ +#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, \ + } +#endif + /** * @brief Creates a new empty array list using using the provided array list create options. * - * If the element type is set to something other than CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, the remove, equals, - * and compare callbacks will be set according to the corresponding celix_arrayList_create*Array function. - * The provided callbacks in the options will override the default callbacks. + * The callbacks in the options will override the default callbacks based on the provided element type. + * The default callbacks (e.g. the remove, equals, compare and copy callback) correspond to the + * celix_arrayList_createArray function. + * For example if the elementType is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, the default callbacks will be set to + * handle string values. * * @param opts The create options, only used during the creation of the array list. * @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message @@ -305,8 +306,8 @@ void* celix_arrayList_get(const celix_array_list_t *list, int index); /** * @brief Returns the value for the provided index. * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, - * CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING + * or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * * @param list The array list. * @param index The entry index to return. @@ -383,12 +384,12 @@ celix_status_t celix_arrayList_add(celix_array_list_t* list, void* value); /** * @brief Add a string entry to the back of the array list. * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, - * CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. + * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING + * or CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. * * If the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, the string will be copied, but - * if the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, the string will be added as reference (as-is). + * if the array list element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED, + * the string will be added as reference (as-is). * * @param list The array list. * @param value The string value to add to the array list. Cannot be NULL. @@ -550,18 +551,6 @@ void celix_arrayList_remove(celix_array_list_t* list, void* value); CELIX_UTILS_EXPORT void celix_arrayList_removeString(celix_array_list_t* list, const char* value); -/** - * @brief Remove the first int entry from array list which matches the provided value. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_INT and - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * The equals callback provided when the array list was created will be used to find the entry. - * If there was no equals callback provided a direct memory compare will be done. - */ -CELIX_UTILS_EXPORT -void celix_arrayList_removeInt(celix_array_list_t* list, int value); - /** * @brief Remove the first long entry from array list which matches the provided value. * @@ -574,42 +563,6 @@ void celix_arrayList_removeInt(celix_array_list_t* list, int value); CELIX_UTILS_EXPORT void celix_arrayList_removeLong(celix_array_list_t* list, long value); -/** - * @brief Remove the first unsigned int entry from array list which matches the provided value. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_UINT and - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * The equals callback provided when the array list was created will be used to find the entry. - * If there was no equals callback provided a direct memory compare will be done. - */ -CELIX_UTILS_EXPORT -void celix_arrayList_removeUInt(celix_array_list_t* list, unsigned int value); - -/** - * @brief Remove the first unsigned long entry from array list which matches the provided value. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_ULONG and - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * The equals callback provided when the array list was created will be used to find the entry. - * If there was no equals callback provided a direct memory compare will be done. - */ -CELIX_UTILS_EXPORT -void celix_arrayList_removeULong(celix_array_list_t* list, unsigned long value); - -/** - * @brief Remove the first float entry from array list which matches the provided value. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_FLOAT and - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * The equals callback provided when the array list was created will be used to find the entry. - * If there was no equals callback provided a direct memory compare will be done. - */ -CELIX_UTILS_EXPORT -void celix_arrayList_removeFloat(celix_array_list_t* list, float value); - /** * @brief Remove the first double entry from array list which matches the provided value. * @@ -634,18 +587,6 @@ void celix_arrayList_removeDouble(celix_array_list_t* list, double value); CELIX_UTILS_EXPORT void celix_arrayList_removeBool(celix_array_list_t* list, bool value); -/** - * @brief Remove the first size entry from array list which matches the provided value. - * - * Can be used for array list with element type CELIX_ARRAY_LIST_ELEMENT_TYPE_SIZE or - * CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED. - * - * The equals callback provided when the array list was created will be used to find the entry. - * If there was no equals callback provided a direct memory compare will be done. - */ -CELIX_UTILS_EXPORT -void celix_arrayList_removeSize(celix_array_list_t* list, size_t value); - /** * @brief Remove the first version entry from array list which matches the provided value. * @@ -695,9 +636,8 @@ bool celix_arrayList_equals(const celix_array_list_t* listA, const celix_array_l * @Brief Copy the array list to a new array list. * * The new array list will have the same element type and the same callbacks as the original array list. - * If the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, the strings will be copied and - * if the element type is CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION, the versions will be copied. - * For all other element types the values will be copied. + * For copying the array list entries the copy callback will be used, if the capy callback is NULL a shallow copy will + * be done. * * If a NULL is returned and the original array list is not NULL, a error message is logged to celix_err. * diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index d70af3677..3fbb7f4ff 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -18,16 +18,15 @@ */ #include -#include -#include + #include #include #include "celix_array_list.h" -#include "celix_build_assert.h" #include "celix_err.h" #include "celix_stdlib_cleanup.h" #include "celix_utils.h" +#include "celix_version.h" struct celix_array_list { celix_array_list_element_type_t elementType; @@ -36,6 +35,7 @@ struct celix_array_list { size_t capacity; celix_arrayList_equals_fp equalsCallback; celix_array_list_compare_entries_fp compareCallback; + celix_array_list_copy_entry_fp copyCallback; void (*simpleRemovedCallback)(void* value); void* removedCallbackData; void (*removedCallback)(void* data, celix_array_list_entry_t entry); @@ -100,6 +100,24 @@ static bool celix_arrayList_equalsForElement(celix_array_list_t *list, celix_arr return false; } +static celix_status_t celix_arrayList_copyStringEntry(celix_array_list_entry_t src, celix_array_list_entry_t* dst) { + assert(dst); + dst->stringVal = celix_utils_strdup(src.stringVal); + if (!dst->stringVal) { + return ENOMEM; + } + return CELIX_SUCCESS; +} + +static celix_status_t celix_arrayList_copyVersionEntry(celix_array_list_entry_t src, celix_array_list_entry_t* dst) { + assert(dst); + dst->versionVal = celix_version_copy(src.versionVal); + if (!dst->versionVal) { + return ENOMEM; + } + return CELIX_SUCCESS; +} + static void celix_arrayList_destroyVersion(void* v) { celix_version_t* version = v; celix_version_destroy(version); @@ -114,7 +132,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, int capacity) { +static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, size_t capacity) { celix_array_list_entry_t *newList; size_t oldCapacity = list->capacity; if (capacity > oldCapacity) { @@ -122,7 +140,7 @@ static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, i newList = realloc(list->elementData, sizeof(celix_array_list_entry_t) * newCapacity); if (!newList) { celix_err_push("Failed to reallocate memory for elementData"); - return CELIX_ENOMEM; + return ENOMEM; } list->capacity = newCapacity; list->elementData = newList; @@ -140,10 +158,7 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { list->simpleRemovedCallback = free; list->equalsCallback = celix_arrayList_stringEquals; list->compareCallback = celix_arrayList_compareStringEntries; - break; - case CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF: - list->equalsCallback = celix_arrayList_stringEquals; - list->compareCallback = celix_arrayList_compareStringEntries; + list->copyCallback = celix_arrayList_copyStringEntry; break; case CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG: list->equalsCallback = celix_arrayList_longEquals; @@ -161,6 +176,7 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) { list->simpleRemovedCallback = celix_arrayList_destroyVersion; list->equalsCallback = celix_arrayList_versionEquals; list->compareCallback = celix_arrayList_compareVersionEntries; + list->copyCallback = celix_arrayList_copyVersionEntry; break; default: assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); @@ -200,6 +216,9 @@ celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_cre if (opts->compareCallback) { list->compareCallback = opts->compareCallback; } + if (opts->copyCallback) { + list->copyCallback = opts->copyCallback; + } return celix_steal_ptr(list); } @@ -221,10 +240,6 @@ celix_array_list_t* celix_arrayList_createStringArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING); } -celix_array_list_t* celix_arrayList_createStringRefArray() { - return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF); -} - celix_array_list_t* celix_arrayList_createLongArray() { return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG); } @@ -274,7 +289,6 @@ void* celix_arrayList_get(const celix_array_list_t* list, int index) { const char* celix_arrayList_getString(const celix_array_list_t* list, int index) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); return arrayList_getEntry(list, index).stringVal; } @@ -303,7 +317,7 @@ const celix_version_t* celix_arrayList_getVersion(const celix_array_list_t* list } static celix_status_t celix_arrayList_addEntry(celix_array_list_t* list, celix_array_list_entry_t entry) { - celix_status_t status = celix_arrayList_ensureCapacity(list, (int)list->size + 1); + celix_status_t status = celix_arrayList_ensureCapacity(list, list->size + 1); if (status == CELIX_SUCCESS) { list->elementData[list->size++] = entry; } else { @@ -329,14 +343,13 @@ celix_status_t celix_arrayList_add(celix_array_list_t* list, void* element) { celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* val) { assert(val); assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { entry.stringVal = celix_utils_strdup(val); if (entry.stringVal == NULL) { - return CELIX_ENOMEM; + return ENOMEM; } } else { entry.stringVal = val; @@ -389,7 +402,7 @@ celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_ if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { entry.versionVal = celix_version_copy(value); if (entry.versionVal == NULL) { - return CELIX_ENOMEM; + return ENOMEM; } } else { entry.versionVal = value; @@ -444,7 +457,6 @@ void celix_arrayList_remove(celix_array_list_t* list, void* ptr) { void celix_arrayList_removeString(celix_array_list_t* list, const char* val) { assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING || - list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING_REF || list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED); celix_array_list_entry_t entry; memset(&entry, 0, sizeof(entry)); @@ -535,6 +547,10 @@ bool celix_arrayList_equals(const celix_array_list_t* listA, const celix_array_l } celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { + if (!list) { + return NULL; + } + celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; opts.elementType = list->elementType; opts.equalsCallback = list->equalsCallback; @@ -542,25 +558,32 @@ celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) { opts.removedCallback = list->removedCallback; opts.removedCallbackData = list->removedCallbackData; opts.simpleRemovedCallback = list->simpleRemovedCallback; + opts.copyCallback = list->copyCallback; celix_autoptr(celix_array_list_t) copy = celix_arrayList_createWithOptions(&opts); if (!copy) { return NULL; } + celix_status_t status = celix_arrayList_ensureCapacity(copy, list->capacity); + if (status != CELIX_SUCCESS) { + return NULL; + } + for (int i = 0; i < celix_arrayList_size(list); ++i) { - celix_array_list_entry_t entry = list->elementData[i]; - celix_status_t status; - if (copy->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) { - status = celix_arrayList_addString(copy, entry.stringVal); - } else if (copy->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) { - status = celix_arrayList_addVersion(copy, entry.versionVal); + celix_array_list_entry_t entry; + if (list->copyCallback) { + memset(&entry, 0, sizeof(entry)); + status = list->copyCallback(list->elementData[i], &entry); + if (status != CELIX_SUCCESS) { + celix_err_push("Failed to copy entry"); + return NULL; + } } else { - status = celix_arrayList_addEntry(copy, entry); - } - if (status != CELIX_SUCCESS) { - celix_err_push("Failed to add entry to copy list."); - return NULL; + entry = list->elementData[i]; //shallow copy } + + (void)celix_arrayList_addEntry(copy, entry); // Cannot fail, because ensureCapacity is already called to + // ensure enough space } return celix_steal_ptr(copy); From 9ae479eb8f5c550e7b69d0b370eaf64c08b4f1ef Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 25 Feb 2024 14:27:48 +0100 Subject: [PATCH 11/11] gh-674: Add missing equals callback check in array list equals --- libs/utils/gtest/src/ArrayListTestSuite.cc | 20 +++++++++++++++++--- libs/utils/include/celix_array_list.h | 2 +- libs/utils/src/array_list.c | 3 +++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libs/utils/gtest/src/ArrayListTestSuite.cc b/libs/utils/gtest/src/ArrayListTestSuite.cc index 24c864a22..0274cd358 100644 --- a/libs/utils/gtest/src/ArrayListTestSuite.cc +++ b/libs/utils/gtest/src/ArrayListTestSuite.cc @@ -42,7 +42,7 @@ TEST_F(ArrayListTestSuite, ArrayListWithEqualsTest) { const char* sb = (char*)b.voidPtrVal; return celix_utils_stringEquals(sa, sb); }; - auto* list = celix_arrayList_createWithOptions(&opts); + celix_autoptr(celix_array_list_t) list = celix_arrayList_createWithOptions(&opts); EXPECT_EQ(0, celix_arrayList_size(list)); celix_arrayList_add(list, (void*)"val0"); @@ -80,8 +80,6 @@ TEST_F(ArrayListTestSuite, ArrayListWithEqualsTest) { EXPECT_EQ(celix_arrayList_size(list), 2); EXPECT_STREQ((char*)celix_arrayList_get(list, 0), "val1"); EXPECT_STREQ((char*)celix_arrayList_get(list, 1), "val3"); - - celix_arrayList_destroy(list); } template @@ -280,6 +278,21 @@ TEST_F(ArrayListTestSuite, EqualCheckTest) { celix_autoptr(celix_array_list_t) list5 = celix_arrayList_createDoubleArray(); //different type than list1 celix_arrayList_addDouble(list5, 1.0); + // And 2 custom pointer list, with different equals callbacks + celix_array_list_create_options_t opts{}; + opts.elementType = CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER; + opts.equalsCallback = [](celix_array_list_entry_t, celix_array_list_entry_t) -> bool { + return true; //dummy equals callback + }; + celix_autoptr(celix_array_list_t) list6 = celix_arrayList_createWithOptions(&opts); + celix_arrayList_add(list6, (void*)1); + opts.equalsCallback = [](celix_array_list_entry_t, celix_array_list_entry_t) -> bool { + return false; //dummy equals callback + }; + celix_autoptr(celix_array_list_t) list7 = celix_arrayList_createWithOptions(&opts); + celix_arrayList_add(list7, (void*)1); + + //The lists can be checked for equality EXPECT_TRUE(celix_arrayList_equals(list1, list2)); EXPECT_TRUE(celix_arrayList_equals(list1, list1)); @@ -290,6 +303,7 @@ TEST_F(ArrayListTestSuite, EqualCheckTest) { EXPECT_FALSE(celix_arrayList_equals(list1, list3)); EXPECT_FALSE(celix_arrayList_equals(list1, list4)); EXPECT_FALSE(celix_arrayList_equals(list1, list5)); + EXPECT_FALSE(celix_arrayList_equals(list6, list7)); } TEST_F(ArrayListTestSuite, CopyArrayTest) { diff --git a/libs/utils/include/celix_array_list.h b/libs/utils/include/celix_array_list.h index b53c70e7e..313f8eb5a 100644 --- a/libs/utils/include/celix_array_list.h +++ b/libs/utils/include/celix_array_list.h @@ -621,7 +621,7 @@ void celix_arrayList_sort(celix_array_list_t *list); * - The array list have the same equals callback * - The array list have the same values at the same index * - * Note that the remove callback and compare callback are ignored. + * Note that the remove, compare and copy callbacks are ignored. * * If both array list are NULL, they are considered equal. * diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c index 3fbb7f4ff..77742c848 100644 --- a/libs/utils/src/array_list.c +++ b/libs/utils/src/array_list.c @@ -532,6 +532,9 @@ bool celix_arrayList_equals(const celix_array_list_t* listA, const celix_array_l if (!listA || !listB) { return false; } + if (listA->elementType != listB->elementType) { + return false; + } if (listA->size != listB->size) { return false; }