| /* |
| * 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. |
| */ |
| |
| #include <assert.h> |
| |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "celix_array_list.h" |
| #include "celix_err.h" |
| #include "celix_stdlib_cleanup.h" |
| #include "celix_utils.h" |
| #include "celix_version.h" |
| |
| #define STRING_VALUE_UNDEFINED_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED" |
| #define STRING_VALUE_POINTER_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER" |
| #define STRING_VALUE_STRING_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING" |
| #define STRING_VALUE_LONG_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG" |
| #define STRING_VALUE_DOUBLE_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE" |
| #define STRING_VALUE_BOOL_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL" |
| #define STRING_VALUE_VERSION_EL_TYPE "CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION" |
| |
| struct celix_array_list { |
| celix_array_list_element_type_t elementType; |
| celix_array_list_entry_t* elementData; |
| size_t size; |
| 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); |
| }; |
| |
| static bool celix_arrayList_undefinedEquals(celix_array_list_entry_t a, celix_array_list_entry_t b) { |
| 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) { |
| 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) { |
| 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_utils_stringEquals(a.stringVal, b.stringVal); |
| } |
| |
| 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_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_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; |
| } |
| |
| inline static bool celix_arrayList_equalsForElement(celix_array_list_t *list, celix_array_list_entry_t a, celix_array_list_entry_t b) { |
| // by class invariant, equalsCallback is never NULL |
| return list->equalsCallback(a, b); |
| } |
| |
| 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); |
| } |
| |
| static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int index) { |
| celix_array_list_entry_t entry = list->elementData[index]; |
| if (list->simpleRemovedCallback != NULL) { |
| list->simpleRemovedCallback(entry.voidPtrVal); |
| } else if (list->removedCallback != NULL) { |
| list->removedCallback(list->removedCallbackData, entry); |
| } |
| } |
| |
| 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) { |
| size_t newCapacity = (oldCapacity * 3) / 2 + 1; |
| newList = realloc(list->elementData, sizeof(celix_array_list_entry_t) * newCapacity); |
| if (!newList) { |
| celix_err_push("Failed to reallocate memory for elementData"); |
| return ENOMEM; |
| } |
| list->capacity = newCapacity; |
| list->elementData = newList; |
| } |
| return CELIX_SUCCESS; |
| } |
| |
| 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; |
| list->copyCallback = celix_arrayList_copyStringEntry; |
| 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_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_VERSION: |
| 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); |
| list->equalsCallback = celix_arrayList_undefinedEquals; |
| break; |
| } |
| } |
| |
| 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) { |
| celix_err_push("Failed to allocate memory for list"); |
| return NULL; |
| } |
| |
| list->capacity = 10; |
| 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; |
| } |
| |
| 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; |
| } |
| if (opts->copyCallback) { |
| list->copyCallback = opts->copyCallback; |
| } |
| return celix_steal_ptr(list); |
| } |
| |
| 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_createLongArray() { |
| return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG); |
| } |
| |
| 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_createVersionArray() { |
| return celix_arrayList_createTypedArray(CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION); |
| } |
| |
| void celix_arrayList_destroy(celix_array_list_t *list) { |
| if (list != NULL) { |
| celix_arrayList_clear(list); |
| free(list->elementData); |
| free(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; |
| } |
| |
| static celix_array_list_entry_t arrayList_getEntry(const celix_array_list_t *list, int index) { |
| celix_array_list_entry_t entry; |
| memset(&entry, 0, sizeof(entry)); |
| if (index < list->size) { |
| entry = list->elementData[index]; |
| } |
| return entry; |
| } |
| |
| celix_array_list_entry_t celix_arrayList_getEntry(const celix_array_list_t *list, int index) { |
| return arrayList_getEntry(list, 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; |
| } |
| |
| 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_UNDEFINED); |
| return arrayList_getEntry(list, index).stringVal; |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| 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, 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; |
| memset(&entry, 0, sizeof(entry)); |
| entry.voidPtrVal = element; |
| return celix_arrayList_addEntry(list, entry); |
| } |
| |
| 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_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 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(value); |
| assert(list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING); |
| celix_array_list_entry_t entry; |
| memset(&entry, 0, sizeof(entry)); |
| entry.stringVal = value; |
| 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); |
| 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_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_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_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) { |
| entry.versionVal = celix_version_copy(value); |
| if (entry.versionVal == NULL) { |
| return 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(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; |
| int index = -1; |
| for (i = 0 ; i < size ; ++i) { |
| bool eq = celix_arrayList_equalsForElement(list, entry, list->elementData[i]); |
| if (eq) { |
| index = i; |
| break; |
| } |
| } |
| return index; |
| } |
| void celix_arrayList_removeAt(celix_array_list_t *list, int index) { |
| if (index >= 0 && index < list->size) { |
| celix_arrayList_callRemovedCallback(list, index); |
| size_t numMoved = list->size - index - 1; |
| memmove(list->elementData+index, list->elementData+index+1, sizeof(celix_array_list_entry_t) * numMoved); |
| memset(&list->elementData[--list->size], 0, sizeof(celix_array_list_entry_t)); |
| } |
| } |
| |
| void celix_arrayList_removeEntry(celix_array_list_t *list, celix_array_list_entry_t entry) { |
| int index = celix_arrayList_indexOf(list, entry); |
| celix_arrayList_removeAt(list, index); |
| } |
| |
| 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_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_UNDEFINED); |
| celix_array_list_entry_t entry; |
| memset(&entry, 0, sizeof(entry)); |
| entry.stringVal = 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); |
| celix_array_list_entry_t entry; |
| memset(&entry, 0, sizeof(entry)); |
| entry.longVal = 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); |
| 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) { |
| 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_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) { |
| for (int i = 0; i < list->size; ++i) { |
| celix_arrayList_callRemovedCallback(list, i); |
| memset(&list->elementData[i], 0, sizeof(celix_array_list_entry_t)); |
| } |
| list->size = 0; |
| } |
| |
| #if defined(__APPLE__) |
| static int celix_arrayList_compareEntries(void* arg, const void* voidA, const void* voidB) { |
| #else |
| static int celix_arrayList_compareEntries(const void* voidA, const void* voidB, void* arg) { |
| #endif |
| celix_array_list_compare_entries_fp compare = arg; |
| const celix_array_list_entry_t* a = voidA; |
| const celix_array_list_entry_t* b = voidB; |
| return compare(*a, *b); |
| } |
| |
| void celix_arrayList_sort(celix_array_list_t *list) { |
| if (list->compareCallback) { |
| celix_arrayList_sortEntries(list, list->compareCallback); |
| } |
| } |
| |
| 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->elementType != listB->elementType) { |
| 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) { |
| 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; |
| opts.compareCallback = list->compareCallback; |
| 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; |
| 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 { |
| 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); |
| } |
| |
| void celix_arrayList_sortEntries(celix_array_list_t *list, celix_array_list_compare_entries_fp compare) { |
| #if defined(__APPLE__) |
| qsort_r(list->elementData, list->size, sizeof(celix_array_list_entry_t), compare, celix_arrayList_compareEntries); |
| #else |
| qsort_r(list->elementData, list->size, sizeof(celix_array_list_entry_t), celix_arrayList_compareEntries, compare); |
| #endif |
| } |
| |
| const char* celix_arrayList_elementTypeToString(celix_array_list_element_type_t type) { |
| switch (type) { |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED: |
| return STRING_VALUE_UNDEFINED_EL_TYPE; |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_POINTER: |
| return STRING_VALUE_POINTER_EL_TYPE; |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING: |
| return STRING_VALUE_STRING_EL_TYPE; |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_LONG: |
| return STRING_VALUE_LONG_EL_TYPE; |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_DOUBLE: |
| return STRING_VALUE_DOUBLE_EL_TYPE; |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_BOOL: |
| return STRING_VALUE_BOOL_EL_TYPE; |
| case CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION: |
| return STRING_VALUE_VERSION_EL_TYPE; |
| default: |
| return STRING_VALUE_UNDEFINED_EL_TYPE; |
| } |
| } |