From 1f324c5b2bb5ff20defaa9f2bdb32a66d1d33034 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Mon, 5 Feb 2024 19:56:44 +0100 Subject: [PATCH] #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);