#include "zh_vector.h" #include #include #include static const char *TAG = "zh_vector"; #define ZH_VECTOR_LOGE(msg, ...) ESP_LOGE(TAG, "[%s:%d] " msg, __FILE__, __LINE__, ##__VA_ARGS__) #define ZH_VECTOR_LOGI(msg, ...) ESP_LOGI(TAG, "[%s:%d] " msg, __FILE__, __LINE__, ##__VA_ARGS__) #define ZH_VECTOR_CHECK(cond, err, msg) \ if (!(cond)) \ { \ ZH_VECTOR_LOGE(msg); \ return err; \ } #define ZH_VECTOR_VALIDATE(cond, err, msg) \ do { \ if (!(cond)) { \ ZH_VECTOR_LOGE(msg); \ return err; \ } \ } while (0) #define ZH_VECTOR_INIT(type) zh_vector_init(sizeof(type)) static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity); esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit) { ZH_VECTOR_LOGI("Vector initialization begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Vector initialization fail. Invalid argument."); ZH_VECTOR_CHECK(unit > 0, ESP_ERR_INVALID_ARG, "Vector initialization fail. Unit size must be greater than 0."); ZH_VECTOR_CHECK(vector->status == false, ESP_ERR_INVALID_STATE, "Vector initialization fail. Vector already initialized."); vector->capacity = 0; vector->size = 0; vector->unit = unit; vector->status = true; ZH_VECTOR_LOGI("Vector initialization success."); return ESP_OK; } esp_err_t zh_vector_free(zh_vector_t *vector) { ZH_VECTOR_LOGI("Vector deletion begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Vector deletion fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Vector deletion fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (vector->items[i] != NULL) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } } if (vector->items != NULL) { heap_caps_free(vector->items); vector->items = NULL; } vector->capacity = 0; vector->size = 0; vector->unit = 0; vector->status = false; ZH_VECTOR_LOGI("Vector deletion success."); return ESP_OK; } esp_err_t zh_vector_get_size(zh_vector_t *vector) { ZH_VECTOR_LOGI("Getting vector size begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_FAIL, "Getting vector size fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_FAIL, "Getting vector size fail. Vector not initialized."); ZH_VECTOR_LOGI("Getting vector size success. Size: %d.", vector->size); return vector->size; } esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item) { ZH_VECTOR_LOGI("Adding item to vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Adding item to vector fail. Invalid argument."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Adding item to vector fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Adding item to vector fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size < UINT16_MAX, ESP_ERR_INVALID_SIZE, "Adding item to vector fail. Maximum size exceeded."); if (vector->capacity == vector->size) { uint16_t new_capacity = (vector->capacity == 0) ? 1 : vector->capacity * 2; ZH_VECTOR_CHECK(new_capacity <= UINT16_MAX, ESP_ERR_INVALID_SIZE, "Adding item to vector fail. Capacity exceeds maximum allowed size."); esp_err_t resize_err = _resize(vector, new_capacity); ZH_VECTOR_CHECK(resize_err == ESP_OK, ESP_ERR_NO_MEM, "Adding item to vector fail. Memory allocation failed during resize."); } vector->items[vector->size] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[vector->size] != NULL, ESP_ERR_NO_MEM, "Adding item to vector fail. Memory allocation failed."); memcpy(vector->items[vector->size], item, vector->unit); vector->size++; ZH_VECTOR_LOGI("Adding item to vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_emplace_back(zh_vector_t *vector, void *item) { ZH_VECTOR_LOGI("Emplacing item to vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Emplacing item to vector fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Emplacing item to vector fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Emplacing item to vector fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size < UINT16_MAX, ESP_ERR_INVALID_SIZE, "Emplacing item to vector fail. Maximum size exceeded."); if (vector->capacity == vector->size) { uint16_t new_capacity = (vector->capacity == 0) ? 1 : vector->capacity * 2; ZH_VECTOR_CHECK(new_capacity <= UINT16_MAX, ESP_ERR_INVALID_SIZE, "Emplacing item to vector fail. Capacity exceeds maximum allowed size."); esp_err_t resize_err = _resize(vector, new_capacity); ZH_VECTOR_CHECK(resize_err == ESP_OK, ESP_ERR_NO_MEM, "Emplacing item to vector fail. Memory allocation failed during resize."); } vector->items[vector->size] = item; vector->size++; ZH_VECTOR_LOGI("Emplacing item to vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_change_item(zh_vector_t *vector, uint16_t index, void *item) { ZH_VECTOR_LOGI("Changing item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Changing item in vector fail. Invalid argument."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Changing item in vector fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Changing item in vector fail. Vector not initialized."); ZH_VECTOR_CHECK(index < vector->size, ESP_FAIL, "Changing item in vector fail. Index does not exist."); memcpy(vector->items[index], item, vector->unit); ZH_VECTOR_LOGI("Changing item in vector success."); return ESP_OK; } void *zh_vector_get_item(zh_vector_t *vector, uint16_t index) { ZH_VECTOR_LOGI("Getting item from vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Getting item from vector fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Getting item from vector fail. Vector not initialized."); ZH_VECTOR_CHECK(index < vector->size, NULL, "Getting item from vector fail. Index does not exist."); void *item = vector->items[index]; ZH_VECTOR_LOGI("Getting item from vector success."); return item; } void *zh_vector_at(zh_vector_t *vector, uint16_t index) { ZH_VECTOR_LOGI("Accessing item at index begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Accessing item fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Accessing item fail. Vector not initialized."); ZH_VECTOR_CHECK(index < vector->size, NULL, "Accessing item fail. Index out of bounds."); ZH_VECTOR_LOGI("Accessing item at index success."); return vector->items[index]; } esp_err_t zh_vector_delete_item(zh_vector_t *vector, uint16_t index) { ZH_VECTOR_LOGI("Deleting item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Deleting item in vector fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Deleting item in vector fail. Vector not initialized."); ZH_VECTOR_CHECK(index < vector->size, ESP_FAIL, "Deleting item in vector fail. Index out of bounds."); heap_caps_free(vector->items[index]); for (uint16_t i = index; i < vector->size - 1; ++i) { vector->items[i] = vector->items[i + 1]; } vector->items[--vector->size] = NULL; if (vector->size < vector->capacity / 2) { esp_err_t resize_err = _resize(vector, vector->capacity / 2); ZH_VECTOR_CHECK(resize_err == ESP_OK, ESP_ERR_NO_MEM, "Deleting item in vector fail. Memory allocation failed during resize."); } ZH_VECTOR_LOGI("Deleting item in vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_remove(zh_vector_t *vector, uint16_t index) { ZH_VECTOR_LOGI("Removing item from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing item fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing item fail. Vector not initialized."); ZH_VECTOR_CHECK(index < vector->size, ESP_FAIL, "Removing item fail. Index out of bounds."); heap_caps_free(vector->items[index]); for (uint16_t i = index; i < vector->size - 1; ++i) { vector->items[i] = vector->items[i + 1]; } vector->items[--vector->size] = NULL; ZH_VECTOR_LOGI("Removing item from vector success. New size: %d.", vector->size); return ESP_OK; } void zh_vector_foreach(zh_vector_t *vector, void (*callback)(void *item)) { for (uint16_t i = 0; i < vector->size; ++i) { callback(vector->items[i]); } } esp_err_t zh_vector_iterate(zh_vector_t *vector, void (*callback)(void *item)) { ZH_VECTOR_LOGI("Iterating over vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Iterating over vector fail. Invalid argument."); ZH_VECTOR_CHECK(callback != NULL, ESP_ERR_INVALID_ARG, "Iterating over vector fail. Callback is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Iterating over vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { callback(vector->items[i]); } ZH_VECTOR_LOGI("Iterating over vector success."); return ESP_OK; } esp_err_t zh_vector_foreach(zh_vector_t *vector, void (*callback)(void *item, void *context), void *context) { ZH_VECTOR_LOGI("Iterating over vector with context begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Iterating over vector fail. Vector is NULL."); ZH_VECTOR_CHECK(callback != NULL, ESP_ERR_INVALID_ARG, "Iterating over vector fail. Callback is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Iterating over vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { callback(vector->items[i], context); } ZH_VECTOR_LOGI("Iterating over vector with context success."); return ESP_OK; } esp_err_t zh_vector_clear(zh_vector_t *vector) { ZH_VECTOR_LOGI("Clearing vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Clearing vector fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Clearing vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } vector->size = 0; ZH_VECTOR_LOGI("Clearing vector success."); return ESP_OK; } esp_err_t zh_vector_clear_and_shrink(zh_vector_t *vector) { ZH_VECTOR_LOGI("Clearing and shrinking vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Clearing and shrinking vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Clearing and shrinking vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } vector->size = 0; esp_err_t err = _resize(vector, 0); ZH_VECTOR_CHECK(err == ESP_OK, err, "Clearing and shrinking vector fail. Failed to resize capacity."); ZH_VECTOR_LOGI("Clearing and shrinking vector success."); return ESP_OK; } esp_err_t zh_vector_reserve(zh_vector_t *vector, uint16_t new_capacity) { ZH_VECTOR_LOGI("Reserving vector capacity begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Reserving vector capacity fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Reserving vector capacity fail. Vector not initialized."); ZH_VECTOR_CHECK(new_capacity > vector->capacity, ESP_OK, "Reserving vector capacity skipped. New capacity is less than or equal to current capacity."); return _resize(vector, new_capacity); } esp_err_t zh_vector_shrink_to_fit(zh_vector_t *vector) { ZH_VECTOR_LOGI("Shrinking vector capacity to fit size begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Shrinking vector capacity fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Shrinking vector capacity fail. Vector not initialized."); if (vector->capacity > vector->size) { return _resize(vector, vector->size); } ZH_VECTOR_LOGI("Shrinking vector capacity skipped. Capacity already fits size."); return ESP_OK; } bool zh_vector_is_empty(zh_vector_t *vector) { return (vector == NULL || vector->status == false || vector->size == 0); } esp_err_t zh_vector_copy(zh_vector_t *dest, const zh_vector_t *src) { ZH_VECTOR_LOGI("Copying vector begin."); ZH_VECTOR_CHECK(dest != NULL, ESP_ERR_INVALID_ARG, "Copying vector fail. Destination vector is NULL."); ZH_VECTOR_CHECK(src != NULL, ESP_ERR_INVALID_ARG, "Copying vector fail. Source vector is NULL."); ZH_VECTOR_CHECK(src->status == true, ESP_ERR_INVALID_STATE, "Copying vector fail. Source vector not initialized."); esp_err_t err = zh_vector_init(dest, src->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Copying vector fail. Failed to initialize destination vector."); err = zh_vector_reserve(dest, src->capacity); ZH_VECTOR_CHECK(err == ESP_OK, err, "Copying vector fail. Failed to reserve memory for destination vector."); for (uint16_t i = 0; i < src->size; ++i) { err = zh_vector_push_back(dest, src->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Copying vector fail. Failed to copy item."); } ZH_VECTOR_LOGI("Copying vector success."); return ESP_OK; } esp_err_t zh_vector_swap(zh_vector_t *vector1, zh_vector_t *vector2) { ZH_VECTOR_LOGI("Swapping vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, ESP_ERR_INVALID_ARG, "Swapping vectors fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, ESP_ERR_INVALID_ARG, "Swapping vectors fail. Second vector is NULL."); ZH_VECTOR_CHECK(vector1->status == true, ESP_ERR_INVALID_STATE, "Swapping vectors fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, ESP_ERR_INVALID_STATE, "Swapping vectors fail. Second vector not initialized."); zh_vector_t temp = *vector1; *vector1 = *vector2; *vector2 = temp; ZH_VECTOR_LOGI("Swapping vectors success."); return ESP_OK; } static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity) { ZH_VECTOR_LOGI("Vector resize begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Vector resize fail. Invalid argument."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Vector resize fail. Vector not initialized."); ZH_VECTOR_CHECK(capacity > 0, ESP_ERR_INVALID_ARG, "Vector resize fail. Capacity must be greater than 0."); ZH_VECTOR_CHECK(capacity <= UINT16_MAX, ESP_ERR_INVALID_ARG, "Vector resize fail. Capacity exceeds maximum allowed size."); if (capacity == vector->capacity) { ZH_VECTOR_LOGI("Vector resize skipped. Capacity already matches the requested size."); return ESP_OK; } if (capacity < vector->size) { for (uint16_t i = capacity; i < vector->size; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } vector->size = capacity; } void **new_items = heap_caps_realloc(vector->items, capacity * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(new_items != NULL, ESP_ERR_NO_MEM, "Vector resize fail. Memory allocation failed."); vector->items = new_items; vector->capacity = capacity; ZH_VECTOR_LOGI("Vector resize success. New capacity: %d.", capacity); return ESP_OK; } /** * @brief Fills the entire vector with the specified item. * * @param vector Pointer to the vector. * @param item Pointer to the item to fill the vector with. * @return ESP_OK on success, or an error code otherwise. * * Example usage: * @code * zh_vector_t vector; * zh_vector_init(&vector, sizeof(int)); * int value = 42; * zh_vector_resize(&vector, 10); * zh_vector_fill(&vector, &value); * @endcode */ esp_err_t zh_vector_fill(zh_vector_t *vector, void *item) { ZH_VECTOR_LOGI("Filling vector with item begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Filling vector fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Filling vector fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Filling vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { memcpy(vector->items[i], item, vector->unit); } ZH_VECTOR_LOGI("Filling vector with item success."); return ESP_OK; } esp_err_t zh_vector_resize_and_fill(zh_vector_t *vector, uint16_t new_size, void *item) { ZH_VECTOR_LOGI("Resizing and filling vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Resizing and filling vector fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Resizing and filling vector fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Resizing and filling vector fail. Vector not initialized."); ZH_VECTOR_CHECK(new_size <= UINT16_MAX, ESP_ERR_INVALID_SIZE, "Resizing vector fail. New size exceeds maximum allowed size."); if (new_size > vector->capacity) { esp_err_t err = _resize(vector, new_size); ZH_VECTOR_CHECK(err == ESP_OK, err, "Resizing and filling vector fail. Failed to resize capacity."); } for (uint16_t i = vector->size; i < new_size; ++i) { vector->items[i] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[i] != NULL, ESP_ERR_NO_MEM, "Resizing and filling vector fail. Memory allocation failed."); memcpy(vector->items[i], item, vector->unit); } vector->size = new_size; ZH_VECTOR_LOGI("Resizing and filling vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_resize_exact(zh_vector_t *vector, uint16_t new_size) { ZH_VECTOR_LOGI("Resizing vector with exact size begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Resizing vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Resizing vector fail. Vector not initialized."); ZH_VECTOR_CHECK(new_size <= UINT16_MAX, ESP_ERR_INVALID_SIZE, "Resizing vector fail. New size exceeds maximum allowed size."); esp_err_t err = _resize(vector, new_size); ZH_VECTOR_CHECK(err == ESP_OK, err, "Resizing vector fail. Failed to resize capacity."); if (new_size > vector->size) { for (uint16_t i = vector->size; i < new_size; ++i) { vector->items[i] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[i] != NULL, ESP_ERR_NO_MEM, "Resizing vector fail. Memory allocation failed."); } } else if (new_size < vector->size) { for (uint16_t i = new_size; i < vector->size; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } } vector->size = new_size; ZH_VECTOR_LOGI("Resizing vector with exact size success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_resize_no_init(zh_vector_t *vector, uint16_t new_size) { ZH_VECTOR_LOGI("Resizing vector without initialization begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Resizing vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Resizing vector fail. Vector not initialized."); ZH_VECTOR_CHECK(new_size <= UINT16_MAX, ESP_ERR_INVALID_SIZE, "Resizing vector fail. New size exceeds maximum allowed size."); if (new_size > vector->capacity) { esp_err_t err = _resize(vector, new_size); ZH_VECTOR_CHECK(err == ESP_OK, err, "Resizing vector fail. Failed to resize capacity."); } if (new_size < vector->size) { for (uint16_t i = new_size; i < vector->size; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } } vector->size = new_size; ZH_VECTOR_LOGI("Resizing vector without initialization success. New size: %d.", vector->size); return ESP_OK; } /** * @brief Finds the index of the specified item in the vector. * * @param vector Pointer to the vector. * @param item Pointer to the item to find. * @param cmp Comparison function to compare items. * @return Index of the found item, or -1 if the item is not found. * * Example usage: * @code * zh_vector_t vector; * zh_vector_init(&vector, sizeof(int)); * int value = 42; * zh_vector_push_back(&vector, &value); * int index = zh_vector_find(&vector, &value, int_cmp); * @endcode */ int zh_vector_find(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding item in vector fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, -1, "Finding item in vector fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding item in vector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding item in vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) == 0) { ZH_VECTOR_LOGI("Item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("Item not found in vector."); return -1; } int zh_vector_find_if(zh_vector_t *vector, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Finding item in vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding item fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, -1, "Finding item fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding item fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { ZH_VECTOR_LOGI("Item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("Item not found in vector."); return -1; } int zh_vector_find_last(zh_vector_t *vector, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Finding last item in vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding last item fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, -1, "Finding last item fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding last item fail. Vector not initialized."); for (int i = vector->size - 1; i >= 0; --i) { if (predicate(vector->items[i])) { ZH_VECTOR_LOGI("Last item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("Last item not found in vector."); return -1; } int zh_vector_find_range(zh_vector_t *vector, uint16_t start, uint16_t end, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Finding item in range of vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding item fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, -1, "Finding item fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding item fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, -1, "Finding item fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, -1, "Finding item fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, -1, "Finding item fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { if (predicate(vector->items[i])) { ZH_VECTOR_LOGI("Item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("Item not found in range of vector."); return -1; } /** * @brief Finds all indices of items in the vector that satisfy a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @param indices Pointer to an array of indices (allocated dynamically). * @param count Pointer to store the number of found indices. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_indices(zh_vector_t *vector, bool (*predicate)(const void *), uint16_t **indices, uint16_t *count) { ZH_VECTOR_LOGI("Finding all indices in vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Predicate is NULL."); ZH_VECTOR_CHECK(indices != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Indices pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding indices fail. Vector not initialized."); *count = 0; *indices = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*indices != NULL, ESP_ERR_NO_MEM, "Finding indices fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { (*indices)[(*count)++] = i; } } ZH_VECTOR_LOGI("Finding all indices in vector with predicate success. Found: %d.", *count); return ESP_OK; } /** * @brief Finds all indices of items in a specified range of the vector that satisfy a predicate. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param predicate Predicate function to evaluate items. * @param indices Pointer to an array of indices (allocated dynamically). * @param count Pointer to store the number of found indices. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_range_indices(zh_vector_t *vector, uint16_t start, uint16_t end, bool (*predicate)(const void *), uint16_t **indices, uint16_t *count) { ZH_VECTOR_LOGI("Finding indices in range of vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Predicate is NULL."); ZH_VECTOR_CHECK(indices != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Indices pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding indices fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding indices fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Finding indices fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Finding indices fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Finding indices fail. Start index must be less than end index."); *count = 0; *indices = heap_caps_malloc((end - start) * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*indices != NULL, ESP_ERR_NO_MEM, "Finding indices fail. Memory allocation failed."); for (uint16_t i = start; i < end; ++i) { if (predicate(vector->items[i])) { (*indices)[(*count)++] = i; } } ZH_VECTOR_LOGI("Finding indices in range of vector with predicate success. Found: %d.", *count); return ESP_OK; } /** * @brief Sorts the elements of the vector in ascending order. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @return ESP_OK on success, or an error code otherwise. * * Example usage: * @code * zh_vector_t vector; * zh_vector_init(&vector, sizeof(int)); * int values[] = {3, 1, 4, 1, 5}; * for (int i = 0; i < 5; ++i) { * zh_vector_push_back(&vector, &values[i]); * } * zh_vector_sort(&vector, int_cmp); * @endcode */ esp_err_t zh_vector_sort(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Sorting vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Sorting vector fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Sorting vector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Sorting vector fail. Vector not initialized."); if (vector->size <= 1) { ZH_VECTOR_LOGI("Sorting vector skipped. Vector is empty or has only one element."); return ESP_OK; } qsort(vector->items, vector->size, sizeof(void *), cmp); ZH_VECTOR_LOGI("Sorting vector success."); return ESP_OK; } esp_err_t zh_vector_sort_descending(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Sorting vector in descending order begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Sorting vector fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Sorting vector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Sorting vector fail. Vector not initialized."); if (vector->size <= 1) { ZH_VECTOR_LOGI("Sorting vector skipped. Vector is empty or has only one element."); return ESP_OK; } int reverse_cmp(const void *a, const void *b) { return -cmp(a, b); } qsort(vector->items, vector->size, sizeof(void *), reverse_cmp); ZH_VECTOR_LOGI("Sorting vector in descending order success."); return ESP_OK; } esp_err_t zh_vector_reverse(zh_vector_t *vector) { ZH_VECTOR_LOGI("Reversing vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Reversing vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Reversing vector fail. Vector not initialized."); if (vector->size <= 1) { ZH_VECTOR_LOGI("Reversing vector skipped. Vector is empty or has only one element."); return ESP_OK; } for (uint16_t i = 0; i < vector->size / 2; ++i) { void *temp = vector->items[i]; vector->items[i] = vector->items[vector->size - i - 1]; vector->items[vector->size - i - 1] = temp; } ZH_VECTOR_LOGI("Reversing vector success."); return ESP_OK; } uint16_t zh_vector_capacity(zh_vector_t *vector) { ZH_VECTOR_LOGI("Getting vector capacity begin."); ZH_VECTOR_CHECK(vector != NULL, 0, "Getting vector capacity fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, 0, "Getting vector capacity fail. Vector not initialized."); ZH_VECTOR_LOGI("Getting vector capacity success. Capacity: %d.", vector->capacity); return vector->capacity; } uint16_t zh_vector_capacity_left(zh_vector_t *vector) { ZH_VECTOR_LOGI("Getting vector free capacity begin."); ZH_VECTOR_CHECK(vector != NULL, 0, "Getting vector free capacity fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, 0, "Getting vector free capacity fail. Vector not initialized."); uint16_t free_capacity = vector->capacity - vector->size; ZH_VECTOR_LOGI("Getting vector free capacity success. Free capacity: %d.", free_capacity); return free_capacity; } esp_err_t zh_vector_resize(zh_vector_t *vector, uint16_t new_size) { ZH_VECTOR_LOGI("Resizing vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Resizing vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Resizing vector fail. Vector not initialized."); ZH_VECTOR_CHECK(new_size <= UINT16_MAX, ESP_ERR_INVALID_SIZE, "Resizing vector fail. New size exceeds maximum allowed size."); if (new_size > vector->capacity) { esp_err_t err = _resize(vector, new_size); ZH_VECTOR_CHECK(err == ESP_OK, err, "Resizing vector fail. Failed to resize capacity."); } if (new_size > vector->size) { for (uint16_t i = vector->size; i < new_size; ++i) { vector->items[i] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[i] != NULL, ESP_ERR_NO_MEM, "Resizing vector fail. Memory allocation failed."); } } else if (new_size < vector->size) { for (uint16_t i = new_size; i < vector->size; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = NULL; } } vector->size = new_size; ZH_VECTOR_LOGI("Resizing vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_pop_back(zh_vector_t *vector) { ZH_VECTOR_LOGI("Popping item from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Popping item from vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Popping item from vector fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, ESP_FAIL, "Popping item from vector fail. Vector is empty."); heap_caps_free(vector->items[vector->size - 1]); vector->items[vector->size - 1] = NULL; vector->size--; ZH_VECTOR_LOGI("Popping item from vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_insert(zh_vector_t *vector, uint16_t index, void *item) { ZH_VECTOR_LOGI("Inserting item into vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Inserting item fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Inserting item fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Inserting item fail. Vector not initialized."); ZH_VECTOR_CHECK(index <= vector->size, ESP_FAIL, "Inserting item fail. Index out of bounds."); if (vector->capacity == vector->size) { uint16_t new_capacity = (vector->capacity == 0) ? 1 : vector->capacity * 2; esp_err_t resize_err = _resize(vector, new_capacity); ZH_VECTOR_CHECK(resize_err == ESP_OK, ESP_ERR_NO_MEM, "Inserting item fail. Memory allocation failed during resize."); } for (uint16_t i = vector->size; i > index; --i) { vector->items[i] = vector->items[i - 1]; } vector->items[index] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[index] != NULL, ESP_ERR_NO_MEM, "Inserting item fail. Memory allocation failed."); memcpy(vector->items[index], item, vector->unit); vector->size++; ZH_VECTOR_LOGI("Inserting item into vector success. New size: %d.", vector->size); return ESP_OK; } zh_vector_t *zh_vector_clone(const zh_vector_t *src) { ZH_VECTOR_LOGI("Cloning vector begin."); ZH_VECTOR_CHECK(src != NULL, NULL, "Cloning vector fail. Source vector is NULL."); ZH_VECTOR_CHECK(src->status == true, NULL, "Cloning vector fail. Source vector not initialized."); zh_vector_t *clone = heap_caps_calloc(1, sizeof(zh_vector_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(clone != NULL, NULL, "Cloning vector fail. Memory allocation failed."); esp_err_t err = zh_vector_init(clone, src->unit); if (err != ESP_OK) { heap_caps_free(clone); return NULL; } err = zh_vector_reserve(clone, src->capacity); if (err != ESP_OK) { zh_vector_free(clone); heap_caps_free(clone); return NULL; } for (uint16_t i = 0; i < src->size; ++i) { err = zh_vector_push_back(clone, src->items[i]); if (err != ESP_OK) { zh_vector_free(clone); heap_caps_free(clone); return NULL; } } ZH_VECTOR_LOGI("Cloning vector success."); return clone; } bool zh_vector_compare(const zh_vector_t *vector1, const zh_vector_t *vector2, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Comparing vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, false, "Comparing vectors fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, false, "Comparing vectors fail. Second vector is NULL."); ZH_VECTOR_CHECK(vector1->status == true, false, "Comparing vectors fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, false, "Comparing vectors fail. Second vector not initialized."); ZH_VECTOR_CHECK(cmp != NULL, false, "Comparing vectors fail. Comparison function is NULL."); if (vector1->size != vector2->size) { ZH_VECTOR_LOGI("Comparing vectors fail. Sizes are different."); return false; } for (uint16_t i = 0; i < vector1->size; ++i) { if (cmp(vector1->items[i], vector2->items[i]) != 0) { ZH_VECTOR_LOGI("Comparing vectors fail. Items at index %d are different.", i); return false; } } ZH_VECTOR_LOGI("Comparing vectors success. Vectors are equal."); return true; } bool zh_vector_compare_ranges(zh_vector_t *vector1, uint16_t start1, uint16_t end1, zh_vector_t *vector2, uint16_t start2, uint16_t end2, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Comparing ranges of two vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, false, "Comparing ranges fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, false, "Comparing ranges fail. Second vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, false, "Comparing ranges fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, false, "Comparing ranges fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, false, "Comparing ranges fail. Second vector not initialized."); ZH_VECTOR_CHECK(start1 < vector1->size && end1 <= vector1->size, false, "Comparing ranges fail. Range out of bounds in first vector."); ZH_VECTOR_CHECK(start2 < vector2->size && end2 <= vector2->size, false, "Comparing ranges fail. Range out of bounds in second vector."); ZH_VECTOR_CHECK((end1 - start1) == (end2 - start2), false, "Comparing ranges fail. Ranges have different lengths."); for (uint16_t i = 0; i < (end1 - start1); ++i) { if (cmp(vector1->items[start1 + i], vector2->items[start2 + i]) != 0) { ZH_VECTOR_LOGI("Ranges are different at index: %d.", i); return false; } } ZH_VECTOR_LOGI("Ranges are equal."); return true; } esp_err_t zh_vector_filter(zh_vector_t *vector, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Filtering vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Filtering vector fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Filtering vector fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Filtering vector fail. Vector not initialized."); uint16_t write_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { if (write_index != i) { vector->items[write_index] = vector->items[i]; } write_index++; } else { heap_caps_free(vector->items[i]); } } for (uint16_t i = write_index; i < vector->size; ++i) { vector->items[i] = NULL; } vector->size = write_index; ZH_VECTOR_LOGI("Filtering vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_map(zh_vector_t *vector, void (*func)(void *item)) { ZH_VECTOR_LOGI("Mapping function over vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Mapping function fail. Vector is NULL."); ZH_VECTOR_CHECK(func != NULL, ESP_ERR_INVALID_ARG, "Mapping function fail. Function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Mapping function fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { func(vector->items[i]); } ZH_VECTOR_LOGI("Mapping function over vector success."); return ESP_OK; } void *zh_vector_reduce(zh_vector_t *vector, void *(*func)(void *acc, void *item), void *initial) { ZH_VECTOR_LOGI("Reducing vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Reducing vector fail. Vector is NULL."); ZH_VECTOR_CHECK(func != NULL, NULL, "Reducing vector fail. Function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Reducing vector fail. Vector not initialized."); void *acc = initial; for (uint16_t i = 0; i < vector->size; ++i) { acc = func(acc, vector->items[i]); } ZH_VECTOR_LOGI("Reducing vector success."); return acc; } void *zh_vector_accumulate(zh_vector_t *vector, void *initial, void *(*func)(void *acc, void *item)) { ZH_VECTOR_LOGI("Accumulating values in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Accumulating values fail. Vector is NULL."); ZH_VECTOR_CHECK(func != NULL, NULL, "Accumulating values fail. Function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Accumulating values fail. Vector not initialized."); void *acc = initial; for (uint16_t i = 0; i < vector->size; ++i) { acc = func(acc, vector->items[i]); } ZH_VECTOR_LOGI("Accumulating values in vector success."); return acc; } /** * @brief Accumulates values in a specified range of the vector using a user-defined function. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param initial Initial value for the accumulation. * @param func Accumulation function that takes the current accumulator and an item. * @return Accumulated value. */ void *zh_vector_accumulate_range(zh_vector_t *vector, uint16_t start, uint16_t end, void *initial, void *(*func)(void *acc, void *item)) { ZH_VECTOR_LOGI("Accumulating values in range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Accumulating values fail. Vector is NULL."); ZH_VECTOR_CHECK(func != NULL, NULL, "Accumulating values fail. Function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Accumulating values fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, NULL, "Accumulating values fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, NULL, "Accumulating values fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, NULL, "Accumulating values fail. Start index must be less than end index."); void *acc = initial; for (uint16_t i = start; i < end; ++i) { acc = func(acc, vector->items[i]); } ZH_VECTOR_LOGI("Accumulating values in range of vector success."); return acc; } esp_err_t zh_vector_swap_items(zh_vector_t *vector, uint16_t index1, uint16_t index2) { ZH_VECTOR_LOGI("Swapping items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Swapping items fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Swapping items fail. Vector not initialized."); ZH_VECTOR_CHECK(index1 < vector->size, ESP_FAIL, "Swapping items fail. Index1 out of bounds."); ZH_VECTOR_CHECK(index2 < vector->size, ESP_FAIL, "Swapping items fail. Index2 out of bounds."); void *temp = vector->items[index1]; vector->items[index1] = vector->items[index2]; vector->items[index2] = temp; ZH_VECTOR_LOGI("Swapping items in vector success."); return ESP_OK; } bool zh_vector_contains(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Checking if vector contains item begin."); ZH_VECTOR_CHECK(vector != NULL, false, "Checking item fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, false, "Checking item fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, false, "Checking item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, false, "Checking item fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) == 0) { ZH_VECTOR_LOGI("Item found in vector."); return true; } } ZH_VECTOR_LOGI("Item not found in vector."); return false; } esp_err_t zh_vector_extend(zh_vector_t *dest, const zh_vector_t *src) { ZH_VECTOR_LOGI("Extending vector begin."); ZH_VECTOR_CHECK(dest != NULL, ESP_ERR_INVALID_ARG, "Extending vector fail. Destination vector is NULL."); ZH_VECTOR_CHECK(src != NULL, ESP_ERR_INVALID_ARG, "Extending vector fail. Source vector is NULL."); ZH_VECTOR_CHECK(dest->status == true, ESP_ERR_INVALID_STATE, "Extending vector fail. Destination vector not initialized."); ZH_VECTOR_CHECK(src->status == true, ESP_ERR_INVALID_STATE, "Extending vector fail. Source vector not initialized."); ZH_VECTOR_CHECK(dest->unit == src->unit, ESP_ERR_INVALID_ARG, "Extending vector fail. Unit sizes do not match."); for (uint16_t i = 0; i < src->size; ++i) { esp_err_t err = zh_vector_push_back(dest, src->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Extending vector fail. Failed to add item."); } ZH_VECTOR_LOGI("Extending vector success."); return ESP_OK; } void **zh_vector_to_array(zh_vector_t *vector) { ZH_VECTOR_LOGI("Converting vector to array begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Converting vector to array fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Converting vector to array fail. Vector not initialized."); void **array = heap_caps_malloc(vector->size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(array != NULL, NULL, "Converting vector to array fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { array[i] = vector->items[i]; } ZH_VECTOR_LOGI("Converting vector to array success."); return array; } esp_err_t zh_vector_remove_if(zh_vector_t *vector, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Removing items from vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing items fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Removing items fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing items fail. Vector not initialized."); uint16_t write_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (!predicate(vector->items[i])) { if (write_index != i) { vector->items[write_index] = vector->items[i]; } write_index++; } else { heap_caps_free(vector->items[i]); } } for (uint16_t i = write_index; i < vector->size; ++i) { vector->items[i] = NULL; } vector->size = write_index; ZH_VECTOR_LOGI("Removing items from vector with predicate success. New size: %d.", vector->size); return ESP_OK; } /** * @brief Removes all items from the vector that do not satisfy a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_remove_if_not(zh_vector_t *vector, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Removing items from vector that do not satisfy predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing items fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Removing items fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing items fail. Vector not initialized."); uint16_t write_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { if (write_index != i) { vector->items[write_index] = vector->items[i]; } write_index++; } else { heap_caps_free(vector->items[i]); } } for (uint16_t i = write_index; i < vector->size; ++i) { vector->items[i] = NULL; } vector->size = write_index; ZH_VECTOR_LOGI("Removing items from vector that do not satisfy predicate success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_replace(zh_vector_t *vector, bool (*predicate)(const void *), void *new_item) { ZH_VECTOR_LOGI("Replacing items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Replacing items fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Replacing items fail. Predicate is NULL."); ZH_VECTOR_CHECK(new_item != NULL, ESP_ERR_INVALID_ARG, "Replacing items fail. New item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Replacing items fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { heap_caps_free(vector->items[i]); vector->items[i] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[i] != NULL, ESP_ERR_NO_MEM, "Replacing items fail. Memory allocation failed."); memcpy(vector->items[i], new_item, vector->unit); } } ZH_VECTOR_LOGI("Replacing items in vector success."); return ESP_OK; } /** * @brief Removes all occurrences of the specified item from the vector. * * @param vector Pointer to the vector. * @param item Pointer to the item to remove. * @param cmp Comparison function to compare items. * @return ESP_OK on success, or an error code otherwise. * * Example usage: * @code * zh_vector_t vector; * zh_vector_init(&vector, sizeof(int)); * int value = 42; * zh_vector_push_back(&vector, &value); * zh_vector_remove_all(&vector, &value, int_cmp); * @endcode */ esp_err_t zh_vector_remove_all(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing all occurrences of item from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing all occurrences fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Removing all occurrences fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing all occurrences fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing all occurrences fail. Vector not initialized."); uint16_t write_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) != 0) { if (write_index != i) { vector->items[write_index] = vector->items[i]; } write_index++; } else { heap_caps_free(vector->items[i]); } } for (uint16_t i = write_index; i < vector->size; ++i) { vector->items[i] = NULL; } vector->size = write_index; ZH_VECTOR_LOGI("Removing all occurrences of item from vector success. New size: %d.", vector->size); return ESP_OK; } esp_err_t zh_vector_replace_all(zh_vector_t *vector, void *old_item, void *new_item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Replacing all occurrences of item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Replacing all occurrences fail. Vector is NULL."); ZH_VECTOR_CHECK(old_item != NULL, ESP_ERR_INVALID_ARG, "Replacing all occurrences fail. Old item is NULL."); ZH_VECTOR_CHECK(new_item != NULL, ESP_ERR_INVALID_ARG, "Replacing all occurrences fail. New item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Replacing all occurrences fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Replacing all occurrences fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], old_item) == 0) { heap_caps_free(vector->items[i]); vector->items[i] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[i] != NULL, ESP_ERR_NO_MEM, "Replacing all occurrences fail. Memory allocation failed."); memcpy(vector->items[i], new_item, vector->unit); } } ZH_VECTOR_LOGI("Replacing all occurrences of item in vector success."); return ESP_OK; } uint16_t zh_vector_count_if(zh_vector_t *vector, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Counting items in vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, 0, "Counting items fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, 0, "Counting items fail. Predicate is NULL."); ZH_VECTOR_CHECK(vector->status == true, 0, "Counting items fail. Vector not initialized."); uint16_t count = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { count++; } } ZH_VECTOR_LOGI("Counting items in vector with predicate success. Count: %d.", count); return count; } esp_err_t zh_vector_merge(zh_vector_t *dest, const zh_vector_t *src) { ZH_VECTOR_LOGI("Merging vectors begin."); ZH_VECTOR_CHECK(dest != NULL, ESP_ERR_INVALID_ARG, "Merging vectors fail. Destination vector is NULL."); ZH_VECTOR_CHECK(src != NULL, ESP_ERR_INVALID_ARG, "Merging vectors fail. Source vector is NULL."); ZH_VECTOR_CHECK(dest->status == true, ESP_ERR_INVALID_STATE, "Merging vectors fail. Destination vector not initialized."); ZH_VECTOR_CHECK(src->status == true, ESP_ERR_INVALID_STATE, "Merging vectors fail. Source vector not initialized."); ZH_VECTOR_CHECK(dest->unit == src->unit, ESP_ERR_INVALID_ARG, "Merging vectors fail. Unit sizes do not match."); for (uint16_t i = 0; i < src->size; ++i) { esp_err_t err = zh_vector_push_back(dest, src->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Merging vectors fail. Failed to add item."); } ZH_VECTOR_LOGI("Merging vectors success."); return ESP_OK; } esp_err_t zh_vector_unique(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing duplicates from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing duplicates fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = i + 1; j < vector->size;) { if (cmp(vector->items[i], vector->items[j]) == 0) { zh_vector_remove(vector, j); } else { j++; } } } ZH_VECTOR_LOGI("Removing duplicates from vector success."); return ESP_OK; } esp_err_t zh_vector_remove_duplicates(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing duplicates from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing duplicates fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = i + 1; j < vector->size;) { if (cmp(vector->items[i], vector->items[j]) == 0) { zh_vector_remove(vector, j); } else { j++; } } } ZH_VECTOR_LOGI("Removing duplicates from vector success."); return ESP_OK; } /** * @brief Removes duplicate items from the vector using a comparison function. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_remove_duplicates_with_predicate(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing duplicates from vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing duplicates fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = i + 1; j < vector->size;) { if (cmp(vector->items[i], vector->items[j]) == 0) { zh_vector_remove(vector, j); } else { j++; } } } ZH_VECTOR_LOGI("Removing duplicates from vector with predicate success."); return ESP_OK; } void **zh_vector_to_array(zh_vector_t *vector) { ZH_VECTOR_LOGI("Converting vector to array begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Converting vector to array fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Converting vector to array fail. Vector not initialized."); void **array = heap_caps_malloc(vector->size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(array != NULL, NULL, "Converting vector to array fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { array[i] = vector->items[i]; } ZH_VECTOR_LOGI("Converting vector to array success."); return array; } /** * @brief Partitions the vector into two parts based on a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @param true_part Pointer to the vector to store items satisfying the predicate. * @param false_part Pointer to the vector to store items not satisfying the predicate. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_partition(zh_vector_t *vector, bool (*predicate)(const void *), zh_vector_t *true_part, zh_vector_t *false_part) { ZH_VECTOR_LOGI("Partitioning vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Predicate is NULL."); ZH_VECTOR_CHECK(true_part != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. True part is NULL."); ZH_VECTOR_CHECK(false_part != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. False part is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Partitioning vector fail. Vector not initialized."); esp_err_t err = zh_vector_init(true_part, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning vector fail. Failed to initialize true part."); err = zh_vector_init(false_part, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning vector fail. Failed to initialize false part."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { err = zh_vector_push_back(true_part, vector->items[i]); } else { err = zh_vector_push_back(false_part, vector->items[i]); } ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning vector fail. Failed to add item."); } ZH_VECTOR_LOGI("Partitioning vector success."); return ESP_OK; } /** * @brief Partitions a specified range of the vector into two parts based on a predicate. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param predicate Predicate function to evaluate items. * @param true_part Pointer to the vector to store items satisfying the predicate. * @param false_part Pointer to the vector to store items not satisfying the predicate. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_partition_range(zh_vector_t *vector, uint16_t start, uint16_t end, bool (*predicate)(const void *), zh_vector_t *true_part, zh_vector_t *false_part) { ZH_VECTOR_LOGI("Partitioning range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Partitioning range fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Partitioning range fail. Predicate is NULL."); ZH_VECTOR_CHECK(true_part != NULL, ESP_ERR_INVALID_ARG, "Partitioning range fail. True part is NULL."); ZH_VECTOR_CHECK(false_part != NULL, ESP_ERR_INVALID_ARG, "Partitioning range fail. False part is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Partitioning range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Partitioning range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Partitioning range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Partitioning range fail. Start index must be less than end index."); esp_err_t err = zh_vector_init(true_part, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning range fail. Failed to initialize true part."); err = zh_vector_init(false_part, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning range fail. Failed to initialize false part."); for (uint16_t i = start; i < end; ++i) { if (predicate(vector->items[i])) { err = zh_vector_push_back(true_part, vector->items[i]); } else { err = zh_vector_push_back(false_part, vector->items[i]); } ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning range fail. Failed to add item."); } ZH_VECTOR_LOGI("Partitioning range of vector success."); return ESP_OK; } esp_err_t zh_vector_copy_if(const zh_vector_t *src, zh_vector_t *dest, bool (*predicate)(const void *)) { ZH_VECTOR_LOGI("Copying items from vector with predicate begin."); ZH_VECTOR_CHECK(src != NULL, ESP_ERR_INVALID_ARG, "Copying items fail. Source vector is NULL."); ZH_VECTOR_CHECK(dest != NULL, ESP_ERR_INVALID_ARG, "Copying items fail. Destination vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Copying items fail. Predicate is NULL."); ZH_VECTOR_CHECK(src->status == true, ESP_ERR_INVALID_STATE, "Copying items fail. Source vector not initialized."); esp_err_t err = zh_vector_init(dest, src->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Copying items fail. Failed to initialize destination vector."); for (uint16_t i = 0; i < src->size; ++i) { if (predicate(src->items[i])) { err = zh_vector_push_back(dest, src->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Copying items fail. Failed to add item."); } } ZH_VECTOR_LOGI("Copying items from vector with predicate success."); return ESP_OK; } /** * @brief Rotates the vector by the specified number of positions. * * @param vector Pointer to the vector. * @param positions Number of positions to rotate (positive for right, negative for left). * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_rotate(zh_vector_t *vector, int16_t positions) { ZH_VECTOR_LOGI("Rotating vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Rotating vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Rotating vector fail. Vector not initialized."); if (vector->size <= 1 || positions == 0) { ZH_VECTOR_LOGI("Rotating vector skipped. Vector is empty, has only one element, or positions is zero."); return ESP_OK; } positions = positions % vector->size; if (positions < 0) { positions += vector->size; } void **temp = heap_caps_malloc(vector->size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Rotating vector fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { temp[(i + positions) % vector->size] = vector->items[i]; } memcpy(vector->items, temp, vector->size * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Rotating vector success."); return ESP_OK; } esp_err_t zh_vector_find_all(zh_vector_t *vector, bool (*predicate)(const void *), uint16_t **indices, uint16_t *count) { ZH_VECTOR_LOGI("Finding all items in vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding all items fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Finding all items fail. Predicate is NULL."); ZH_VECTOR_CHECK(indices != NULL, ESP_ERR_INVALID_ARG, "Finding all items fail. Indices pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding all items fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding all items fail. Vector not initialized."); *count = 0; *indices = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*indices != NULL, ESP_ERR_NO_MEM, "Finding all items fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { (*indices)[(*count)++] = i; } } ZH_VECTOR_LOGI("Finding all items in vector with predicate success. Found: %d.", *count); return ESP_OK; } esp_err_t zh_vector_intersect(const zh_vector_t *vector1, const zh_vector_t *vector2, zh_vector_t *result, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding intersection of two vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. Second vector is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. Result vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, ESP_ERR_INVALID_STATE, "Intersection fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, ESP_ERR_INVALID_STATE, "Intersection fail. Second vector not initialized."); esp_err_t err = zh_vector_init(result, vector1->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Intersection fail. Failed to initialize result vector."); for (uint16_t i = 0; i < vector1->size; ++i) { for (uint16_t j = 0; j < vector2->size; ++j) { if (cmp(vector1->items[i], vector2->items[j]) == 0) { err = zh_vector_push_back(result, vector1->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Intersection fail. Failed to add item to result vector."); break; } } } ZH_VECTOR_LOGI("Finding intersection of two vectors success."); return ESP_OK; } /** * @brief Finds the intersection of two sorted vectors. * * @param vector1 Pointer to the first sorted vector. * @param vector2 Pointer to the second sorted vector. * @param result Pointer to the vector to store the intersection. * @param cmp Comparison function to compare items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_intersect_sorted(zh_vector_t *vector1, zh_vector_t *vector2, zh_vector_t *result, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding intersection of two sorted vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. Second vector is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. Result vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Intersection fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, ESP_ERR_INVALID_STATE, "Intersection fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, ESP_ERR_INVALID_STATE, "Intersection fail. Second vector not initialized."); uint16_t i = 0, j = 0; while (i < vector1->size && j < vector2->size) { int comparison = cmp(vector1->items[i], vector2->items[j]); if (comparison == 0) { esp_err_t err = zh_vector_push_back(result, vector1->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Intersection fail. Failed to add item to result vector."); i++; j++; } else if (comparison < 0) { i++; } else { j++; } } ZH_VECTOR_LOGI("Finding intersection of two sorted vectors success."); return ESP_OK; } esp_err_t zh_vector_union(const zh_vector_t *vector1, const zh_vector_t *vector2, zh_vector_t *result, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding union of two vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, ESP_ERR_INVALID_ARG, "Union fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, ESP_ERR_INVALID_ARG, "Union fail. Second vector is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Union fail. Result vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Union fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, ESP_ERR_INVALID_STATE, "Union fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, ESP_ERR_INVALID_STATE, "Union fail. Second vector not initialized."); esp_err_t err = zh_vector_init(result, vector1->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Union fail. Failed to initialize result vector."); for (uint16_t i = 0; i < vector1->size; ++i) { err = zh_vector_push_back(result, vector1->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Union fail. Failed to add item from first vector."); } for (uint16_t i = 0; i < vector2->size; ++i) { bool found = false; for (uint16_t j = 0; j < result->size; ++j) { if (cmp(vector2->items[i], result->items[j]) == 0) { found = true; break; } } if (!found) { err = zh_vector_push_back(result, vector2->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Union fail. Failed to add item from second vector."); } } ZH_VECTOR_LOGI("Finding union of two vectors success."); return ESP_OK; } esp_err_t zh_vector_difference(const zh_vector_t *vector1, const zh_vector_t *vector2, zh_vector_t *result, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding difference of two vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, ESP_ERR_INVALID_ARG, "Difference fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, ESP_ERR_INVALID_ARG, "Difference fail. Second vector is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Difference fail. Result vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Difference fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, ESP_ERR_INVALID_STATE, "Difference fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, ESP_ERR_INVALID_STATE, "Difference fail. Second vector not initialized."); esp_err_t err = zh_vector_init(result, vector1->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Difference fail. Failed to initialize result vector."); for (uint16_t i = 0; i < vector1->size; ++i) { bool found = false; for (uint16_t j = 0; j < vector2->size; ++j) { if (cmp(vector1->items[i], vector2->items[j]) == 0) { found = true; break; } } if (!found) { err = zh_vector_push_back(result, vector1->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Difference fail. Failed to add item to result vector."); } } ZH_VECTOR_LOGI("Finding difference of two vectors success."); return ESP_OK; } esp_err_t zh_vector_symmetric_difference(const zh_vector_t *vector1, const zh_vector_t *vector2, zh_vector_t *result, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding symmetric difference of two vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, ESP_ERR_INVALID_ARG, "Symmetric difference fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, ESP_ERR_INVALID_ARG, "Symmetric difference fail. Second vector is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Symmetric difference fail. Result vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Symmetric difference fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, ESP_ERR_INVALID_STATE, "Symmetric difference fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, ESP_ERR_INVALID_STATE, "Symmetric difference fail. Second vector not initialized."); esp_err_t err = zh_vector_init(result, vector1->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Symmetric difference fail. Failed to initialize result vector."); // Добавляем элементы из vector1, которых нет в vector2 for (uint16_t i = 0; i < vector1->size; ++i) { bool found = false; for (uint16_t j = 0; j < vector2->size; ++j) { if (cmp(vector1->items[i], vector2->items[j]) == 0) { found = true; break; } } if (!found) { err = zh_vector_push_back(result, vector1->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Symmetric difference fail. Failed to add item from first vector."); } } // Добавляем элементы из vector2, которых нет в vector1 for (uint16_t i = 0; i < vector2->size; ++i) { bool found = false; for (uint16_t j = 0; j < vector1->size; ++j) { if (cmp(vector2->items[i], vector1->items[j]) == 0) { found = true; break; } } if (!found) { err = zh_vector_push_back(result, vector2->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Symmetric difference fail. Failed to add item from second vector."); } } ZH_VECTOR_LOGI("Finding symmetric difference of two vectors success."); return ESP_OK; } esp_err_t zh_vector_shuffle(zh_vector_t *vector) { ZH_VECTOR_LOGI("Shuffling vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Shuffling vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Shuffling vector fail. Vector not initialized."); srand((unsigned int)time(NULL)); // Инициализация генератора случайных чисел return mid; } else if (result < 0) { left = mid + 1; } else { right = mid - 1; } } ZH_VECTOR_LOGI("Item not found in vector."); return -1; } void *zh_vector_min(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding minimum item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding minimum fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding minimum fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding minimum fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, NULL, "Finding minimum fail. Vector is empty."); void *min_item = vector->items[0]; for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i], min_item) < 0) { min_item = vector->items[i]; } } ZH_VECTOR_LOGI("Finding minimum item in vector success."); return min_item; } void *zh_vector_max(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding maximum item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding maximum fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding maximum fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding maximum fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, NULL, "Finding maximum fail. Vector is empty."); void *max_item = vector->items[0]; for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i], max_item) > 0) { max_item = vector->items[i]; } } ZH_VECTOR_LOGI("Finding maximum item in vector success."); return max_item; } esp_err_t zh_vector_fill(zh_vector_t *vector, void *item) { ZH_VECTOR_LOGI("Filling vector with item begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Filling vector fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Filling vector fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Filling vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { memcpy(vector->items[i], item, vector->unit); } ZH_VECTOR_LOGI("Filling vector with item success."); return ESP_OK; } esp_err_t zh_vector_fill_range(zh_vector_t *vector, uint16_t start, uint16_t end, void *item) { ZH_VECTOR_LOGI("Filling range of items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Filling range fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Filling range fail. Item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Filling range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Filling range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Filling range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Filling range fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { memcpy(vector->items[i], item, vector->unit); } ZH_VECTOR_LOGI("Filling range of items in vector success."); return ESP_OK; } esp_err_t zh_vector_fill_with_generator(zh_vector_t *vector, void *(*generator)(uint16_t index)) { ZH_VECTOR_LOGI("Filling vector with generated values begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Filling vector fail. Vector is NULL."); ZH_VECTOR_CHECK(generator != NULL, ESP_ERR_INVALID_ARG, "Filling vector fail. Generator function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Filling vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { void *generated_value = generator(i); ZH_VECTOR_CHECK(generated_value != NULL, ESP_ERR_NO_MEM, "Filling vector fail. Generator returned NULL."); memcpy(vector->items[i], generated_value, vector->unit); } ZH_VECTOR_LOGI("Filling vector with generated values success."); return ESP_OK; } bool zh_vector_is_sorted(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Checking if vector is sorted begin."); ZH_VECTOR_CHECK(vector != NULL, false, "Checking if vector is sorted fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, false, "Checking if vector is sorted fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, false, "Checking if vector is sorted fail. Vector not initialized."); for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i - 1], vector->items[i]) > 0) { ZH_VECTOR_LOGI("Vector is not sorted."); return false; } } ZH_VECTOR_LOGI("Vector is sorted."); return true; } esp_err_t zh_vector_remove_range(zh_vector_t *vector, uint16_t start, uint16_t end) { ZH_VECTOR_LOGI("Removing range of items from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing range fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Removing range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Removing range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Removing range fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { { void *temp = vector1->items[start1 + i]; vector1->items[start1 + i] = vector2->items[start2 + i]; vector2->items[start2 + i] = temp; } ZH_VECTOR_LOGI("Swapping ranges between vectors success."); return ESP_OK; } esp_err_t zh_vector_copy_range(const zh_vector_t *src, uint16_t start, uint16_t end, zh_vector_t *dest) { ZH_VECTOR_LOGI("Copying range of items from vector begin."); ZH_VECTOR_CHECK(src != NULL, ESP_ERR_INVALID_ARG, "Copying range fail. Source vector is NULL."); ZH_VECTOR_CHECK(dest != NULL, ESP_ERR_INVALID_ARG, "Copying range fail. Destination vector is NULL."); ZH_VECTOR_CHECK(src->status == true, ESP_ERR_INVALID_STATE, "Copying range fail. Source vector not initialized."); ZH_VECTOR_CHECK(dest->status == true, ESP_ERR_INVALID_STATE, "Copying range fail. Destination vector not initialized."); ZH_VECTOR_CHECK(start < src->size, ESP_FAIL, "Copying range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= src->size, ESP_FAIL, "Copying range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Copying range fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { esp_err_t err = zh_vector_push_back(dest, src->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Copying range fail. Failed to add item."); } ZH_VECTOR_LOGI("Copying range of items from vector success."); return ESP_OK; } esp_err_t zh_vector_reverse_range(zh_vector_t *vector, uint16_t start, uint16_t end) { ZH_VECTOR_LOGI("Reversing range of items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Reversing range fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Reversing range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Reversing range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Reversing range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Reversing range fail. Start index must be less than end index."); for (uint16_t i = 0; i < (end - start) / 2; ++i) { void *temp = vector->items[start + i]; vector->items[start + i] = vector->items[end - i - 1]; vector->items[end - i - 1] = temp; } ZH_VECTOR_LOGI("Reversing range of items in vector success."); return ESP_OK; } esp_err_t zh_vector_swap(zh_vector_t *vector, uint16_t index1, uint16_t index2) { ZH_VECTOR_LOGI("Swapping items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Swapping items fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Swapping items fail. Vector not initialized."); ZH_VECTOR_CHECK(index1 < vector->size, ESP_FAIL, "Swapping items fail. Index1 out of bounds."); ZH_VECTOR_CHECK(index2 < vector->size, ESP_FAIL, "Swapping items fail. Index2 out of bounds."); void *temp = vector->items[index1]; vector->items[index1] = vector->items[index2]; vector->items[index2] = temp; ZH_VECTOR_LOGI("Swapping items in vector success."); return ESP_OK; } esp_err_t zh_vector_rotate_left(zh_vector_t *vector, uint16_t positions) { ZH_VECTOR_LOGI("Rotating vector left begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Rotating vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Rotating vector fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, ESP_FAIL, "Rotating vector fail. Vector is empty."); positions = positions % vector->size; if (positions == 0) { ZH_VECTOR_LOGI("Rotating vector left skipped. No positions to rotate."); return ESP_OK; } void **temp = heap_caps_malloc(positions * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Rotating vector fail. Memory allocation failed."); // Сохраняем первые `positions` элементов memcpy(temp, vector->items, positions * sizeof(void *)); // Сдвигаем оставшиеся элементы memmove(vector->items, vector->items + positions, (vector->size - positions) * sizeof(void *)); // Переносим сохраненные элементы в конец memcpy(vector->items + (vector->size - positions), temp, positions * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Rotating vector left success."); return ESP_OK; } esp_err_t zh_vector_rotate_right(zh_vector_t *vector, uint16_t positions) { ZH_VECTOR_LOGI("Rotating vector right begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Rotating vector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Rotating vector fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, ESP_FAIL, "Rotating vector fail. Vector is empty."); positions = positions % vector->size; if (positions == 0) { ZH_VECTOR_LOGI("Rotating vector right skipped. No positions to rotate."); return ESP_OK; } void **temp = heap_caps_malloc(positions * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Rotating vector fail. Memory allocation failed."); // Сохраняем последние `positions` элементов memcpy(temp, vector->items + (vector->size - positions), positions * sizeof(void *)); // Сдвигаем оставшиеся элементы memmove(vector->items + positions, vector->items, (vector->size - positions) * sizeof(void *)); // Переносим сохраненные элементы в начало memcpy(vector->items, temp, positions * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Rotating vector right success."); return ESP_OK; } esp_err_t zh_vector_find_duplicates(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *duplicates) { ZH_VECTOR_LOGI("Finding duplicates in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(duplicates != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Duplicates vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding duplicates fail. Vector not initialized."); ZH_VECTOR_CHECK(duplicates->status == true, ESP_ERR_INVALID_STATE, "Finding duplicates fail. Duplicates vector not initialized."); if (vector->size <= 1) { ZH_VECTOR_LOGI("Finding duplicates skipped. Vector is empty or has only one element."); return ESP_OK; } for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = i + 1; j < vector->size; ++j) { if (cmp(vector->items[i], vector->items[j]) == 0) { esp_err_t err = zh_vector_push_back(duplicates, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding duplicates fail. Failed to add duplicate."); break; } } } ZH_VECTOR_LOGI("Finding duplicates in vector success."); return ESP_OK; } /** * @brief Finds duplicates in a specified range of the vector. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param cmp Comparison function to compare items. * @param duplicates Pointer to the vector to store duplicates. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_duplicates_in_range(zh_vector_t *vector, uint16_t start, uint16_t end, int (*cmp)(const void *, const void *), zh_vector_t *duplicates) { ZH_VECTOR_LOGI("Finding duplicates in range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(duplicates != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Duplicates vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding duplicates fail. Vector not initialized."); ZH_VECTOR_CHECK(duplicates->status == true, ESP_ERR_INVALID_STATE, "Finding duplicates fail. Duplicates vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Finding duplicates fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Finding duplicates fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Finding duplicates fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { for (uint16_t j = i + 1; j < end; ++j) { if (cmp(vector->items[i], vector->items[j]) == 0) { esp_err_t err = zh_vector_push_back(duplicates, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding duplicates fail. Failed to add duplicate."); break; } } } ZH_VECTOR_LOGI("Finding duplicates in range of vector success."); return ESP_OK; } esp_err_t zh_vector_sort(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Sorting vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Sorting vector fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Sorting vector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Sorting vector fail. Vector not initialized."); if (vector->size <= 1) { ZH_VECTOR_LOGI("Sorting vector skipped. Vector is empty or has only one element."); return ESP_OK; } qsort(vector->items, vector->size, sizeof(void *), cmp); ZH_VECTOR_LOGI("Sorting vector success."); return ESP_OK; } uint16_t zh_vector_count(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Counting occurrences of item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, 0, "Counting occurrences fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, 0, "Counting occurrences fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, 0, "Counting occurrences fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, 0, "Counting occurrences fail. Vector not initialized."); uint16_t count = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) == 0) { count++; } } ZH_VECTOR_LOGI("Counting occurrences of item in vector success. Count: %d.", count); return count; } esp_err_t zh_vector_remove_all(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing all occurrences of item from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing all occurrences fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Removing all occurrences fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing all occurrences fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing all occurrences fail. Vector not initialized."); uint16_t write_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) != 0) { if (write_index != i) { vector->items[write_index] = vector->items[i]; } write_index++; } else { heap_caps_free(vector->items[i]); } } for (uint16_t i = write_index; i < vector->size; ++i) { vector->items[i] = NULL; } vector->size = write_index; ZH_VECTOR_LOGI("Removing all occurrences of item from vector success. New size: %d.", vector->size); return ESP_OK; } int zh_vector_find_first_of(zh_vector_t *vector, zh_vector_t *other, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first matching item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding first matching item fail. Vector is NULL."); ZH_VECTOR_CHECK(other != NULL, -1, "Finding first matching item fail. Other vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding first matching item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding first matching item fail. Vector not initialized."); ZH_VECTOR_CHECK(other->status == true, -1, "Finding first matching item fail. Other vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = 0; j < other->size; ++j) { if (cmp(vector->items[i], other->items[j]) == 0) { ZH_VECTOR_LOGI("First matching item found in vector at index: %d.", i); return i; } } } ZH_VECTOR_LOGI("No matching item found in vector."); return -1; } int zh_vector_find_last_of(zh_vector_t *vector, zh_vector_t *other, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding last matching item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding last matching item fail. Vector is NULL."); ZH_VECTOR_CHECK(other != NULL, -1, "Finding last matching item fail. Other vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding last matching item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding last matching item fail. Vector not initialized."); ZH_VECTOR_CHECK(other->status == true, -1, "Finding last matching item fail. Other vector not initialized."); for (int i = vector->size - 1; i >= 0; --i) { for (uint16_t j = 0; j < other->size; ++j) { if (cmp(vector->items[i], other->items[j]) == 0) { ZH_VECTOR_LOGI("Last matching item found in vector at index: %d.", i); return i; } } } ZH_VECTOR_LOGI("No matching item found in vector."); return -1; } int zh_vector_find_mismatch(zh_vector_t *vector1, zh_vector_t *vector2, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first mismatch between two vectors begin."); ZH_VECTOR_CHECK(vector1 != NULL, -1, "Finding mismatch fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, -1, "Finding mismatch fail. Second vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding mismatch fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector1->status == true, -1, "Finding mismatch fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, -1, "Finding mismatch fail. Second vector not initialized."); uint16_t min_size = (vector1->size < vector2->size) ? vector1->size : vector2->size; for (uint16_t i = 0; i < min_size; ++i) { if (cmp(vector1->items[i], vector2->items[i]) != 0) { ZH_VECTOR_LOGI("Mismatch found at index: %d.", i); return i; } } ZH_VECTOR_LOGI("No mismatch found between vectors."); return -1; } esp_err_t zh_vector_transform(zh_vector_t *vector, void *(*func)(void *item)) { ZH_VECTOR_LOGI("Transforming vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Transforming vector fail. Vector is NULL."); ZH_VECTOR_CHECK(func != NULL, ESP_ERR_INVALID_ARG, "Transforming vector fail. Function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Transforming vector fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { vector->items[i] = func(vector->items[i]); } ZH_VECTOR_LOGI("Transforming vector success."); return ESP_OK; } /** * @brief Transforms items in a specified range of the vector using a user-defined function. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param func Transformation function to apply to each item. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_transform_range(zh_vector_t *vector, uint16_t start, uint16_t end, void *(*func)(void *item)) { ZH_VECTOR_LOGI("Transforming range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Transforming range fail. Vector is NULL."); ZH_VECTOR_CHECK(func != NULL, ESP_ERR_INVALID_ARG, "Transforming range fail. Function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Transforming range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Transforming range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Transforming range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Transforming range fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { vector->items[i] = func(vector->items[i]); } ZH_VECTOR_LOGI("Transforming range of vector success."); return ESP_OK; } /** * @brief Finds the first occurrence of a subvector in the vector. * * @param vector Pointer to the vector. * @param subvector Pointer to the subvector to find. * @param cmp Comparison function to compare items. * @return Index of the first occurrence of the subvector, or -1 if not found. */ int zh_vector_find_subvector(zh_vector_t *vector, zh_vector_t *subvector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding subvector in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding subvector fail. Vector is NULL."); ZH_VECTOR_CHECK(subvector != NULL, -1, "Finding subvector fail. Subvector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding subvector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding subvector fail. Vector not initialized."); ZH_VECTOR_CHECK(subvector->status == true, -1, "Finding subvector fail. Subvector not initialized."); ZH_VECTOR_CHECK(subvector->size <= vector->size, -1, "Finding subvector fail. Subvector is larger than vector."); for (uint16_t i = 0; i <= vector->size - subvector->size; ++i) { bool match = true; for (uint16_t j = 0; j < subvector->size; ++j) { if (cmp(vector->items[i + j], subvector->items[j]) != 0) { match = false; break; } } if (match) { ZH_VECTOR_LOGI("Subvector found at index: %d.", i); return i; } } ZH_VECTOR_LOGI("Subvector not found in vector."); return -1; } int zh_vector_find_subvector(zh_vector_t *vector, zh_vector_t *subvector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding subvector in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding subvector fail. Vector is NULL."); ZH_VECTOR_CHECK(subvector != NULL, -1, "Finding subvector fail. Subvector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding subvector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding subvector fail. Vector not initialized."); ZH_VECTOR_CHECK(subvector->status == true, -1, "Finding subvector fail. Subvector not initialized."); ZH_VECTOR_CHECK(subvector->size <= vector->size, -1, "Finding subvector fail. Subvector is larger than vector."); for (uint16_t i = 0; i <= vector->size - subvector->size; ++i) { bool match = true; for (uint16_t j = 0; j < subvector->size; ++j) { if (cmp(vector->items[i + j], subvector->items[j]) != 0) { match = false; break; } } if (match) { ZH_VECTOR_LOGI("Subvector found at index: %d.", i); return i; } } ZH_VECTOR_LOGI("Subvector not found in vector."); return -1; } int zh_vector_find_max(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding maximum item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding maximum fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding maximum fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding maximum fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, -1, "Finding maximum fail. Vector is empty."); int max_index = 0; for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i], vector->items[max_index]) > 0) { max_index = i; } } ZH_VECTOR_LOGI("Maximum item found in vector at index: %d.", max_index); return max_index; } int zh_vector_find_min(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding minimum item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding minimum fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding minimum fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding minimum fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, -1, "Finding minimum fail. Vector is empty."); int min_index = 0; for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i], vector->items[min_index]) < 0) { min_index = i; } } ZH_VECTOR_LOGI("Minimum item found in vector at index: %d.", min_index); return min_index; } esp_err_t zh_vector_replace_range(zh_vector_t *vector, uint16_t start, uint16_t end, void *new_item) { ZH_VECTOR_LOGI("Replacing range of items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Replacing range fail. Vector is NULL."); ZH_VECTOR_CHECK(new_item != NULL, ESP_ERR_INVALID_ARG, "Replacing range fail. New item is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Replacing range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Replacing range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Replacing range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Replacing range fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { heap_caps_free(vector->items[i]); vector->items[i] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(vector->items[i] != NULL, ESP_ERR_NO_MEM, "Replacing range fail. Memory allocation failed."); memcpy(vector->items[i], new_item, vector->unit); } ZH_VECTOR_LOGI("Replacing range of items in vector success."); return ESP_OK; } bool zh_vector_is_equal(zh_vector_t *vector1, zh_vector_t *vector2, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Checking if two vectors are equal begin."); ZH_VECTOR_CHECK(vector1 != NULL, false, "Checking equality fail. First vector is NULL."); ZH_VECTOR_CHECK(vector2 != NULL, false, "Checking equality fail. Second vector is NULL."); ZH_VECTOR_CHECK(vector1->status == true, false, "Checking equality fail. First vector not initialized."); ZH_VECTOR_CHECK(vector2->status == true, false, "Checking equality fail. Second vector not initialized."); ZH_VECTOR_CHECK(cmp != NULL, false, "Checking equality fail. Comparison function is NULL."); if (vector1->size != vector2->size) { ZH_VECTOR_LOGI("Vectors are not equal. Sizes differ."); return false; } for (uint16_t i = 0; i < vector1->size; ++i) { if (cmp(vector1->items[i], vector2->items[i]) != 0) { ZH_VECTOR_LOGI("Vectors are not equal. Items differ at index: %d.", i); return false; } } ZH_VECTOR_LOGI("Vectors are equal."); return true; } /** * @brief Performs a binary search for an item in a sorted vector. * * @param vector Pointer to the vector. * @param item Pointer to the item to search for. * @param cmp Comparison function to compare items. * @return Index of the found item, or -1 if the item is not found. */ int zh_vector_binary_search(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Performing binary search in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Binary search fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, -1, "Binary search fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Binary search fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Binary search fail. Vector not initialized."); int left = 0; int right = vector->size - 1; while (left <= right) { int mid = left + (right - left) / 2; int result = cmp(item, vector->items[mid]); if (result == 0) { ZH_VECTOR_LOGI("Item found in vector at index: %d.", mid); return mid; } else if (result < 0) { right = mid - 1; } else { left = mid + 1; } } ZH_VECTOR_LOGI("Item not found in vector."); return -1; } /** * @brief Finds all items in the vector that match the specified item. * * @param vector Pointer to the vector. * @param item Pointer to the item to match. * @param cmp Comparison function to compare items. * @param matches Pointer to the vector to store matching items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_matches(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *), zh_vector_t *matches) { ZH_VECTOR_LOGI("Finding all matches in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding matches fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, ESP_ERR_INVALID_ARG, "Finding matches fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding matches fail. Comparison function is NULL."); ZH_VECTOR_CHECK(matches != NULL, ESP_ERR_INVALID_ARG, "Finding matches fail. Matches vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding matches fail. Vector not initialized."); ZH_VECTOR_CHECK(matches->status == true, ESP_ERR_INVALID_STATE, "Finding matches fail. Matches vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) == 0) { esp_err_t err = zh_vector_push_back(matches, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding matches fail. Failed to add item to matches vector."); } } ZH_VECTOR_LOGI("Finding all matches in vector success."); return ESP_OK; } /** * @brief Splits the vector into multiple parts of specified size. * * @param vector Pointer to the vector. * @param part_size Size of each part. * @param parts Pointer to an array of vectors to store the parts (allocated dynamically). * @param part_count Pointer to store the number of parts. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_split(zh_vector_t *vector, uint16_t part_size, zh_vector_t **parts, uint16_t *part_count) { ZH_VECTOR_LOGI("Splitting vector into parts begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. Vector is NULL."); ZH_VECTOR_CHECK(part_size > 0, ESP_ERR_INVALID_ARG, "Splitting vector fail. Part size must be greater than 0."); ZH_VECTOR_CHECK(parts != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. Parts pointer is NULL."); ZH_VECTOR_CHECK(part_count != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. Part count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Splitting vector fail. Vector not initialized."); *part_count = (vector->size + part_size - 1) / part_size; *parts = heap_caps_malloc(*part_count * sizeof(zh_vector_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*parts != NULL, ESP_ERR_NO_MEM, "Splitting vector fail. Memory allocation failed."); for (uint16_t i = 0; i < *part_count; ++i) { esp_err_t err = zh_vector_init(&(*parts)[i], vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Splitting vector fail. Failed to initialize part vector."); uint16_t start = i * part_size; uint16_t end = (start + part_size > vector->size) ? vector->size : start + part_size; for (uint16_t j = start; j < end; ++j) { err = zh_vector_push_back(&(*parts)[i], vector->items[j]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Splitting vector fail. Failed to add item to part vector."); } } ZH_VECTOR_LOGI("Splitting vector into parts success. Number of parts: %d.", *part_count); return ESP_OK; } /** * @brief Flattens a vector of vectors into a single vector. * * @param vector Pointer to the vector of vectors. * @param result Pointer to the resulting flattened vector. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_flatten(zh_vector_t *vector, zh_vector_t *result) { ZH_VECTOR_LOGI("Flattening vector of vectors begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Flattening vector fail. Vector is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Flattening vector fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Flattening vector fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Flattening vector fail. Result vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { zh_vector_t *subvector = (zh_vector_t *)vector->items[i]; ZH_VECTOR_CHECK(subvector != NULL, ESP_ERR_INVALID_ARG, "Flattening vector fail. Subvector is NULL."); ZH_VECTOR_CHECK(subvector->status == true, ESP_ERR_INVALID_STATE, "Flattening vector fail. Subvector not initialized."); for (uint16_t j = 0; j < subvector->size; ++j) { esp_err_t err = zh_vector_push_back(result, subvector->items[j]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Flattening vector fail. Failed to add item to result vector."); } } ZH_VECTOR_LOGI("Flattening vector of vectors success."); return ESP_OK; } /** * @brief Rotates a specified range of the vector by the given number of positions. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param positions Number of positions to rotate (positive for right, negative for left). * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_rotate_range(zh_vector_t *vector, uint16_t start, uint16_t end, int16_t positions) { ZH_VECTOR_LOGI("Rotating range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Rotating range fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Rotating range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Rotating range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Rotating range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Rotating range fail. Start index must be less than end index."); uint16_t range_size = end - start; positions = positions % range_size; if (positions < 0) { positions += range_size; } if (positions == 0) { ZH_VECTOR_LOGI("Rotating range skipped. No positions to rotate."); return ESP_OK; } void **temp = heap_caps_malloc(range_size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Rotating range fail. Memory allocation failed."); for (uint16_t i = 0; i < range_size; ++i) { temp[(i + positions) % range_size] = vector->items[start + i]; } memcpy(vector->items + start, temp, range_size * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Rotating range of vector success."); return ESP_OK; } /** * @brief Rotates a subvector (subarray) of the vector by the given number of positions. * * @param vector Pointer to the vector. * @param start Start index of the subvector. * @param end End index of the subvector (exclusive). * @param positions Number of positions to rotate (positive for right, negative for left). * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_rotate_subvector(zh_vector_t *vector, uint16_t start, uint16_t end, int16_t positions) { ZH_VECTOR_LOGI("Rotating subvector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Rotating subvector fail. Vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Rotating subvector fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Rotating subvector fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Rotating subvector fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Rotating subvector fail. Start index must be less than end index."); uint16_t range_size = end - start; positions = positions % range_size; if (positions < 0) { positions += range_size; } if (positions == 0) { ZH_VECTOR_LOGI("Rotating subvector skipped. No positions to rotate."); return ESP_OK; } void **temp = heap_caps_malloc(range_size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Rotating subvector fail. Memory allocation failed."); for (uint16_t i = 0; i < range_size; ++i) { temp[(i + positions) % range_size] = vector->items[start + i]; } memcpy(vector->items + start, temp, range_size * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Rotating subvector success."); return ESP_OK; } /** * @brief Finds the first item in the vector that does not match any item in another vector. * * @param vector Pointer to the vector. * @param other Pointer to the other vector. * @param cmp Comparison function to compare items. * @return Index of the first non-matching item, or -1 if all items match. */ int zh_vector_find_first_not_of(zh_vector_t *vector, zh_vector_t *other, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first non-matching item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding first non-matching item fail. Vector is NULL."); ZH_VECTOR_CHECK(other != NULL, -1, "Finding first non-matching item fail. Other vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding first non-matching item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding first non-matching item fail. Vector not initialized."); ZH_VECTOR_CHECK(other->status == true, -1, "Finding first non-matching item fail. Other vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { bool found = false; for (uint16_t j = 0; j < other->size; ++j) { if (cmp(vector->items[i], other->items[j]) == 0) { found = true; break; } } if (!found) { ZH_VECTOR_LOGI("First non-matching item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("All items in vector match items in other vector."); return -1; } /** * @brief Finds the last item in the vector that does not match any item in another vector. * * @param vector Pointer to the vector. * @param other Pointer to the other vector. * @param cmp Comparison function to compare items. * @return Index of the last non-matching item, or -1 if all items match. */ int zh_vector_find_last_not_of(zh_vector_t *vector, zh_vector_t *other, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding last non-matching item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding last non-matching item fail. Vector is NULL."); ZH_VECTOR_CHECK(other != NULL, -1, "Finding last non-matching item fail. Other vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding last non-matching item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding last non-matching item fail. Vector not initialized."); ZH_VECTOR_CHECK(other->status == true, -1, "Finding last non-matching item fail. Other vector not initialized."); for (int i = vector->size - 1; i >= 0; --i) { bool found = false; for (uint16_t j = 0; j < other->size; ++j) { if (cmp(vector->items[i], other->items[j]) == 0) { found = true; break; } } if (!found) { ZH_VECTOR_LOGI("Last non-matching item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("All items in vector match items in other vector."); return -1; } /** * @brief Permutes the items in the vector according to the specified order. * * @param vector Pointer to the vector. * @param order Array of indices specifying the new order. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_permute(zh_vector_t *vector, const uint16_t *order) { ZH_VECTOR_LOGI("Permuting vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Permuting vector fail. Vector is NULL."); ZH_VECTOR_CHECK(order != NULL, ESP_ERR_INVALID_ARG, "Permuting vector fail. Order array is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Permuting vector fail. Vector not initialized."); void **temp = heap_caps_malloc(vector->size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Permuting vector fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { temp[i] = vector->items[order[i]]; } memcpy(vector->items, temp, vector->size * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Permuting vector success."); return ESP_OK; } /** * @brief Permutes the items in a specified range of the vector according to the given order. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param order Array of indices specifying the new order within the range. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_permute_range(zh_vector_t *vector, uint16_t start, uint16_t end, const uint16_t *order) { ZH_VECTOR_LOGI("Permuting range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Permuting range fail. Vector is NULL."); ZH_VECTOR_CHECK(order != NULL, ESP_ERR_INVALID_ARG, "Permuting range fail. Order array is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Permuting range fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Permuting range fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Permuting range fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Permuting range fail. Start index must be less than end index."); uint16_t range_size = end - start; void **temp = heap_caps_malloc(range_size * sizeof(void *), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(temp != NULL, ESP_ERR_NO_MEM, "Permuting range fail. Memory allocation failed."); for (uint16_t i = 0; i < range_size; ++i) { temp[i] = vector->items[start + order[i]]; } memcpy(vector->items + start, temp, range_size * sizeof(void *)); heap_caps_free(temp); ZH_VECTOR_LOGI("Permuting range of vector success."); return ESP_OK; } /** * @brief Generates values for the vector using a generator function. * * @param vector Pointer to the vector. * @param generator Generator function that takes an index and returns a value. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_generate(zh_vector_t *vector, void *(*generator)(uint16_t index)) { ZH_VECTOR_LOGI("Generating values for vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Generating values fail. Vector is NULL."); ZH_VECTOR_CHECK(generator != NULL, ESP_ERR_INVALID_ARG, "Generating values fail. Generator function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Generating values fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { void *value = generator(i); ZH_VECTOR_CHECK(value != NULL, ESP_ERR_NO_MEM, "Generating values fail. Generator returned NULL."); memcpy(vector->items[i], value, vector->unit); } ZH_VECTOR_LOGI("Generating values for vector success."); return ESP_OK; } /** * @brief Finds the first item in the vector that is not within a specified range. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param cmp Comparison function to compare items. * @return Index of the first non-matching item, or -1 if all items match. */ int zh_vector_find_first_not_in_range(zh_vector_t *vector, uint16_t start, uint16_t end, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first non-matching item in range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding first non-matching item fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding first non-matching item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding first non-matching item fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, -1, "Finding first non-matching item fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, -1, "Finding first non-matching item fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, -1, "Finding first non-matching item fail. Start index must be less than end index."); for (uint16_t i = 0; i < vector->size; ++i) { if (i < start || i >= end) { if (cmp(vector->items[i], vector->items[start]) != 0) { ZH_VECTOR_LOGI("First non-matching item found in vector at index: %d.", i); return i; } } } ZH_VECTOR_LOGI("All items in vector match the range."); return -1; } /** * @brief Finds all ranges in the vector that satisfy a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @param ranges Pointer to an array of ranges (allocated dynamically). * @param count Pointer to store the number of found ranges. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_ranges(zh_vector_t *vector, bool (*predicate)(const void *), uint16_t **ranges, uint16_t *count) { ZH_VECTOR_LOGI("Finding all ranges in vector with predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding ranges fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Finding ranges fail. Predicate is NULL."); ZH_VECTOR_CHECK(ranges != NULL, ESP_ERR_INVALID_ARG, "Finding ranges fail. Ranges pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding ranges fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding ranges fail. Vector not initialized."); *count = 0; *ranges = heap_caps_malloc(vector->size * 2 * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*ranges != NULL, ESP_ERR_NO_MEM, "Finding ranges fail. Memory allocation failed."); uint16_t start = 0; bool in_range = false; for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { if (!in_range) { start = i; in_range = true; } } else { if (in_range) { (*ranges)[(*count)++] = start; (*ranges)[(*count)++] = i; in_range = false; } } } if (in_range) { (*ranges)[(*count)++] = start; (*ranges)[(*count)++] = vector->size; } ZH_VECTOR_LOGI("Finding all ranges in vector with predicate success. Found: %d ranges.", *count / 2); return ESP_OK; } /** * @brief Finds the first item in the vector that matches any item in a specified range of another vector. * * @param vector Pointer to the vector. * @param other Pointer to the other vector. * @param start Start index of the range in the other vector. * @param end End index of the range in the other vector (exclusive). * @param cmp Comparison function to compare items. * @return Index of the first matching item, or -1 if no match is found. */ int zh_vector_find_first_of_range(zh_vector_t *vector, zh_vector_t *other, uint16_t start, uint16_t end, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first matching item in range of another vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding first matching item fail. Vector is NULL."); ZH_VECTOR_CHECK(other != NULL, -1, "Finding first matching item fail. Other vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding first matching item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding first matching item fail. Vector not initialized."); ZH_VECTOR_CHECK(other->status == true, -1, "Finding first matching item fail. Other vector not initialized."); ZH_VECTOR_CHECK(start < other->size, -1, "Finding first matching item fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= other->size, -1, "Finding first matching item fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, -1, "Finding first matching item fail. Start index must be less than end index."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = start; j < end; ++j) { if (cmp(vector->items[i], other->items[j]) == 0) { ZH_VECTOR_LOGI("First matching item found in vector at index: %d.", i); return i; } } } ZH_VECTOR_LOGI("No matching item found in vector."); return -1; } /** * @brief Finds all items in the vector that do not match any item in another vector. * * @param vector Pointer to the vector. * @param other Pointer to the other vector. * @param cmp Comparison function to compare items. * @param indices Pointer to an array of indices (allocated dynamically). * @param count Pointer to store the number of found indices. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_not_of(zh_vector_t *vector, zh_vector_t *other, int (*cmp)(const void *, const void *), uint16_t **indices, uint16_t *count) { ZH_VECTOR_LOGI("Finding all non-matching items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding non-matching items fail. Vector is NULL."); ZH_VECTOR_CHECK(other != NULL, ESP_ERR_INVALID_ARG, "Finding non-matching items fail. Other vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding non-matching items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(indices != NULL, ESP_ERR_INVALID_ARG, "Finding non-matching items fail. Indices pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding non-matching items fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding non-matching items fail. Vector not initialized."); ZH_VECTOR_CHECK(other->status == true, ESP_ERR_INVALID_STATE, "Finding non-matching items fail. Other vector not initialized."); *count = 0; *indices = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*indices != NULL, ESP_ERR_NO_MEM, "Finding non-matching items fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { bool found = false; for (uint16_t j = 0; j < other->size; ++j) { if (cmp(vector->items[i], other->items[j]) == 0) { found = true; break; } } if (!found) { (*indices)[(*count)++] = i; } } ZH_VECTOR_LOGI("Finding all non-matching items in vector success. Found: %d.", *count); return ESP_OK; } /** * @brief Finds the first item in the vector that is not equal to the specified item. * * @param vector Pointer to the vector. * @param item Pointer to the item to compare. * @param cmp Comparison function to compare items. * @return Index of the first non-equal item, or -1 if all items are equal. */ int zh_vector_find_first_not_equal(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first non-equal item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding first non-equal item fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, -1, "Finding first non-equal item fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding first non-equal item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding first non-equal item fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], item) != 0) { ZH_VECTOR_LOGI("First non-equal item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("All items in vector are equal to the specified item."); return -1; } /** * @brief Finds the last item in the vector that is not equal to the specified item. * * @param vector Pointer to the vector. * @param item Pointer to the item to compare. * @param cmp Comparison function to compare items. * @return Index of the last non-equal item, or -1 if all items are equal. */ int zh_vector_find_last_not_equal(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding last non-equal item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding last non-equal item fail. Vector is NULL."); ZH_VECTOR_CHECK(item != NULL, -1, "Finding last non-equal item fail. Item is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding last non-equal item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding last non-equal item fail. Vector not initialized."); for (int i = vector->size - 1; i >= 0; --i) { if (cmp(vector->items[i], item) != 0) { ZH_VECTOR_LOGI("Last non-equal item found in vector at index: %d.", i); return i; } } ZH_VECTOR_LOGI("All items in vector are equal to the specified item."); return -1; } /** * @brief Partitions the vector into two parts based on a comparison with a specified value. * * @param vector Pointer to the vector. * @param value Pointer to the value to compare. * @param cmp Comparison function to compare items. * @param less_than Pointer to the vector to store items less than the value. * @param greater_or_equal Pointer to the vector to store items greater than or equal to the value. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_partition_by_value(zh_vector_t *vector, void *value, int (*cmp)(const void *, const void *), zh_vector_t *less_than, zh_vector_t *greater_or_equal) { ZH_VECTOR_LOGI("Partitioning vector by value begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Vector is NULL."); ZH_VECTOR_CHECK(value != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Value is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(less_than != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Less-than vector is NULL."); ZH_VECTOR_CHECK(greater_or_equal != NULL, ESP_ERR_INVALID_ARG, "Partitioning vector fail. Greater-or-equal vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Partitioning vector fail. Vector not initialized."); esp_err_t err = zh_vector_init(less_than, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning vector fail. Failed to initialize less-than vector."); err = zh_vector_init(greater_or_equal, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning vector fail. Failed to initialize greater-or-equal vector."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], value) < 0) { err = zh_vector_push_back(less_than, vector->items[i]); } else { err = zh_vector_push_back(greater_or_equal, vector->items[i]); } ZH_VECTOR_CHECK(err == ESP_OK, err, "Partitioning vector fail. Failed to add item."); } ZH_VECTOR_LOGI("Partitioning vector by value success."); return ESP_OK; } /** * @brief Generates values for a specified range of the vector using a generator function. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param generator Generator function that takes an index and returns a value. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_generate_range(zh_vector_t *vector, uint16_t start, uint16_t end, void *(*generator)(uint16_t index)) { ZH_VECTOR_LOGI("Generating values for range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Generating values fail. Vector is NULL."); ZH_VECTOR_CHECK(generator != NULL, ESP_ERR_INVALID_ARG, "Generating values fail. Generator function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Generating values fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Generating values fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Generating values fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Generating values fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { void *value = generator(i); ZH_VECTOR_CHECK(value != NULL, ESP_ERR_NO_MEM, "Generating values fail. Generator returned NULL."); memcpy(vector->items[i], value, vector->unit); } ZH_VECTOR_LOGI("Generating values for range of vector success."); return ESP_OK; } /** * @brief Finds the first duplicate item in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @return Index of the first duplicate item, or -1 if no duplicates are found. */ int zh_vector_find_first_duplicate(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding first duplicate in vector begin."); ZH_VECTOR_CHECK(vector != NULL, -1, "Finding first duplicate fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, -1, "Finding first duplicate fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, -1, "Finding first duplicate fail. Vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = i + 1; j < vector->size; ++j) { if (cmp(vector->items[i], vector->items[j]) == 0) { ZH_VECTOR_LOGI("First duplicate found in vector at index: %d.", i); return i; } } } ZH_VECTOR_LOGI("No duplicates found in vector."); return -1; } /** * @brief Finds all unique items in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param unique Pointer to the vector to store unique items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_unique(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *unique) { ZH_VECTOR_LOGI("Finding unique items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding unique items fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding unique items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(unique != NULL, ESP_ERR_INVALID_ARG, "Finding unique items fail. Unique vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding unique items fail. Vector not initialized."); ZH_VECTOR_CHECK(unique->status == true, ESP_ERR_INVALID_STATE, "Finding unique items fail. Unique vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { bool is_unique = true; for (uint16_t j = 0; j < unique->size; ++j) { if (cmp(vector->items[i], unique->items[j]) == 0) { is_unique = false; break; } } if (is_unique) { esp_err_t err = zh_vector_push_back(unique, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding unique items fail. Failed to add item."); } } ZH_VECTOR_LOGI("Finding unique items in vector success."); return ESP_OK; } /** * @brief Removes duplicate items in a specified range of the vector. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param cmp Comparison function to compare items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_remove_duplicates_in_range(zh_vector_t *vector, uint16_t start, uint16_t end, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing duplicates in range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing duplicates fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, ESP_FAIL, "Removing duplicates fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, ESP_FAIL, "Removing duplicates fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, ESP_FAIL, "Removing duplicates fail. Start index must be less than end index."); for (uint16_t i = start; i < end; ++i) { for (uint16_t j = i + 1; j < end;) { if (cmp(vector->items[i], vector->items[j]) == 0) { zh_vector_remove(vector, j); end--; // Уменьшаем конец диапазона после удаления } else { j++; } } } ZH_VECTOR_LOGI("Removing duplicates in range of vector success."); return ESP_OK; } /** * @brief Finds the longest subvector in the vector that satisfies a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @param start Pointer to store the start index of the subvector. * @param length Pointer to store the length of the subvector. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_longest_subvector(zh_vector_t *vector, bool (*predicate)(const void *), uint16_t *start, uint16_t *length) { ZH_VECTOR_LOGI("Finding longest subvector in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding longest subvector fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Finding longest subvector fail. Predicate is NULL."); ZH_VECTOR_CHECK(start != NULL, ESP_ERR_INVALID_ARG, "Finding longest subvector fail. Start pointer is NULL."); ZH_VECTOR_CHECK(length != NULL, ESP_ERR_INVALID_ARG, "Finding longest subvector fail. Length pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding longest subvector fail. Vector not initialized."); uint16_t max_start = 0, max_length = 0; uint16_t current_start = 0, current_length = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { if (current_length == 0) { current_start = i; } current_length++; } else { if (current_length > max_length) { max_start = current_start; max_length = current_length; } current_length = 0; } } if (current_length > max_length) { max_start = current_start; max_length = current_length; } *start = max_start; *length = max_length; ZH_VECTOR_LOGI("Finding longest subvector in vector success. Start: %d, Length: %d.", max_start, max_length); return ESP_OK; } /** * @brief Finds all duplicate items in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param duplicates Pointer to the vector to store duplicate items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_duplicates(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *duplicates) { ZH_VECTOR_LOGI("Finding all duplicates in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(duplicates != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Duplicates vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding duplicates fail. Vector not initialized."); ZH_VECTOR_CHECK(duplicates->status == true, ESP_ERR_INVALID_STATE, "Finding duplicates fail. Duplicates vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { for (uint16_t j = i + 1; j < vector->size; ++j) { if (cmp(vector->items[i], vector->items[j]) == 0) { esp_err_t err = zh_vector_push_back(duplicates, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding duplicates fail. Failed to add duplicate."); break; } } } ZH_VECTOR_LOGI("Finding all duplicates in vector success."); return ESP_OK; } /** * @brief Finds the most frequent item in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param most_frequent Pointer to store the most frequent item. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_most_frequent(zh_vector_t *vector, int (*cmp)(const void *, const void *), void **most_frequent) { ZH_VECTOR_LOGI("Finding most frequent item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding most frequent item fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding most frequent item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(most_frequent != NULL, ESP_ERR_INVALID_ARG, "Finding most frequent item fail. Output pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding most frequent item fail. Vector not initialized."); uint16_t max_count = 0; *most_frequent = NULL; for (uint16_t i = 0; i < vector->size; ++i) { uint16_t count = 0; for (uint16_t j = 0; j < vector->size; ++j) { if (cmp(vector->items[i], vector->items[j]) == 0) { count++; } } if (count > max_count) { max_count = count; *most_frequent = vector->items[i]; } } ZH_VECTOR_LOGI("Finding most frequent item in vector success. Count: %d.", max_count); return ESP_OK; } /** * @brief Splits the vector into two parts based on a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @param true_part Pointer to the vector to store items satisfying the predicate. * @param false_part Pointer to the vector to store items not satisfying the predicate. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_split_by_predicate(zh_vector_t *vector, bool (*predicate)(const void *), zh_vector_t *true_part, zh_vector_t *false_part) { ZH_VECTOR_LOGI("Splitting vector by predicate begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. Predicate is NULL."); ZH_VECTOR_CHECK(true_part != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. True part is NULL."); ZH_VECTOR_CHECK(false_part != NULL, ESP_ERR_INVALID_ARG, "Splitting vector fail. False part is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Splitting vector fail. Vector not initialized."); esp_err_t err = zh_vector_init(true_part, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Splitting vector fail. Failed to initialize true part."); err = zh_vector_init(false_part, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Splitting vector fail. Failed to initialize false part."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { err = zh_vector_push_back(true_part, vector->items[i]); } else { err = zh_vector_push_back(false_part, vector->items[i]); } ZH_VECTOR_CHECK(err == ESP_OK, err, "Splitting vector fail. Failed to add item."); } ZH_VECTOR_LOGI("Splitting vector by predicate success."); return ESP_OK; } /** * @brief Finds the longest sequence of identical items in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param start Pointer to store the start index of the sequence. * @param length Pointer to store the length of the sequence. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_longest_sequence(zh_vector_t *vector, int (*cmp)(const void *, const void *), uint16_t *start, uint16_t *length) { ZH_VECTOR_LOGI("Finding longest sequence in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding longest sequence fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding longest sequence fail. Comparison function is NULL."); ZH_VECTOR_CHECK(start != NULL, ESP_ERR_INVALID_ARG, "Finding longest sequence fail. Start pointer is NULL."); ZH_VECTOR_CHECK(length != NULL, ESP_ERR_INVALID_ARG, "Finding longest sequence fail. Length pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding longest sequence fail. Vector not initialized."); uint16_t max_start = 0, max_length = 0; uint16_t current_start = 0, current_length = 1; for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i], vector->items[i - 1]) == 0) { current_length++; } else { if (current_length > max_length) { max_start = current_start; max_length = current_length; } current_start = i; current_length = 1; } } if (current_length > max_length) { max_start = current_start; max_length = current_length; } *start = max_start; *length = max_length; ZH_VECTOR_LOGI("Finding longest sequence in vector success. Start: %d, Length: %d.", max_start, max_length); return ESP_OK; } /** * @brief Finds all occurrences of a subvector in the vector. * * @param vector Pointer to the vector. * @param subvector Pointer to the subvector to find. * @param cmp Comparison function to compare items. * @param indices Pointer to an array of starting indices (allocated dynamically). * @param count Pointer to store the number of found occurrences. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_subvectors(zh_vector_t *vector, zh_vector_t *subvector, int (*cmp)(const void *, const void *), uint16_t **indices, uint16_t *count) { ZH_VECTOR_LOGI("Finding all occurrences of subvector in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Vector is NULL."); ZH_VECTOR_CHECK(subvector != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Subvector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Comparison function is NULL."); ZH_VECTOR_CHECK(indices != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Indices pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding subvector fail. Vector not initialized."); ZH_VECTOR_CHECK(subvector->status == true, ESP_ERR_INVALID_STATE, "Finding subvector fail. Subvector not initialized."); ZH_VECTOR_CHECK(subvector->size <= vector->size, ESP_FAIL, "Finding subvector fail. Subvector is larger than vector."); *count = 0; *indices = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*indices != NULL, ESP_ERR_NO_MEM, "Finding subvector fail. Memory allocation failed."); for (uint16_t i = 0; i <= vector->size - subvector->size; ++i) { bool match = true; for (uint16_t j = 0; j < subvector->size; ++j) { if (cmp(vector->items[i + j], subvector->items[j]) != 0) { match = false; break; } } if (match) { (*indices)[(*count)++] = i; } } ZH_VECTOR_LOGI("Finding all occurrences of subvector in vector success. Found: %d.", *count); return ESP_OK; } /** * @brief Removes all duplicate items from the vector globally. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_remove_duplicates_globally(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Removing all duplicates globally from vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Removing duplicates fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Removing duplicates fail. Vector not initialized."); zh_vector_t unique; esp_err_t err = zh_vector_init(&unique, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Removing duplicates fail. Failed to initialize unique vector."); for (uint16_t i = 0; i < vector->size; ++i) { bool is_duplicate = false; for (uint16_t j = 0; j < unique.size; ++j) { if (cmp(vector->items[i], unique.items[j]) == 0) { is_duplicate = true; break; } } if (!is_duplicate) { err = zh_vector_push_back(&unique, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Removing duplicates fail. Failed to add unique item."); } } zh_vector_clear(vector); for (uint16_t i = 0; i < unique.size; ++i) { err = zh_vector_push_back(vector, unique.items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Removing duplicates fail. Failed to copy unique item."); } zh_vector_free(&unique); ZH_VECTOR_LOGI("Removing all duplicates globally from vector success."); return ESP_OK; } /** * @brief Finds the median item in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @return Pointer to the median item, or NULL if the vector is empty. */ void *zh_vector_find_median(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding median in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding median fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding median fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding median fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, NULL, "Finding median fail. Vector is empty."); zh_vector_t sorted; esp_err_t err = zh_vector_copy(&sorted, vector); ZH_VECTOR_CHECK(err == ESP_OK, NULL, "Finding median fail. Failed to copy vector."); zh_vector_sort(&sorted, cmp); void *median = sorted.items[sorted.size / 2]; zh_vector_free(&sorted); ZH_VECTOR_LOGI("Finding median in vector success."); return median; } /** * @brief Finds the mode (most frequent item) in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @return Pointer to the mode item, or NULL if the vector is empty. */ void *zh_vector_find_mode(zh_vector_t *vector, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding mode in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding mode fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding mode fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding mode fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, NULL, "Finding mode fail. Vector is empty."); void *mode = NULL; uint16_t max_count = 0; for (uint16_t i = 0; i < vector->size; ++i) { uint16_t count = 0; for (uint16_t j = 0; j < vector->size; ++j) { if (cmp(vector->items[i], vector->items[j]) == 0) { count++; } } if (count > max_count) { max_count = count; mode = vector->items[i]; } } ZH_VECTOR_LOGI("Finding mode in vector success. Count: %d.", max_count); return mode; } /** * @brief Finds the k-th largest item in the vector. * * @param vector Pointer to the vector. * @param k The rank of the largest item to find (1-based index). * @param cmp Comparison function to compare items. * @return Pointer to the k-th largest item, or NULL if k is out of bounds. */ void *zh_vector_find_kth_largest(zh_vector_t *vector, uint16_t k, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding k-th largest item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding k-th largest fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding k-th largest fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding k-th largest fail. Vector not initialized."); ZH_VECTOR_CHECK(k > 0 && k <= vector->size, NULL, "Finding k-th largest fail. k is out of bounds."); zh_vector_t sorted; esp_err_t err = zh_vector_copy(&sorted, vector); ZH_VECTOR_CHECK(err == ESP_OK, NULL, "Finding k-th largest fail. Failed to copy vector."); zh_vector_sort(&sorted, cmp); void *kth_largest = sorted.items[sorted.size - k]; zh_vector_free(&sorted); ZH_VECTOR_LOGI("Finding k-th largest item in vector success."); return kth_largest; } /** * @brief Finds the k-th smallest item in the vector. * * @param vector Pointer to the vector. * @param k The rank of the smallest item to find (1-based index). * @param cmp Comparison function to compare items. * @return Pointer to the k-th smallest item, or NULL if k is out of bounds. */ void *zh_vector_find_kth_smallest(zh_vector_t *vector, uint16_t k, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding k-th smallest item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding k-th smallest fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding k-th smallest fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding k-th smallest fail. Vector not initialized."); ZH_VECTOR_CHECK(k > 0 && k <= vector->size, NULL, "Finding k-th smallest fail. k is out of bounds."); zh_vector_t sorted; esp_err_t err = zh_vector_copy(&sorted, vector); ZH_VECTOR_CHECK(err == ESP_OK, NULL, "Finding k-th smallest fail. Failed to copy vector."); zh_vector_sort(&sorted, cmp); void *kth_smallest = sorted.items[k - 1]; zh_vector_free(&sorted); ZH_VECTOR_LOGI("Finding k-th smallest item in vector success."); return kth_smallest; } /** * @brief Finds all items in the vector that are greater than the specified value. * * @param vector Pointer to the vector. * @param value Pointer to the value to compare. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the results. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_greater_than(zh_vector_t *vector, void *value, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding all items greater than value in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Vector is NULL."); ZH_VECTOR_CHECK(value != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Value is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Result vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], value) > 0) { esp_err_t err = zh_vector_push_back(result, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding items fail. Failed to add item to result vector."); } } ZH_VECTOR_LOGI("Finding all items greater than value in vector success."); return ESP_OK; } /** * @brief Finds all items in the vector that are less than the specified value. * * @param vector Pointer to the vector. * @param value Pointer to the value to compare. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the results. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_less_than(zh_vector_t *vector, void *value, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding all items less than value in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Vector is NULL."); ZH_VECTOR_CHECK(value != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Value is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Result vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], value) < 0) { esp_err_t err = zh_vector_push_back(result, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding items fail. Failed to add item to result vector."); } } ZH_VECTOR_LOGI("Finding all items less than value in vector success."); return ESP_OK; } /** * @brief Finds all items in the vector that are between two specified values. * * @param vector Pointer to the vector. * @param lower Pointer to the lower bound. * @param upper Pointer to the upper bound. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the results. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_between(zh_vector_t *vector, void *lower, void *upper, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding all items between two values in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Vector is NULL."); ZH_VECTOR_CHECK(lower != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Lower bound is NULL."); ZH_VECTOR_CHECK(upper != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Upper bound is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Result vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], lower) >= 0 && cmp(vector->items[i], upper) <= 0) { esp_err_t err = zh_vector_push_back(result, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding items fail. Failed to add item to result vector."); } } ZH_VECTOR_LOGI("Finding all items between two values in vector success."); return ESP_OK; } /** * @brief Finds the item in the vector that is closest to the specified value. * * @param vector Pointer to the vector. * @param value Pointer to the value to compare. * @param cmp Comparison function to compare items. * @return Pointer to the closest item, or NULL if the vector is empty. */ void *zh_vector_find_closest(zh_vector_t *vector, void *value, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding closest item in vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding closest item fail. Vector is NULL."); ZH_VECTOR_CHECK(value != NULL, NULL, "Finding closest item fail. Value is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding closest item fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding closest item fail. Vector not initialized."); ZH_VECTOR_CHECK(vector->size > 0, NULL, "Finding closest item fail. Vector is empty."); void *closest = vector->items[0]; for (uint16_t i = 1; i < vector->size; ++i) { if (cmp(vector->items[i], value) < cmp(closest, value)) { closest = vector->items[i]; } } ZH_VECTOR_LOGI("Finding closest item in vector success."); return closest; } /** * @brief Finds all peak items in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param peaks Pointer to the vector to store peak items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_peaks(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *peaks) { ZH_VECTOR_LOGI("Finding peaks in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding peaks fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding peaks fail. Comparison function is NULL."); ZH_VECTOR_CHECK(peaks != NULL, ESP_ERR_INVALID_ARG, "Finding peaks fail. Peaks vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding peaks fail. Vector not initialized."); ZH_VECTOR_CHECK(peaks->status == true, ESP_ERR_INVALID_STATE, "Finding peaks fail. Peaks vector not initialized."); for (uint16_t i = 1; i < vector->size - 1; ++i) { if (cmp(vector->items[i], vector->items[i - 1]) > 0 && cmp(vector->items[i], vector->items[i + 1]) > 0) { esp_err_t err = zh_vector_push_back(peaks, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding peaks fail. Failed to add peak."); } } ZH_VECTOR_LOGI("Finding peaks in vector success."); return ESP_OK; } /** * @brief Finds all valley items in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param valleys Pointer to the vector to store valley items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_valleys(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *valleys) { ZH_VECTOR_LOGI("Finding valleys in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding valleys fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding valleys fail. Comparison function is NULL."); ZH_VECTOR_CHECK(valleys != NULL, ESP_ERR_INVALID_ARG, "Finding valleys fail. Valleys vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding valleys fail. Vector not initialized."); ZH_VECTOR_CHECK(valleys->status == true, ESP_ERR_INVALID_STATE, "Finding valleys fail. Valleys vector not initialized."); for (uint16_t i = 1; i < vector->size - 1; ++i) { if (cmp(vector->items[i], vector->items[i - 1]) < 0 && cmp(vector->items[i], vector->items[i + 1]) < 0) { esp_err_t err = zh_vector_push_back(valleys, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding valleys fail. Failed to add valley."); } } ZH_VECTOR_LOGI("Finding valleys in vector success."); return ESP_OK; } /** * @brief Finds all outliers in the vector based on a predicate. * * @param vector Pointer to the vector. * @param predicate Predicate function to evaluate items. * @param outliers Pointer to the vector to store outlier items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_outliers(zh_vector_t *vector, bool (*predicate)(const void *), zh_vector_t *outliers) { ZH_VECTOR_LOGI("Finding outliers in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding outliers fail. Vector is NULL."); ZH_VECTOR_CHECK(predicate != NULL, ESP_ERR_INVALID_ARG, "Finding outliers fail. Predicate is NULL."); ZH_VECTOR_CHECK(outliers != NULL, ESP_ERR_INVALID_ARG, "Finding outliers fail. Outliers vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding outliers fail. Vector not initialized."); ZH_VECTOR_CHECK(outliers->status == true, ESP_ERR_INVALID_STATE, "Finding outliers fail. Outliers vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (predicate(vector->items[i])) { esp_err_t err = zh_vector_push_back(outliers, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding outliers fail. Failed to add outlier."); } } ZH_VECTOR_LOGI("Finding outliers in vector success."); return ESP_OK; } /** * @brief Finds the median item in a specified range of the vector. * * @param vector Pointer to the vector. * @param start Start index of the range. * @param end End index of the range (exclusive). * @param cmp Comparison function to compare items. * @return Pointer to the median item, or NULL if the range is invalid. */ void *zh_vector_find_median_range(zh_vector_t *vector, uint16_t start, uint16_t end, int (*cmp)(const void *, const void *)) { ZH_VECTOR_LOGI("Finding median in range of vector begin."); ZH_VECTOR_CHECK(vector != NULL, NULL, "Finding median fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, NULL, "Finding median fail. Comparison function is NULL."); ZH_VECTOR_CHECK(vector->status == true, NULL, "Finding median fail. Vector not initialized."); ZH_VECTOR_CHECK(start < vector->size, NULL, "Finding median fail. Start index out of bounds."); ZH_VECTOR_CHECK(end <= vector->size, NULL, "Finding median fail. End index out of bounds."); ZH_VECTOR_CHECK(start < end, NULL, "Finding median fail. Start index must be less than end index."); uint16_t range_size = end - start; zh_vector_t temp; esp_err_t err = zh_vector_init(&temp, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, NULL, "Finding median fail. Failed to initialize temporary vector."); for (uint16_t i = start; i < end; ++i) { err = zh_vector_push_back(&temp, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, NULL, "Finding median fail. Failed to copy item."); } zh_vector_sort(&temp, cmp); void *median = temp.items[range_size / 2]; zh_vector_free(&temp); ZH_VECTOR_LOGI("Finding median in range of vector success."); return median; } /** * @brief Finds the k closest items to a specified value in the vector. * * @param vector Pointer to the vector. * @param value Pointer to the value to compare. * @param k Number of closest items to find. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the closest items. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_k_closest(zh_vector_t *vector, void *value, uint16_t k, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding k closest items in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding k closest items fail. Vector is NULL."); ZH_VECTOR_CHECK(value != NULL, ESP_ERR_INVALID_ARG, "Finding k closest items fail. Value is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding k closest items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding k closest items fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding k closest items fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding k closest items fail. Result vector not initialized."); ZH_VECTOR_CHECK(k > 0 && k <= vector->size, ESP_ERR_INVALID_ARG, "Finding k closest items fail. Invalid k value."); zh_vector_t distances; esp_err_t err = zh_vector_init(&distances, sizeof(int)); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding k closest items fail. Failed to initialize distances vector."); for (uint16_t i = 0; i < vector->size; ++i) { int distance = cmp(vector->items[i], value); err = zh_vector_push_back(&distances, &distance); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding k closest items fail. Failed to calculate distance."); } for (uint16_t i = 0; i < k; ++i) { int min_index = zh_vector_find_min(&distances, cmp); err = zh_vector_push_back(result, vector->items[min_index]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding k closest items fail. Failed to add item to result."); zh_vector_change_item(&distances, min_index, (void *)&INT_MAX); // Исключаем найденный элемент } zh_vector_free(&distances); ZH_VECTOR_LOGI("Finding k closest items in vector success."); return ESP_OK; } /** * @brief Finds all items in the vector that are outside a specified range. * * @param vector Pointer to the vector. * @param lower Pointer to the lower bound. * @param upper Pointer to the upper bound. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the results. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_out_of_range(zh_vector_t *vector, void *lower, void *upper, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding all items outside range in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Vector is NULL."); ZH_VECTOR_CHECK(lower != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Lower bound is NULL."); ZH_VECTOR_CHECK(upper != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Upper bound is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding items fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding items fail. Result vector not initialized."); for (uint16_t i = 0; i < vector->size; ++i) { if (cmp(vector->items[i], lower) < 0 || cmp(vector->items[i], upper) > 0) { esp_err_t err = zh_vector_push_back(result, vector->items[i]); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding items fail. Failed to add item to result vector."); } } ZH_VECTOR_LOGI("Finding all items outside range in vector success."); return ESP_OK; } /** * @brief Finds the longest increasing subsequence in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the subsequence. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_longest_increasing_subsequence(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding longest increasing subsequence in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding subsequence fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding subsequence fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding subsequence fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding subsequence fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding subsequence fail. Result vector not initialized."); uint16_t *lengths = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); uint16_t *previous = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(lengths != NULL && previous != NULL, ESP_ERR_NO_MEM, "Finding subsequence fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { lengths[i] = 1; previous[i] = UINT16_MAX; for (uint16_t j = 0; j < i; ++j) { if (cmp(vector->items[j], vector->items[i]) < 0 && lengths[j] + 1 > lengths[i]) { lengths[i] = lengths[j] + 1; previous[i] = j; } } } uint16_t max_length = 0, max_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (lengths[i] > max_length) { max_length = lengths[i]; max_index = i; } } zh_vector_clear(result); for (uint16_t i = max_index; i != UINT16_MAX; i = previous[i]) { zh_vector_push_back(result, vector->items[i]); } heap_caps_free(lengths); heap_caps_free(previous); ZH_VECTOR_LOGI("Finding longest increasing subsequence in vector success."); return ESP_OK; } /** * @brief Finds the longest decreasing subsequence in the vector. * * @param vector Pointer to the vector. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the subsequence. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_longest_decreasing_subsequence(zh_vector_t *vector, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding longest decreasing subsequence in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding subsequence fail. Vector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding subsequence fail. Comparison function is NULL."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding subsequence fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding subsequence fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding subsequence fail. Result vector not initialized."); uint16_t *lengths = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); uint16_t *previous = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(lengths != NULL && previous != NULL, ESP_ERR_NO_MEM, "Finding subsequence fail. Memory allocation failed."); for (uint16_t i = 0; i < vector->size; ++i) { lengths[i] = 1; previous[i] = UINT16_MAX; for (uint16_t j = 0; j < i; ++j) { if (cmp(vector->items[j], vector->items[i]) > 0 && lengths[j] + 1 > lengths[i]) { lengths[i] = lengths[j] + 1; previous[i] = j; } } } uint16_t max_length = 0, max_index = 0; for (uint16_t i = 0; i < vector->size; ++i) { if (lengths[i] > max_length) { max_length = lengths[i]; max_index = i; } } zh_vector_clear(result); for (uint16_t i = max_index; i != UINT16_MAX; i = previous[i]) { zh_vector_push_back(result, vector->items[i]); } heap_caps_free(lengths); heap_caps_free(previous); ZH_VECTOR_LOGI("Finding longest decreasing subsequence in vector success."); return ESP_OK; } /** * @brief Finds the most common subvector in the vector. * * @param vector Pointer to the vector. * @param subvector_size Size of the subvector to find. * @param cmp Comparison function to compare items. * @param result Pointer to the vector to store the most common subvector. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_most_common_subvector(zh_vector_t *vector, uint16_t subvector_size, int (*cmp)(const void *, const void *), zh_vector_t *result) { ZH_VECTOR_LOGI("Finding most common subvector in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Vector is NULL."); ZH_VECTOR_CHECK(subvector_size > 0, ESP_ERR_INVALID_ARG, "Finding subvector fail. Subvector size must be greater than 0."); ZH_VECTOR_CHECK(subvector_size <= vector->size, ESP_ERR_INVALID_ARG, "Finding subvector fail. Subvector size is larger than vector."); ZH_VECTOR_CHECK(result != NULL, ESP_ERR_INVALID_ARG, "Finding subvector fail. Result vector is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding subvector fail. Vector not initialized."); ZH_VECTOR_CHECK(result->status == true, ESP_ERR_INVALID_STATE, "Finding subvector fail. Result vector not initialized."); uint16_t max_count = 0; zh_vector_t temp_result; esp_err_t err = zh_vector_init(&temp_result, vector->unit); ZH_VECTOR_CHECK(err == ESP_OK, err, "Finding subvector fail. Failed to initialize temporary vector."); for (uint16_t i = 0; i <= vector->size - subvector_size; ++i) { uint16_t count = 0; for (uint16_t j = i + 1; j <= vector->size - subvector_size; ++j) { bool match = true; for (uint16_t k = 0; k < subvector_size; ++k) { if (cmp(vector->items[i + k], vector->items[j + k]) != 0) { match = false; break; } } if (match) { count++; } } if (count > max_count) { max_count = count; zh_vector_clear(&temp_result); for (uint16_t k = 0; k < subvector_size; ++k) { zh_vector_push_back(&temp_result, vector->items[i + k]); } } } zh_vector_clear(result); for (uint16_t i = 0; i < temp_result.size; ++i) { zh_vector_push_back(result, temp_result.items[i]); } zh_vector_free(&temp_result); ZH_VECTOR_LOGI("Finding most common subvector in vector success."); return ESP_OK; } /** * @brief Finds all permutations of a subvector in the vector. * * @param vector Pointer to the vector. * @param subvector Pointer to the subvector to find permutations of. * @param cmp Comparison function to compare items. * @param indices Pointer to an array of starting indices (allocated dynamically). * @param count Pointer to store the number of found permutations. * @return ESP_OK on success, or an error code otherwise. */ esp_err_t zh_vector_find_all_permutations(zh_vector_t *vector, zh_vector_t *subvector, int (*cmp)(const void *, const void *), uint16_t **indices, uint16_t *count) { ZH_VECTOR_LOGI("Finding all permutations of subvector in vector begin."); ZH_VECTOR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, "Finding permutations fail. Vector is NULL."); ZH_VECTOR_CHECK(subvector != NULL, ESP_ERR_INVALID_ARG, "Finding permutations fail. Subvector is NULL."); ZH_VECTOR_CHECK(cmp != NULL, ESP_ERR_INVALID_ARG, "Finding permutations fail. Comparison function is NULL."); ZH_VECTOR_CHECK(indices != NULL, ESP_ERR_INVALID_ARG, "Finding permutations fail. Indices pointer is NULL."); ZH_VECTOR_CHECK(count != NULL, ESP_ERR_INVALID_ARG, "Finding permutations fail. Count pointer is NULL."); ZH_VECTOR_CHECK(vector->status == true, ESP_ERR_INVALID_STATE, "Finding permutations fail. Vector not initialized."); ZH_VECTOR_CHECK(subvector->status == true, ESP_ERR_INVALID_STATE, "Finding permutations fail. Subvector not initialized."); ZH_VECTOR_CHECK(subvector->size <= vector->size, ESP_FAIL, "Finding permutations fail. Subvector is larger than vector."); *count = 0; *indices = heap_caps_malloc(vector->size * sizeof(uint16_t), MALLOC_CAP_8BIT); ZH_VECTOR_CHECK(*indices != NULL, ESP_ERR_NO_MEM, "Finding permutations fail. Memory allocation failed."); for (uint16_t i = 0; i <= vector->size - subvector->size; ++i) { bool match = true; for (uint16_t j = 0; j < subvector->size; ++j) { bool found = false; for (uint16_t k = 0; k < subvector->size; ++k) { if (cmp(vector->items[i + j], subvector->items[k]) == 0) { found = true; break; } } if (!found) { match = false; break; } } if (match) { (*indices)[(*count)++] = i; } } ZH_VECTOR_LOGI("Finding all permutations of subvector in vector success. Found: %d.", *count); return ESP_OK; }