diff --git a/include/zh_vector.h b/include/zh_vector.h index 5aa5a93..c773529 100644 --- a/include/zh_vector.h +++ b/include/zh_vector.h @@ -1,115 +1,492 @@ -#pragma once +#ifndef ZH_VECTOR_H +#define ZH_VECTOR_H -#include "string.h" -#include "esp_err.h" -#include "esp_log.h" -#include "esp_heap_caps.h" +#include +#include +#include + +/** + * @brief Structure representing a dynamic vector. + */ +typedef struct { + void **items; ///< Pointer to the array of items. + uint16_t size; ///< Current number of elements in the vector. + uint16_t capacity; ///< Current capacity of the vector. + uint16_t unit; ///< Size of each element in bytes. + bool status; ///< Indicates whether the vector is initialized. +} zh_vector_t; #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - typedef struct // Main structure of vector data. - { - void **items; // Array of pointers of vector items. - uint16_t capacity; // Maximum capacity of the vector. @note Used to control the size of allocated memory for array of pointers of vector items. Usually equal to the current number of items in the vector. Automatically changes when items are added or deleted. - uint16_t size; // Number of items in the vector. @note Can be read with zh_vector_get_size(). - uint16_t unit; // Vector item size. @note Possible values from 1 to 65535. - bool status; // Vector initialization status flag. @note Used to prevent execution of vector functions without prior vector initialization. - } zh_vector_t; +/** + * @brief Initializes a vector. + * + * @param vector Pointer to the vector to initialize. + * @param unit Size of each element in bytes. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_t vector; + * esp_err_t err = zh_vector_init(&vector, sizeof(int)); + * if (err == ESP_OK) { + * // Vector initialized successfully. + * } + * @endcode + */ +esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit); - /** - * @brief Initialize vector. - * - * @param[in] vector Pointer to main structure of vector data. - * @param[in] unit Size of vector item. - * - * @return - * - ESP_OK if initialization was success - * - ESP_ERR_INVALID_ARG if parameter error - * - ESP_ERR_INVALID_STATE if vector already initialized - */ - esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit); +/** + * @brief Frees the memory allocated for the vector. + * + * @param vector Pointer to the vector to free. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_free(&vector); + * @endcode + */ +esp_err_t zh_vector_free(zh_vector_t *vector); - /** - * @brief Deinitialize vector. Free all allocated memory. - * - * @param[in] vector Pointer to main structure of vector data. - * - * @return - * - ESP_OK if deinitialization was success - * - ESP_ERR_INVALID_ARG if parameter error - * - ESP_ERR_INVALID_STATE if vector not initialized - */ - esp_err_t zh_vector_free(zh_vector_t *vector); +/** + * @brief Adds an item to the end of the vector. + * + * @param vector Pointer to the vector. + * @param item Pointer to the item to add. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * int value = 42; + * zh_vector_push_back(&vector, &value); + * @endcode + */ +esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item); - /** - * @brief Get current vector size. - * - * @param[in] vector Pointer to main structure of vector data. - * - * @return - * - Vector size - * - ESP_FAIL if parameter error or vector not initialized - */ - esp_err_t zh_vector_get_size(zh_vector_t *vector); +/** + * @brief Adds an item to the end of the vector without copying its contents. + * + * This function directly assigns the provided pointer to the vector's internal storage, + * avoiding the need to allocate memory or copy data. It is useful when the item is already + * allocated and managed externally. + * + * @param vector Pointer to the vector. + * @param item Pointer to the item to add. + * @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 = malloc(sizeof(int)); + * *value = 42; + * zh_vector_emplace_back(&vector, value); + * @endcode + */ +esp_err_t zh_vector_emplace_back(zh_vector_t *vector, void *item); - /** - * @brief Add item at end of vector. - * - * @param[in] vector Pointer to main structure of vector data. - * @param[in] item Pointer to item for add. - * - * @return - * - ESP_OK if add was success - * - ESP_ERR_INVALID_ARG if parameter error - * - ESP_ERR_NO_MEM if memory allocation fail or no free memory in the heap - * - ESP_ERR_INVALID_STATE if vector not initialized - */ - esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item); +/** + * @brief Removes the last item from the vector. + * + * @param vector Pointer to the vector. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_pop_back(&vector); + * @endcode + */ +esp_err_t zh_vector_pop_back(zh_vector_t *vector); - /** - * @brief Change item by index. - * - * @param[in] vector Pointer to main structure of vector data. - * @param[in] index Index of item for change. - * @param[in] item Pointer to new data of item. - * - * @return - * - ESP_OK if change was success - * - ESP_ERR_INVALID_ARG if parameter error - * - ESP_ERR_INVALID_STATE if vector not initialized - * - ESP_FAIL if index does not exist - */ - esp_err_t zh_vector_change_item(zh_vector_t *vector, uint16_t index, void *item); +/** + * @brief Gets the item at the specified index. + * + * @param vector Pointer to the vector. + * @param index Index of the item to retrieve. + * @return Pointer to the item, or NULL if the index is out of bounds. + * + * Example usage: + * @code + * int *item = (int *)zh_vector_get_item(&vector, 0); + * if (item != NULL) { + * // Use the item. + * } + * @endcode + */ +void *zh_vector_get_item(zh_vector_t *vector, uint16_t index); - /** - * @brief Get item by index. - * - * @param[in] vector Pointer to main structure of vector data. - * @param[in] index Index of item for get. - * - * @return - * - Pointer to item - * - NULL if parameter error or vector not initialized or if index does not exist - */ - void *zh_vector_get_item(zh_vector_t *vector, uint16_t index); +/** + * @brief Checks if the vector is empty. + * + * @param vector Pointer to the vector. + * @return true if the vector is empty, false otherwise. + * + * Example usage: + * @code + * if (zh_vector_is_empty(&vector)) { + * // Vector is empty. + * } + * @endcode + */ +bool zh_vector_is_empty(zh_vector_t *vector); - /** - * @brief Delete item by index and shifts all elements in vector. - * - * @param[in] vector Pointer to main structure of vector data. - * @param[in] index Index of item for delete. - * - * @return - * - ESP_OK if delete was success - * - ESP_ERR_INVALID_ARG if parameter error - * - ESP_ERR_INVALID_STATE if vector not initialized - * - ESP_FAIL if index does not exist - */ - esp_err_t zh_vector_delete_item(zh_vector_t *vector, uint16_t index); +/** + * @brief Clears all items from the vector. + * + * @param vector Pointer to the vector. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_clear(&vector); + * @endcode + */ +esp_err_t zh_vector_clear(zh_vector_t *vector); + +/** + * @brief Sorts 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 + * int compare(const void *a, const void *b) { + * return (*(int *)a - *(int *)b); + * } + * zh_vector_sort(&vector, compare); + * @endcode + */ +esp_err_t zh_vector_sort(zh_vector_t *vector, int (*cmp)(const void *, const void *)); + +/** + * @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 + * int value = 42; + * int index = zh_vector_find(&vector, &value, compare); + * if (index != -1) { + * // Item found at index. + * } + * @endcode + */ +int zh_vector_find(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)); + +/** + * @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 + * int value = 42; + * zh_vector_remove_all(&vector, &value, compare); + * @endcode + */ +esp_err_t zh_vector_remove_all(zh_vector_t *vector, void *item, int (*cmp)(const void *, const void *)); + +/** + * @brief Replaces all occurrences of an item in the vector with a new item. + * + * @param vector Pointer to the vector. + * @param old_item Pointer to the item to replace. + * @param new_item Pointer to the new item. + * @param cmp Comparison function to compare items. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * int old_value = 42; + * int new_value = 84; + * zh_vector_replace_all(&vector, &old_value, &new_value, compare); + * @endcode + */ +esp_err_t zh_vector_replace_all(zh_vector_t *vector, void *old_item, void *new_item, int (*cmp)(const void *, const void *)); + +/** + * @brief Counts the number of items in the vector that satisfy a predicate. + * + * @param vector Pointer to the vector. + * @param predicate Predicate function to evaluate items. + * @return Number of items that satisfy the predicate. + * + * Example usage: + * @code + * bool is_even(const void *item) { + * return (*(int *)item % 2) == 0; + * } + * uint16_t count = zh_vector_count_if(&vector, is_even); + * @endcode + */ +uint16_t zh_vector_count_if(zh_vector_t *vector, bool (*predicate)(const void *)); + +/** + * @brief Shuffles the elements of the vector randomly. + * + * @param vector Pointer to the vector. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_shuffle(&vector); + * @endcode + */ +esp_err_t zh_vector_shuffle(zh_vector_t *vector); + +/** + * @brief Finds the minimum item in the vector. + * + * @param vector Pointer to the vector. + * @param cmp Comparison function to compare items. + * @return Pointer to the minimum item, or NULL if the vector is empty. + * + * Example usage: + * @code + * int *min_item = (int *)zh_vector_min(&vector, compare); + * if (min_item != NULL) { + * // Use the minimum item. + * } + * @endcode + */ +void *zh_vector_min(zh_vector_t *vector, int (*cmp)(const void *, const void *)); + +/** + * @brief Finds the maximum item in the vector. + * + * @param vector Pointer to the vector. + * @param cmp Comparison function to compare items. + * @return Pointer to the maximum item, or NULL if the vector is empty. + * + * Example usage: + * @code + * int *max_item = (int *)zh_vector_max(&vector, compare); + * if (max_item != NULL) { + * // Use the maximum item. + * } + * @endcode + */ +void *zh_vector_max(zh_vector_t *vector, int (*cmp)(const void *, const void *)); + +/** + * @brief Rotates the vector to the left by the specified number of positions. + * + * @param vector Pointer to the vector. + * @param positions Number of positions to rotate. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_rotate_left(&vector, 3); + * @endcode + */ +esp_err_t zh_vector_rotate_left(zh_vector_t *vector, uint16_t positions); + +/** + * @brief Rotates the vector to the right by the specified number of positions. + * + * @param vector Pointer to the vector. + * @param positions Number of positions to rotate. + * @return ESP_OK on success, or an error code otherwise. + * + * Example usage: + * @code + * zh_vector_rotate_right(&vector, 2); + * @endcode + */ +esp_err_t zh_vector_rotate_right(zh_vector_t *vector, uint16_t positions); + +/** + * @brief Removes all items from the vector that 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(zh_vector_t *vector, bool (*predicate)(const void *)); + +/** + * @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 *)); + +/** + * @brief Replaces items in the vector that satisfy a predicate with a new item. + * + * @param vector Pointer to the vector. + * @param predicate Predicate function to evaluate items. + * @param new_item Pointer to the new item to replace with. + * @return ESP_OK on success, or an error code otherwise. + */ +esp_err_t zh_vector_replace(zh_vector_t *vector, bool (*predicate)(const void *), void *new_item); + +/** + * @brief Merges the source vector into the destination vector. + * + * @param dest Pointer to the destination vector. + * @param src Pointer to the source vector. + * @return ESP_OK on success, or an error code otherwise. + */ +esp_err_t zh_vector_merge(zh_vector_t *dest, const zh_vector_t *src); + +/** + * @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_unique(zh_vector_t *vector, int (*cmp)(const void *, const void *)); + +/** + * @brief Converts the vector to an array of pointers. + * + * @param vector Pointer to the vector. + * @return Pointer to the array of pointers, or NULL on failure. + */ +void **zh_vector_to_array(zh_vector_t *vector); + +/** + * @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); + +/** + * @brief Copies items from the source vector to the destination vector that satisfy a predicate. + * + * @param src Pointer to the source vector. + * @param dest Pointer to the destination vector. + * @param predicate Predicate function to evaluate items. + * @return ESP_OK on success, or an error code otherwise. + */ +esp_err_t zh_vector_copy_if(const zh_vector_t *src, zh_vector_t *dest, bool (*predicate)(const void *)); + +/** + * @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); + +/** + * @brief Finds all items in the vector that match a predicate and returns their indices. + * + * @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(zh_vector_t *vector, bool (*predicate)(const void *), uint16_t **indices, uint16_t *count); + +/** + * @brief Finds the intersection of two vectors and stores the result in a third vector. + * + * @param vector1 Pointer to the first vector. + * @param vector2 Pointer to the second 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(const zh_vector_t *vector1, const zh_vector_t *vector2, zh_vector_t *result, int (*cmp)(const void *, const void *)); + +/** + * @brief Finds the union of two vectors and stores the result in a third vector. + * + * @param vector1 Pointer to the first vector. + * @param vector2 Pointer to the second vector. + * @param result Pointer to the vector to store the union. + * @param cmp Comparison function to compare items. + * @return ESP_OK on success, or an error code otherwise. + */ +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 *)); + +/** + * @brief Finds the difference of two vectors and stores the result in a third vector. + * + * @param vector1 Pointer to the first vector. + * @param vector2 Pointer to the second vector. + * @param result Pointer to the vector to store the difference. + * @param cmp Comparison function to compare items. + * @return ESP_OK on success, or an error code otherwise. + */ +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 *)); + +/** + * @brief Finds the symmetric difference of two vectors and stores the result in a third vector. + * + * @param vector1 Pointer to the first vector. + * @param vector2 Pointer to the second vector. + * @param result Pointer to the vector to store the symmetric difference. + * @param cmp Comparison function to compare items. + * @return ESP_OK on success, or an error code otherwise. + */ +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 *)); + +/** + * @brief Gets the current size (number of elements) of the vector. + * + * @param vector Pointer to the vector. + * @return The size of the vector, or -1 if the vector is not initialized or invalid. + * + * Example usage: + * @code + * zh_vector_t vector; + * zh_vector_init(&vector, sizeof(int)); + * int size = zh_vector_get_size(&vector); + * printf("Vector size: %d\n", size); + * @endcode + */ +esp_err_t zh_vector_get_size(zh_vector_t *vector); + +/** + * @brief Adds an item to the end of the vector without copying its contents. + * + * This function directly assigns the provided pointer to the vector's internal storage, + * avoiding the need to allocate memory or copy data. It is useful when the item is already + * allocated and managed externally. + * + * @param vector Pointer to the vector. + * @param item Pointer to the item to add. + * @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 = malloc(sizeof(int)); + * *value = 42; + * zh_vector_emplace_back(&vector, value); + * @endcode + */ +esp_err_t zh_vector_emplace_back(zh_vector_t *vector, void *item); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif // ZH_VECTOR_H \ No newline at end of file diff --git a/zh_vector.c b/zh_vector.c index 0863374..664967b 100644 --- a/zh_vector.c +++ b/zh_vector.c @@ -1,188 +1,4546 @@ #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) { - ESP_LOGI(TAG, "Vector initialization begin."); - if (vector == NULL || unit == 0) - { - ESP_LOGE(TAG, "Vector initialization fail. Invalid argument."); - return ESP_ERR_INVALID_ARG; - } - if (vector->status == true) - { - ESP_LOGE(TAG, "Vector initialization fail. Vector already initialized."); - return ESP_ERR_INVALID_STATE; - } + 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; - ESP_LOGI(TAG, "Vector initialization success."); + ZH_VECTOR_LOGI("Vector initialization success."); return ESP_OK; } esp_err_t zh_vector_free(zh_vector_t *vector) { - ESP_LOGI(TAG, "Vector deletion begin."); - if (vector == NULL) - { - ESP_LOGE(TAG, "Vector deletion fail. Invalid argument."); - return ESP_ERR_INVALID_ARG; - } - if (vector->status == false) - { - ESP_LOGE(TAG, "Vector deletion fail. Vector not initialized."); - return ESP_ERR_INVALID_STATE; - } + 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) { - heap_caps_free(vector->items[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; - ESP_LOGI(TAG, "Vector deletion success."); + ZH_VECTOR_LOGI("Vector deletion success."); return ESP_OK; } esp_err_t zh_vector_get_size(zh_vector_t *vector) { - ESP_LOGI(TAG, "Getting vector size begin."); - if (vector == NULL || vector->status == false) - { - ESP_LOGE(TAG, "Getting vector size fail. Invalid argument or vector not initialized."); - return ESP_FAIL; - } - ESP_LOGI(TAG, "Getting vector size success. Size: %d.", vector->size); + 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) { - ESP_LOGI(TAG, "Adding item to vector begin."); - if (vector == NULL || item == NULL) - { - ESP_LOGE(TAG, "Adding item to vector fail. Invalid argument."); - return ESP_ERR_INVALID_ARG; - } - if (vector->status == false) - { - ESP_LOGE(TAG, "Adding item to vector fail. Vector not initialized."); - return ESP_ERR_INVALID_STATE; - } + 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) { - if (_resize(vector, vector->capacity + 1) == ESP_ERR_NO_MEM) - { - ESP_LOGE(TAG, "Adding item to vector fail. Memory allocation fail or no free memory in the heap."); - return ESP_ERR_NO_MEM; - } + 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); - if (vector->items[vector->size] == NULL) + 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) { - ESP_LOGE(TAG, "Adding item to vector fail. Memory allocation fail or no free memory in the heap."); - return ESP_ERR_NO_MEM; + 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."); } - memcpy(vector->items[vector->size++], item, vector->unit); - ESP_LOGI(TAG, "Adding item to vector success."); + + 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) { - ESP_LOGI(TAG, "Changing item in vector begin."); - if (vector == NULL || item == NULL) - { - ESP_LOGE(TAG, "Changing item in vector fail. Invalid argument."); - return ESP_ERR_INVALID_ARG; - } - if (vector->status == false) - { - ESP_LOGE(TAG, "Changing item in vector fail. Vector not initialized."); - return ESP_ERR_INVALID_STATE; - } - if (index < vector->size) - { - memcpy(vector->items[index], item, vector->unit); - ESP_LOGI(TAG, "Changing item in vector success."); - return ESP_OK; - } - ESP_LOGE(TAG, "Changing item in vector fail. Index does not exist."); - return ESP_FAIL; + 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) { - ESP_LOGI(TAG, "Getting item from vector begin."); - if (vector == NULL) - { - ESP_LOGE(TAG, "Getting item from vector fail. Invalid argument."); - return NULL; - } - if (vector->status == false) - { - ESP_LOGE(TAG, "Getting item from vector fail. Vector not initialized."); - return NULL; - } - if (index < vector->size) - { - void *item = vector->items[index]; - ESP_LOGI(TAG, "Getting item from vector success."); - return item; - } - else - { - ESP_LOGE(TAG, "Getting item from vector fail. Index does not exist."); - return NULL; - } + 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) { - ESP_LOGI(TAG, "Deleting item in vector begin."); - if (vector == NULL) + 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) { - ESP_LOGE(TAG, "Deleting item in vector fail. Invalid argument."); - return ESP_ERR_INVALID_ARG; + vector->items[i] = vector->items[i + 1]; } - if (vector->status == false) + vector->items[--vector->size] = NULL; + + if (vector->size < vector->capacity / 2) { - ESP_LOGE(TAG, "Deleting item in vector fail. Vector not initialized."); - return ESP_ERR_INVALID_STATE; + 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."); } - if (index < vector->size) + + 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) { - heap_caps_free(vector->items[index]); - for (uint8_t i = index; i < (vector->size - 1); ++i) - { - vector->items[i] = vector->items[i + 1]; - vector->items[i + 1] = NULL; - } - --vector->size; - _resize(vector, vector->capacity - 1); - ESP_LOGI(TAG, "Deleting item in vector success."); - return ESP_OK; + vector->items[i] = vector->items[i + 1]; } - ESP_LOGE(TAG, "Deleting item in vector fail. Index does not exist."); - return ESP_FAIL; + + 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) { - ESP_LOGI(TAG, "Vector resize begin."); - if (capacity != 0) + 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) { - vector->items = heap_caps_realloc(vector->items, sizeof(void *) * capacity, MALLOC_CAP_8BIT); - if (vector->items == NULL) + 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) { - ESP_LOGE(TAG, "Vector resize fail. Memory allocation fail or no free memory in the heap."); - return ESP_ERR_NO_MEM; + 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."); } } - vector->capacity = capacity; - ESP_LOGI(TAG, "Vector resize success. New capacity: %d.", vector->capacity); + 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; -} \ No newline at end of file +} + +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; +} + + + + +