Files
zh_vector/include/zh_vector.h
T

262 lines
11 KiB
C

/**
* @file zh_vector.h
*
* @brief Dynamic vector implementation with memory management and thread safety.
*
* This module provides a generic dynamic vector data structure with automatic
* memory management, element insertion/deletion at any position, duplicate
* removal, and item search capabilities. The implementation is thread-safe
* using FreeRTOS mutexes for all public operations.
*
* Key features:
* - Dynamic capacity with automatic growth and shrinkage
* - Thread-safe operations via FreeRTOS mutex
* - Support for arbitrary data types through void pointers
* - Flexible insertion at front or back
* - Duplicate removal and item search functionality
* - Memory allocation with ESP32 heap capabilities
*
* @note All public functions require a valid vector pointer obtained through zh_vector_init().
* @note All operations are protected by internal mutex for thread safety.
*/
#pragma once
#include "esp_err.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Forward declaration of the vector structure.
*
* Opaque handle representing a dynamic vector with internal state
* including items storage, capacity, size, element size, and mutex.
*/
typedef struct _zh_vector_t zh_vector_t;
/**
* @brief Initialize a new vector with specified element size.
*
* Allocates memory for the vector structure and creates an internal mutex.
* The vector starts with zero capacity and will grow dynamically on first use.
*
* @param[out] vector Pointer to receive the initialized vector handle (must be NULL)
* @param[in] unit Size of each element in bytes (must be > 0)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if vector is NULL or unit is zero
* @return ESP_ERR_INVALID_STATE if vector is already initialized
* @return ESP_ERR_NO_MEM if memory allocation fails
*/
esp_err_t zh_vector_init(zh_vector_t **vector, uint16_t unit);
/**
* @brief Free all resources associated with the vector.
*
* Frees all allocated elements, the items array, the mutex, and the vector
* structure itself. The vector pointer is set to NULL after deletion.
*
* @param[in,out] vector Pointer to the vector handle to be freed (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if vector or *vector is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_free(zh_vector_t **vector);
/**
* @brief Get the current number of elements in the vector.
*
* @param[in] vector Pointer to the vector handle (must not be NULL)
* @param[out] size Pointer to receive the current size (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_get_size(zh_vector_t **vector, uint16_t *size);
/**
* @brief Get the current capacity of the vector.
*
* @param[in] vector Pointer to the vector handle (must not be NULL)
* @param[out] capacity Pointer to receive the current capacity (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_get_capacity(zh_vector_t **vector, uint16_t *capacity);
/**
* @brief Insert an element at the beginning of the vector.
*
* Shifts all existing elements one position forward and inserts
* a copy of the provided item at index 0. The vector capacity
* will be increased if necessary.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
* @param[in] item Pointer to the item to insert (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
* @return ESP_ERR_NO_MEM if vector is full or element allocation fails
*/
esp_err_t zh_vector_push_front(zh_vector_t **vector, const void *item);
/**
* @brief Append an element to the end of the vector.
*
* Creates a copy of the provided item and adds it to the end of the vector.
* The vector capacity will be increased if necessary.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
* @param[in] item Pointer to the item to append (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
* @return ESP_ERR_NO_MEM if vector is full or element allocation fails
*/
esp_err_t zh_vector_push_back(zh_vector_t **vector, const void *item);
/**
* @brief Replace an element at the specified index.
*
* Copies the provided item into the existing element at the given index.
* The element must already exist and be non-NULL.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
* @param[in] index Index of the element to replace (must be < size)
* @param[in] item Pointer to the new item data (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL or index is out of bounds
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails or element at index is NULL
*/
esp_err_t zh_vector_change_item(zh_vector_t **vector, uint16_t index, const void *item);
/**
* @brief Retrieve a copy of the element at the specified index.
*
* @param[in] vector Pointer to the vector handle (must not be NULL)
* @param[in] index Index of the element to retrieve (must be < size)
* @param[out] item Pointer to buffer where the element will be copied (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL or index is out of bounds
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails or item is NULL
*
* @note The element at the specified index must exist and be non-NULL.
* This is guaranteed if the vector was properly initialized and no
* internal corruption occurred.
*/
esp_err_t zh_vector_get_item(zh_vector_t **vector, uint16_t index, void *item);
/**
* @brief Delete the element at the specified index.
*
* Frees the element's memory, shifts remaining elements, and updates size.
* Capacity may be reduced if it exceeds twice the current size.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
* @param[in] index Index of the element to delete (must be < size)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if vector or *vector is NULL or index is out of bounds
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_delete_item(zh_vector_t **vector, uint16_t index);
/**
* @brief Delete the last element of the vector.
*
* Frees the last element's memory and updates size.
* Capacity may be reduced if it exceeds twice the current size.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if vector or *vector is NULL or vector is empty
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_delete_back(zh_vector_t **vector);
/**
* @brief Delete the first element of the vector.
*
* Frees the first element's memory, shifts remaining elements, and updates size.
* Capacity may be reduced if it exceeds twice the current size.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if vector or *vector is NULL or vector is empty
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_delete_front(zh_vector_t **vector);
/**
* @brief Remove duplicate elements from the vector.
*
* Compares elements using memcmp and removes subsequent duplicates.
* Elements are compared based on their raw binary content.
*
* @param[in,out] vector Pointer to the vector handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if vector or *vector is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
*/
esp_err_t zh_vector_remove_duplicates(zh_vector_t **vector);
/**
* @brief Find the index of the first matching element.
*
* Searches for an element whose binary content matches the provided item
* using memcmp. Returns the index of the first match or -1 if not found.
*
* @param[in] vector Pointer to the vector handle (must not be NULL)
* @param[in] item Pointer to the item to search for (must not be NULL)
* @param[out] index Pointer to receive the found index (-1 if not found) (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
* @return ESP_ERR_NOT_FOUND if item is not found in the vector
*/
esp_err_t zh_vector_find_item(zh_vector_t **vector, const void *item, int32_t *index);
/**
* @brief Find an element by comparing a specific field within structures.
*
* Searches for an element where a specified field (identified by offset
* and size) matches the provided value. Comparison starts from the
* specified index.
*
* @param[in] vector Pointer to the vector handle containing structures (must not be NULL)
* @param[in] sample_struct Pointer to a sample structure (used for field offset calculation) (must not be NULL)
* @param[in] item Pointer to the field within the structure (e.g., `&sample.id`). Used to calculate the field offset (must not be NULL)
* @param[in] size Size of the field in bytes (must be > 0)
* @param[in] value Pointer to the value to match against the field (must not be NULL)
* @param[in] start Index to begin searching from (must be < size)
* @param[out] index Pointer to receive the found index (-1 if not found) (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is invalid
* @return ESP_ERR_INVALID_STATE if mutex acquisition fails
* @return ESP_ERR_NOT_FOUND if no matching element is found
*/
esp_err_t zh_vector_find_item_in_field(zh_vector_t **vector, const void *sample_struct, const void *item, size_t size, const void *value, uint16_t start, int32_t *index);
#ifdef __cplusplus
}
#endif