feat!: main structure of vector changed to double pointer

This commit is contained in:
aZholtikov committed 2026-07-05 10:14:16 +03:00
1 parent d572e79a5b
commit c76486fa82
7 files changed
+599 -354

No files matched your search

+3 -1
View File
@@ -15,7 +15,9 @@
## Features ## Features
1. Support of any data types. 1. Support of any data types.
2. The maximum size of the veсtor is 65535 elements. 2. The maximum size of the vector is 65535 elements.
3. Thread-safe implementation using FreeRTOS mutex.
4. Automatic memory management with heap_caps functions.
## Using ## Using
+159 -98
View File
@@ -24,56 +24,58 @@ The component is designed specifically for ESP32 microcontrollers and uses ESP-I
## Features ## Features
1. **Type Agnostic**: Supports any data type (integers, floats, structs, custom types, etc.) - **Type Agnostic**: Supports any data type (integers, floats, structs, custom types, etc.)
2. **Automatic Memory Management**: Automatic memory allocation and deallocation - **Automatic Memory Management**: Automatic memory allocation and deallocation
3. **Dynamic Resizing**: Vector capacity grows and shrinks as needed - **Dynamic Resizing**: Vector capacity grows and shrinks as needed
4. **Maximum Capacity**: Up to 65,535 elements (16-bit index limit) - **Maximum Capacity**: Up to 65,535 elements (16-bit index limit)
5. **ESP-IDF Optimized**: Uses heap_caps functions for memory allocation with memory caps - **ESP-IDF Optimized**: Uses heap_caps functions for memory allocation with memory caps
6. **Error Handling**: Comprehensive error checking with detailed logging - **Error Handling**: Comprehensive error checking with detailed logging
7. **Thread-Safe**: Thread-safe (uses FreeRTOS mutex) - **Thread-Safe**: Thread-safe (uses FreeRTOS mutex)
8. **Minimal Overhead**: Low memory and CPU overhead - **Minimal Overhead**: Low memory and CPU overhead
--- ---
## Installation ## Installation
1. Navigate to your project's components directory: Navigate to your project's components directory:
```bash ```bash
cd ../your_project/components cd ../your_project/components
``` ```
2. Clone the repository: Clone the repository:
```bash ```bash
git clone https://github.com/aZholtikov/zh_vector git clone https://github.com/aZholtikov/zh_vector
``` ```
3. In your application, include the header: In your application, include the header:
```c ```c
#include "zh_vector.h" #include "zh_vector.h"
``` ```
4. The component will be automatically built with your project. The component will be automatically built with your project.
--- ---
## API Reference ## API Reference
All functions in this library use double pointer (`zh_vector_t **`) for the vector parameter to allow for proper memory management and thread-safe operations.
### zh_vector_t Structure ### zh_vector_t Structure
```c The structure is declared as `typedef struct _zh_vector_t zh_vector_t;` and encapsulates internal implementation details.
typedef struct
{ **Fields (internal):**
void **items; // Array of pointers of vector items
uint16_t capacity; // Maximum capacity of the vector | Field | Type | Description |
uint16_t size; // Number of items in the vector |-------|------|-------------|
uint16_t unit; // Vector item size (in bytes) | `items` | `void **` | Array of element pointers. Items[0..size-1] are valid. Allocated via heap_caps_calloc, reallocated via heap_caps_realloc. |
bool is_initialized; // Vector initialization status flag | `capacity` | `uint16_t` | Current allocated capacity (number of slots). Grows on insertion - may exceed size after deletions. |
SemaphoreHandle_t mutex; // FreeRTOS mutex for thread safety | `size` | `uint16_t` | Current number of elements (0 ≤ size ≤ capacity). |
} zh_vector_t; | `unit` | `uint16_t` | Size (in bytes) of a single element. Set once in zh_vector_init() and immutable. |
``` | `mutex` | `SemaphoreHandle_t` | FreeRTOS mutex. Created in zh_vector_init(), deleted in zh_vector_free. Automatically locked/unlocked in public functions. |
--- ---
@@ -83,39 +85,44 @@ Initializes the vector.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). If the vector pointer is NULL, memory will be allocated.
- `unit` - Size of each element in bytes - `unit` - Size of each element in bytes
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector or zero unit size) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or zero unit size)
- `ESP_ERR_INVALID_STATE` - Vector already initialized - `ESP_ERR_INVALID_STATE` - Vector already initialized
- `ESP_ERR_NO_MEM` - Memory allocation failed
**Example:** **Example:**
```c ```c
zh_vector_t vector = {0}; zh_vector_t *vector = NULL;
zh_vector_init(&vector, sizeof(int)); // For integers esp_err_t ret = zh_vector_init(&vector, sizeof(int)); // For integers
if (ret != ESP_OK) {
// Handle error
}
// Don't forget to free: zh_vector_free(&vector);
``` ```
--- ---
### zh_vector_free() ### zh_vector_free()
Deinitializes the vector and frees all allocated memory. Deinitializes the vector and frees all allocated memory. Sets the vector pointer to NULL.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or NULL vector)
- `ESP_ERR_INVALID_STATE` - Vector not initialized - `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
**Note:** All dynamically allocated element memory is also freed. **Note:** All dynamically allocated element memory is also freed. The vector pointer is set to NULL after deinitialization.
--- ---
@@ -125,12 +132,14 @@ Gets the current number of elements in the vector.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `size` - Pointer to variable to store the size. Must not be NULL.
**Returns:** **Returns:**
- `>= 0` - Number of elements (success) - `ESP_OK` - Success
- `ESP_FAIL` - Error (NULL vector or not initialized) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or size pointer)
- `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
--- ---
@@ -140,15 +149,15 @@ Adds an element to the beginning of the vector.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `item` - Pointer to the element to add - `item` - Pointer to the element to add. Must not be NULL.
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector or item) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or item pointer)
- `ESP_ERR_INVALID_STATE` - Vector not initialized
- `ESP_ERR_NO_MEM` - Memory allocation failed - `ESP_ERR_NO_MEM` - Memory allocation failed
- `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
**Note:** The function allocates memory for a copy of the item and copies the data. All existing elements are shifted right by one position. **Note:** The function allocates memory for a copy of the item and copies the data. All existing elements are shifted right by one position.
@@ -160,15 +169,15 @@ Adds an element to the end of the vector.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `item` - Pointer to the element to add - `item` - Pointer to the element to add. Must not be NULL.
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector or item) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or item pointer)
- `ESP_ERR_INVALID_STATE` - Vector not initialized
- `ESP_ERR_NO_MEM` - Memory allocation failed - `ESP_ERR_NO_MEM` - Memory allocation failed
- `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
**Note:** The function allocates memory for a copy of the item and copies the data. **Note:** The function allocates memory for a copy of the item and copies the data.
@@ -180,34 +189,35 @@ Changes an element at a specific index.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `index` - Index of the element to change (0-based) - `index` - Index of the element to change (0-based). Must be < vector size.
- `item` - Pointer to the new element data - `item` - Pointer to the new element data. Must not be NULL.
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector, item, or invalid index) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer, item pointer, or invalid index)
- `ESP_ERR_INVALID_STATE` - Vector not initialized - `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
- `ESP_FAIL` - Index out of bounds
--- ---
### zh_vector_get_item() ### zh_vector_get_item()
Gets an element at a specific index. Retrieves an element at a specific index by copying it into the user-provided buffer.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `index` - Index of the element to get (0-based) - `index` - Index of the element to get (0-based).
- `item` - Pointer to a buffer of at least `unit` bytes where the element will be copied. Must not be NULL.
**Returns:** **Returns:**
- Pointer to the element (success) - `ESP_OK` - Success
- `NULL` - Error (NULL vector, not initialized, or invalid index) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer, NULL item pointer, or invalid index)
- `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
**Note:** Returns a pointer to the internal data. Do not free this pointer. **Note:** This function copies the element data into the provided buffer. No pointers are returned.
--- ---
@@ -217,17 +227,17 @@ Deletes an element at a specific index and shifts all subsequent elements.
**Parameters:** **Parameters:**
- `vector` - Pointer to the vector structure - `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `index` - Index of the element to delete (0-based) - `index` - Index of the element to delete (0-based). Must be < vector size.
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or invalid index)
- `ESP_ERR_INVALID_STATE` - Vector not initialized - `ESP_ERR_NO_MEM` - Memory allocation failed (during reallocation)
- `ESP_FAIL` - Index out of bounds - `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
**Note:** All elements after the deleted index are shifted left by one position. **Note:** All elements after the deleted index are shifted left by one position. The deleted item's memory is freed.
--- ---
@@ -238,36 +248,58 @@ Deletes an element at a specific index and shifts all subsequent elements.
```c ```c
#include "zh_vector.h" #include "zh_vector.h"
zh_vector_t int_vector = {0};
void app_main(void) void app_main(void)
{ {
esp_log_level_set("zh_vector", ESP_LOG_ERROR); esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Initialize vector for integers // Initialize vector for integers
zh_vector_init(&int_vector, sizeof(int)); esp_err_t ret = zh_vector_init(&vector, sizeof(int));
if (ret != ESP_OK) {
printf("Vector initialization error\n");
return;
}
// Add elements // Add elements
int val1 = 10; int val1 = 10;
int val2 = 20; int val2 = 20;
int val3 = 30; int val3 = 30;
zh_vector_push_front(&int_vector, &val1); zh_vector_push_front(&vector, &val1);
zh_vector_push_back(&int_vector, &val2); zh_vector_push_back(&vector, &val2);
zh_vector_push_back(&int_vector, &val3); zh_vector_push_back(&vector, &val3);
printf("Vector size: %d\n", zh_vector_get_size(&int_vector));
// Access elements size_t size;
for (int i = 0; i < zh_vector_get_size(&int_vector); i++) { ret = zh_vector_get_size(&vector, &size);
int *item = (int *)zh_vector_get_item(&int_vector, i); if (ret == ESP_OK) {
printf("Element %d: %d\n", i, *item); printf("Vector size: %zu\n", size);
} }
// Access elements
for (int i = 0; i < size; i++) {
int item_value;
esp_err_t err = zh_vector_get_item(&vector, (uint16_t)i, &item_value);
if (err == ESP_OK) {
printf("Element %d: %d\n", i, item_value);
} else {
printf("Error getting element %d: %s\n", i, esp_err_to_name(err));
}
}
// Change element // Change element
int new_val = 100; int new_val = 100;
zh_vector_change_item(&int_vector, 1, &new_val); zh_vector_change_item(&vector, 1, &new_val);
// Delete element // Delete element
zh_vector_delete_item(&int_vector, 0); zh_vector_delete_item(&vector, 0);
// Cleanup // Cleanup
zh_vector_free(&int_vector); zh_vector_free(&vector);
} }
``` ```
---
### Struct Example ### Struct Example
```c ```c
@@ -279,52 +311,82 @@ typedef struct {
float value; float value;
} my_struct_t; } my_struct_t;
zh_vector_t struct_vector = {0};
void app_main(void) void app_main(void)
{ {
esp_log_level_set("zh_vector", ESP_LOG_ERROR); esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Initialize vector for structs // Initialize vector for structs
zh_vector_init(&struct_vector, sizeof(my_struct_t)); esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
if (ret != ESP_OK) {
printf("Vector initialization error\n");
return;
}
// Add struct elements // Add struct elements
my_struct_t item1 = {1, "Item 1", 1.5f}; my_struct_t item1 = {1, "Item 1", 1.5f};
my_struct_t item2 = {2, "Item 2", 2.5f}; my_struct_t item2 = {2, "Item 2", 2.5f};
zh_vector_push_front(&struct_vector, &item1); zh_vector_push_front(&vector, &item1);
zh_vector_push_back(&struct_vector, &item2); zh_vector_push_back(&vector, &item2);
// Access and modify // Access and modify
my_struct_t *ptr = (my_struct_t *)zh_vector_get_item(&struct_vector, 0); my_struct_t item_value;
ptr->value = 10.5f; esp_err_t err = zh_vector_get_item(&vector, 0, &item_value);
if (err == ESP_OK) {
item_value.value = 10.5f;
zh_vector_change_item(&vector, 0, &item_value);
}
// Cleanup // Cleanup
zh_vector_free(&struct_vector); zh_vector_free(&vector);
} }
``` ```
---
### String Example (Char Arrays) ### String Example (Char Arrays)
```c ```c
#include "zh_vector.h" #include "zh_vector.h"
#include "string.h"
zh_vector_t string_vector = {0};
void app_main(void) void app_main(void)
{ {
esp_log_level_set("zh_vector", ESP_LOG_ERROR); esp_log_level_set("zh_vector", ESP_LOG_ERROR);
// Initialize vector for strings (100 char max)
zh_vector_t *vector = NULL;
char buffer[100] = {0}; char buffer[100] = {0};
zh_vector_init(&string_vector, sizeof(buffer));
// Initialize vector for strings (100 char max)
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
if (ret != ESP_OK) {
printf("Vector initialization error\n");
return;
}
// Add strings // Add strings
strcpy(buffer, "Hello"); strcpy(buffer, "Hello");
zh_vector_push_front(&string_vector, &buffer); zh_vector_push_front(&vector, &buffer);
strcpy(buffer, "World"); strcpy(buffer, "World");
zh_vector_push_back(&string_vector, &buffer); zh_vector_push_back(&vector, &buffer);
// Print all strings
for (int i = 0; i < zh_vector_get_size(&string_vector); i++) { size_t size;
char *str = (char *)zh_vector_get_item(&string_vector, i); ret = zh_vector_get_size(&vector, &size);
printf("String %d: %s\n", i, str); if (ret == ESP_OK) {
// Print all strings
for (int i = 0; i < size; i++) {
char str_value[100];
esp_err_t err = zh_vector_get_item(&vector, (uint16_t)i, str_value);
if (err == ESP_OK) {
printf("String %d: %s\n", i, str_value);
} else {
printf("Error getting string %d: %s\n", i, esp_err_to_name(err));
}
}
} }
// Cleanup // Cleanup
zh_vector_free(&string_vector); zh_vector_free(&vector);
} }
``` ```
@@ -351,9 +413,8 @@ void app_main(void)
|------------|-------------| |------------|-------------|
| `ESP_OK` | Operation successful | | `ESP_OK` | Operation successful |
| `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or zero size) | | `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or zero size) |
| `ESP_ERR_INVALID_STATE` | Vector not initialized or already initialized | | `ESP_ERR_INVALID_STATE` | Failed to acquire mutex (rare system error) |
| `ESP_ERR_NO_MEM` | Memory allocation failed (out of memory) | | `ESP_ERR_NO_MEM` | Memory allocation failed (out of memory) |
| `ESP_FAIL` | General failure (e.g., index out of bounds) |
--- ---
@@ -405,4 +466,4 @@ limitations under the License.
--- ---
*Generated for zh_vector v1.3.0* *Generated for zh_vector v2.0.0*
+159 -98
View File
@@ -24,56 +24,58 @@
## Возможности ## Возможности
1. **Независимость от типа данных**: Поддерживает любой тип данных (целые числа, числа с плавающей точкой, структуры, пользовательские типы и т.д.) - **Независимость от типа данных**: Поддерживает любой тип данных (целые числа, числа с плавающей точкой, структуры, пользовательские типы и т.д.)
2. **Автоматическое управление памятью**: Автоматическое выделение и освобождение памяти - **Автоматическое управление памятью**: Автоматическое выделение и освобождение памяти
3. **Динамическое изменение размера**: Емкость вектора увеличивается и уменьшается по мере необходимости - **Динамическое изменение размера**: Емкость вектора увеличивается и уменьшается по мере необходимости
4. **Максимальная емкость**: До 65 535 элементов (ограничение 16-битного индекса) - **Максимальная емкость**: До 65 535 элементов (ограничение 16-битного индекса)
5. **Оптимизировано под ESP-IDF**: Использует функции heap_caps для выделения памяти с параметрами памяти - **Оптимизировано под ESP-IDF**: Использует функции heap_caps для выделения памяти с параметрами памяти
6. **Обработка ошибок**: Комплексная проверка ошибок с детальным логированием - **Обработка ошибок**: Комплексная проверка ошибок с детальным логированием
7. **Потокобезопасность**: Является потокобезопасным (использует FreeRTOS mutex) - **Потокобезопасность**: Является потокобезопасным (использует FreeRTOS mutex)
8. **Минимальные накладные расходы**: Низкие накладные расходы на память и процессор - **Минимальные накладные расходы**: Низкие накладные расходы на память и процессор
--- ---
## Установка ## Установка
1. Перейдите в каталог компонентов вашего проекта: Перейдите в каталог компонентов вашего проекта:
```bash ```bash
cd ../ваш_проект/components cd ../ваш_проект/components
``` ```
2. Клонируйте репозиторий: Клонируйте репозиторий:
```bash ```bash
git clone https://github.com/aZholtikov/zh_vector git clone https://github.com/aZholtikov/zh_vector
``` ```
3. В вашем приложении подключите заголовочный файл: В вашем приложении подключите заголовочный файл:
```c ```c
#include "zh_vector.h" #include "zh_vector.h"
``` ```
4. Компонент будет автоматически собран вместе с вашим проектом. Компонент будет автоматически собран вместе с вашим проектом.
--- ---
## Справочник API ## Справочник API
Все функции в этой библиотеке используют double pointer (`zh_vector_t **`) для параметра вектора, чтобы обеспечить правильное управление памятью и потокобезопасные операции.
### Структура zh_vector_t ### Структура zh_vector_t
```c Структура объявляется как `typedef struct _zh_vector_t zh_vector_t;` и инкапсулирует внутренние детали реализации.
typedef struct
{ **Поля (внутренние):**
void **items; // Массив указателей на элементы вектора
uint16_t capacity; // Максимальная емкость вектора | Поле | Тип | Описание |
uint16_t size; // Количество элементов в векторе |------|-----|----------|
uint16_t unit; // Размер элемента вектора (в байтах) | `items` | `void **` | Массив указателей на элементы вектора. Items[0..size-1] являются валидными. Выделяется через heap_caps_calloc, перераспределяется через heap_caps_realloc. |
bool is_initialized; // Флаг состояния инициализации вектора | `capacity` | `uint16_t` | Текущая выделенная емкость (количество слотов). Увеличивается при вставке — может превышать size после удалений. |
SemaphoreHandle_t mutex; // FreeRTOS mutex для потокобезопасности | `size` | `uint16_t` | Текущее количество элементов (0 ≤ size ≤ capacity). |
} zh_vector_t; | `unit` | `uint16_t` | Размер (в байтах) одного элемента. Устанавливается при инициализации и не должен меняться. |
``` | `mutex` | `SemaphoreHandle_t` | FreeRTOS mutex. Создается в zh_vector_init, удаляется в zh_vector_free. Автоматически блокируется/разблокируется в публичных функциях. |
--- ---
@@ -83,39 +85,44 @@ typedef struct
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Если указатель на вектор равен NULL, будет выделена память.
- `unit` - Размер каждого элемента в байтах - `unit` - Размер каждого элемента в байтах
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL вектор или нулевой размер unit) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на вектор или нулевой размер unit)
- `ESP_ERR_INVALID_STATE` - Вектор уже инициализирован - `ESP_ERR_INVALID_STATE` - Вектор уже инициализирован
- `ESP_ERR_NO_MEM` - Ошибка выделения памяти
**Пример:** **Пример:**
```c ```c
zh_vector_t vector = {0}; zh_vector_t *vector = NULL;
zh_vector_init(&vector, sizeof(int)); // Для целых чисел esp_err_t ret = zh_vector_init(&vector, sizeof(int)); // Для целых чисел
if (ret != ESP_OK) {
// Обработка ошибки
}
// Не забудьте освободить: zh_vector_free(&vector);
``` ```
--- ---
### zh_vector_free() ### zh_vector_free()
Деинициализирует вектор и освобождает всю выделенную память. Деинициализирует вектор и освобождает всю выделенную память. Устанавливает указатель на вектор в NULL.
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL вектор) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или NULL указатель на вектор)
- `ESP_ERR_INVALID_STATE` - Вектор не инициализирован - `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
**Примечание:** Вся динамически выделенная память элементов также освобождается. **Примечание:** Вся динамически выделенная память элементов также освобождается. Указатель на вектор устанавливается в NULL после деинициализации.
--- ---
@@ -125,12 +132,14 @@ zh_vector_init(&vector, sizeof(int)); // Для целых чисел
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
- `size` - Указатель на переменную для сохранения размера. Не должен быть NULL.
**Возвращает:** **Возвращает:**
- `>= 0` - Количество элементов (успех) - `ESP_OK` - Успех
- `ESP_FAIL` - Ошибка (NULL вектор или не инициализирован) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или size)
- `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
--- ---
@@ -140,15 +149,15 @@ zh_vector_init(&vector, sizeof(int)); // Для целых чисел
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
- `item` - Указатель на элемент для добавления - `item` - Указатель на элемент для добавления. Не должен быть NULL.
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL вектор или item) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или item)
- `ESP_ERR_INVALID_STATE` - Вектор не инициализирован
- `ESP_ERR_NO_MEM` - Ошибка выделения памяти - `ESP_ERR_NO_MEM` - Ошибка выделения памяти
- `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
**Примечание:** Функция выделяет память для копии элемента и копирует данные. Все существующие элементы сдвигаются на одну позицию вправо. **Примечание:** Функция выделяет память для копии элемента и копирует данные. Все существующие элементы сдвигаются на одну позицию вправо.
@@ -160,15 +169,15 @@ zh_vector_init(&vector, sizeof(int)); // Для целых чисел
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
- `item` - Указатель на элемент для добавления - `item` - Указатель на элемент для добавления. Не должен быть NULL.
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL вектор или item) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или item)
- `ESP_ERR_INVALID_STATE` - Вектор не инициализирован
- `ESP_ERR_NO_MEM` - Ошибка выделения памяти - `ESP_ERR_NO_MEM` - Ошибка выделения памяти
- `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
**Примечание:** Функция выделяет память для копии элемента и копирует данные. **Примечание:** Функция выделяет память для копии элемента и копирует данные.
@@ -180,34 +189,35 @@ zh_vector_init(&vector, sizeof(int)); // Для целых чисел
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
- `index` - Индекс элемента для изменения (начиная с 0) - `index` - Индекс элемента для изменения (начиная с 0). Должен быть < размера вектора.
- `item` - Указатель на новые данные элемента - `item` - Указатель на новые данные элемента. Не должен быть NULL.
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL вектор, item или неверный индекс) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор, item или неверный индекс)
- `ESP_ERR_INVALID_STATE` - Вектор не инициализирован - `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
- `ESP_FAIL` - Индекс вне границ
--- ---
### zh_vector_get_item() ### zh_vector_get_item()
Получает элемент по определенному индексу. Получает элемент по определенному индексу, копируя его в предоставленный буфер пользователя.
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
- `index` - Индекс элемента для получения (начиная с 0) - `index` - Индекс элемента для получения (начиная с 0).
- `item` - Указатель на буфер размером не менее `unit` байт, куда будет скопирован элемент. Не должен быть NULL.
**Возвращает:** **Возвращает:**
- Указатель на элемент (успех) - `ESP_OK` - Успех
- `NULL` - Ошибка (NULL вектор, не инициализирован или неверный индекс) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор, NULL указатель item или неверный индекс)
- `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
**Примечание:** Возвращает указатель на внутренние данные. Не освобождайте этот указатель. **Примечание:** Эта функция копирует данные элемента в предоставленный буфер. Указатели не возвращаются.
--- ---
@@ -217,17 +227,17 @@ zh_vector_init(&vector, sizeof(int)); // Для целых чисел
**Параметры:** **Параметры:**
- `vector` - Указатель на структуру вектора - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
- `index` - Индекс элемента для удаления (начиная с 0) - `index` - Индекс элемента для удаления (начиная с 0). Должен быть < размера вектора.
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL вектор) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или неверный индекс)
- `ESP_ERR_INVALID_STATE` - Вектор не инициализирован - `ESP_ERR_NO_MEM` - Ошибка выделения памяти (при перераспределении)
- `ESP_FAIL` - Индекс вне границ - `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
**Примечание:** Все элементы после удаляемого индекса сдвигаются влево на одну позицию. **Примечание:** Все элементы после удаляемого индекса сдвигаются влево на одну позицию. Память удаленного элемента освобождается.
--- ---
@@ -238,36 +248,58 @@ zh_vector_init(&vector, sizeof(int)); // Для целых чисел
```c ```c
#include "zh_vector.h" #include "zh_vector.h"
zh_vector_t int_vector = {0};
void app_main(void) void app_main(void)
{ {
esp_log_level_set("zh_vector", ESP_LOG_ERROR); esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для целых чисел // Инициализация вектора для целых чисел
zh_vector_init(&int_vector, sizeof(int)); esp_err_t ret = zh_vector_init(&vector, sizeof(int));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление элементов // Добавление элементов
int val1 = 10; int val1 = 10;
int val2 = 20; int val2 = 20;
int val3 = 30; int val3 = 30;
zh_vector_push_front(&int_vector, &val1); zh_vector_push_front(&vector, &val1);
zh_vector_push_back(&int_vector, &val2); zh_vector_push_back(&vector, &val2);
zh_vector_push_back(&int_vector, &val3); zh_vector_push_back(&vector, &val3);
printf("Размер вектора: %d\n", zh_vector_get_size(&int_vector));
// Доступ к элементам size_t size;
for (int i = 0; i < zh_vector_get_size(&int_vector); i++) { ret = zh_vector_get_size(&vector, &size);
int *item = (int *)zh_vector_get_item(&int_vector, i); if (ret == ESP_OK) {
printf("Элемент %d: %d\n", i, *item); printf("Размер вектора: %zu\n", size);
} }
// Доступ к элементам
for (int i = 0; i < size; i++) {
int item_value;
esp_err_t err = zh_vector_get_item(&vector, (uint16_t)i, &item_value);
if (err == ESP_OK) {
printf("Элемент %d: %d\n", i, item_value);
} else {
printf("Ошибка получения элемента %d: %s\n", i, esp_err_to_name(err));
}
}
// Изменение элемента // Изменение элемента
int new_val = 100; int new_val = 100;
zh_vector_change_item(&int_vector, 1, &new_val); zh_vector_change_item(&vector, 1, &new_val);
// Удаление элемента // Удаление элемента
zh_vector_delete_item(&int_vector, 0); zh_vector_delete_item(&vector, 0);
// Очистка // Очистка
zh_vector_free(&int_vector); zh_vector_free(&vector);
} }
``` ```
---
### Пример со структурой ### Пример со структурой
```c ```c
@@ -279,52 +311,82 @@ typedef struct {
float value; float value;
} my_struct_t; } my_struct_t;
zh_vector_t struct_vector = {0};
void app_main(void) void app_main(void)
{ {
esp_log_level_set("zh_vector", ESP_LOG_ERROR); esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для структур // Инициализация вектора для структур
zh_vector_init(&struct_vector, sizeof(my_struct_t)); esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление элементов-структур // Добавление элементов-структур
my_struct_t item1 = {1, "Item 1", 1.5f}; my_struct_t item1 = {1, "Item 1", 1.5f};
my_struct_t item2 = {2, "Item 2", 2.5f}; my_struct_t item2 = {2, "Item 2", 2.5f};
zh_vector_push_front(&struct_vector, &item1); zh_vector_push_front(&vector, &item1);
zh_vector_push_back(&struct_vector, &item2); zh_vector_push_back(&vector, &item2);
// Доступ и модификация // Доступ и модификация
my_struct_t *ptr = (my_struct_t *)zh_vector_get_item(&struct_vector, 0); my_struct_t item_value;
ptr->value = 10.5f; esp_err_t err = zh_vector_get_item(&vector, 0, &item_value);
if (err == ESP_OK) {
item_value.value = 10.5f;
zh_vector_change_item(&vector, 0, &item_value);
}
// Очистка // Очистка
zh_vector_free(&struct_vector); zh_vector_free(&vector);
} }
``` ```
---
### Пример со строками (массивы символов) ### Пример со строками (массивы символов)
```c ```c
#include "zh_vector.h" #include "zh_vector.h"
#include "string.h"
zh_vector_t string_vector = {0};
void app_main(void) void app_main(void)
{ {
esp_log_level_set("zh_vector", ESP_LOG_ERROR); esp_log_level_set("zh_vector", ESP_LOG_ERROR);
// Инициализация вектора для строк (макс. 100 символов)
zh_vector_t *vector = NULL;
char buffer[100] = {0}; char buffer[100] = {0};
zh_vector_init(&string_vector, sizeof(buffer));
// Инициализация вектора для строк (макс. 100 символов)
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление строк // Добавление строк
strcpy(buffer, "Привет"); strcpy(buffer, "Привет");
zh_vector_push_front(&string_vector, &buffer); zh_vector_push_front(&vector, &buffer);
strcpy(buffer, "Мир"); strcpy(buffer, "Мир");
zh_vector_push_back(&string_vector, &buffer); zh_vector_push_back(&vector, &buffer);
// Печать всех строк
for (int i = 0; i < zh_vector_get_size(&string_vector); i++) { size_t size;
char *str = (char *)zh_vector_get_item(&string_vector, i); ret = zh_vector_get_size(&vector, &size);
printf("Строка %d: %s\n", i, str); if (ret == ESP_OK) {
// Печать всех строк
for (int i = 0; i < size; i++) {
char str_value[100];
esp_err_t err = zh_vector_get_item(&vector, (uint16_t)i, str_value);
if (err == ESP_OK) {
printf("Строка %d: %s\n", i, str_value);
} else {
printf("Ошибка получения строки %d: %s\n", i, esp_err_to_name(err));
}
}
} }
// Очистка // Очистка
zh_vector_free(&string_vector); zh_vector_free(&vector);
} }
``` ```
@@ -351,9 +413,8 @@ void app_main(void)
|------------|----------| |------------|----------|
| `ESP_OK` | Операция выполнена успешно | | `ESP_OK` | Операция выполнена успешно |
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или нулевой размер) | | `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или нулевой размер) |
| `ESP_ERR_INVALID_STATE` | Вектор не инициализирован или уже инициализирован | | `ESP_ERR_INVALID_STATE` | Не удалось захватить mutex (редкий системный сбой) |
| `ESP_ERR_NO_MEM` | Ошибка выделения памяти (не хватает памяти) | | `ESP_ERR_NO_MEM` | Ошибка выделения памяти (не хватает памяти) |
| `ESP_FAIL` | Общий сбой (например, индекс вне границ) |
--- ---
@@ -405,4 +466,4 @@ void app_main(void)
--- ---
*Сгенерировано для zh_vector v1.3.0* *Сгенерировано для zh_vector v2.0.0*
+1 -1
View File
@@ -1,6 +1,6 @@
description: ESP32 ESP-IDF component for vector (dynamic array) description: ESP32 ESP-IDF component for vector (dynamic array)
url: https://github.com/aZholtikov/zh_vector url: https://github.com/aZholtikov/zh_vector
version: "1.3.0" version: "2.0.0"
license: "Apache-2.0" license: "Apache-2.0"
maintainers: maintainers:
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>" - "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
+111 -50
View File
@@ -1,10 +1,19 @@
/** /**
* @file zh_vector.h * @file zh_vector.h
*
* @brief Thread-safe dynamic array (vector) implementation for ESP-IDF.
*
* This vector stores elements by pointer (i.e., it holds `void*` to heap-allocated copies of items).
* The vector is protected by a FreeRTOS mutex, making it safe for use in multi-threaded environments.
*
* @note The vector allocates memory for each item on push operations.
* @note The vector does **not** own the lifetime of the data pointed to by the user — it copies the data.
* @warning The `item` parameter of zh_vector_get_item must point to a buffer of at least `unit` bytes.
* The function copies the element *by value* — no pointers are returned.
*/ */
#pragma once #pragma once
#include "string.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
@@ -17,96 +26,148 @@ extern "C"
#endif #endif
/** /**
* @brief Main structure of vector data. * @brief Opaque vector type.
*/ */
typedef struct typedef struct _zh_vector_t zh_vector_t;
{
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. */
uint16_t unit; /*!< Vector item size. */
bool is_initialized; /*!< Vector initialization status flag. */
SemaphoreHandle_t mutex; /*!< FreeRTOS mutex. */
} zh_vector_t;
/** /**
* @brief Initialize vector. * @brief Initializes a vector.
* *
* @param[in] vector Pointer to main structure of vector data. * Allocates memory for the vector structure, internal item pointer array and a FreeRTOS mutex.
* @param[in] unit Size of vector item.
* *
* @return ESP_OK if success or an error code otherwise. * @note Safe to call with `*vector == NULL` or with `*vector` pointing to uninitialized memory.
* @warning Do **not** call this function twice on the same variable without an intervening `zh_vector_free()` — it will return `ESP_ERR_INVALID_STATE`.
* To reuse a vector, call `zh_vector_free(&v);` then `zh_vector_init(&v, ...);`.
*
* @param[out] vector Double pointer to vector structure (`zh_vector_t **`). On success, `*vector` points to newly allocated structure.
* @param[in] unit Size (in bytes) of each item. Must be > 0.
*
* @return ESP_OK on success.
* @return ESP_ERR_NO_MEM if memory allocation fails (vector struct or mutex).
* @return ESP_ERR_INVALID_ARG if `vector == NULL` or `unit == 0`.
* @return ESP_ERR_INVALID_STATE if `*vector != NULL` (already initialized).
*/ */
esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit, ...); esp_err_t zh_vector_init(zh_vector_t **vector, uint16_t unit);
/** /**
* @brief Deinitialize vector. Free all allocated memory. * @brief Deinitializes and frees the entire vector.
* *
* @param[in] vector Pointer to main structure of vector data. * Frees all item copies, the internal pointer array, and the mutex. Sets `*vector` to `NULL` before returning.
* *
* @return ESP_OK if success or an error code otherwise. * @warning After this call, all previously obtained item pointers become invalid.
* @note Safe to call with `vector == NULL` or `*vector == NULL` (returns `ESP_OK`).
*
* @param[in,out] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`. Set to `NULL` on exit.
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL` or `*vector == NULL` (not initialized).
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
esp_err_t zh_vector_free(zh_vector_t *vector); esp_err_t zh_vector_free(zh_vector_t **vector);
/** /**
* @brief Get current vector size. * @brief Gets the current number of items in the vector.
* *
* @param[in] vector Pointer to main structure of vector data. * @note Thread-safe: internally locks/unlocks the mutex.
* *
* @return Vector size if success or ESP_FAIL otherwise. * @param[in] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
* @param[out] size Pointer to store the number of items. Must not be `NULL`.
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL` or `size == NULL` or `*vector == NULL` (not initialized).
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
esp_err_t zh_vector_get_size(zh_vector_t *vector); esp_err_t zh_vector_get_size(zh_vector_t **vector, uint16_t *size);
/** /**
* @brief Add item at beginning of vector. * @brief Adds a copy of the item to the beginning of the vector.
* *
* @param[in] vector Pointer to main structure of vector data. * A copy of `item` is allocated on the heap and stored in the vector.
* @param[in] item Pointer to item for add. * The vector owns the lifetime of this copy (freed on `zh_vector_free()` or `zh_vector_delete_item()`).
* All existing items are shifted one position to the right.
* This may involve reallocation of the internal pointer array via `heap_caps_realloc`.
* *
* @return ESP_OK if success or an error code otherwise. * @note Memory for the item and potential reallocation is done via `heap_caps_calloc`/`heap_caps_realloc` (`MALLOC_CAP_8BIT`).
*
* @param[in,out] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
* @param[in] item Pointer to the data to copy into the new item. Must not be `NULL`.
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL` or `item == NULL` or `*vector == NULL` (not initialized).
* @return ESP_ERR_NO_MEM if memory allocation fails.
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
esp_err_t zh_vector_push_front(zh_vector_t *vector, void *item); esp_err_t zh_vector_push_front(zh_vector_t **vector, const void *item);
/** /**
* @brief Add item at end of vector. * @brief Adds a copy of the item to the end of the vector.
* *
* @param[in] vector Pointer to main structure of vector data. * A copy of `item` is allocated on the heap and stored in the vector.
* @param[in] item Pointer to item for add. * The vector owns the lifetime of this copy (freed on `zh_vector_free()` or `zh_vector_delete_item()`).
* This may involve reallocation of the internal pointer array via `heap_caps_realloc`.
* *
* @return ESP_OK if success or an error code otherwise. * @note Memory for the item and potential reallocation is done via `heap_caps_calloc`/`heap_caps_realloc` (`MALLOC_CAP_8BIT`).
*
* @param[in,out] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
* @param[in] item Pointer to the data to copy into the new item. Must not be `NULL`.
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL` or `item == NULL` or `*vector == NULL` (not initialized).
* @return ESP_ERR_NO_MEM if memory allocation fails.
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item); esp_err_t zh_vector_push_back(zh_vector_t **vector, const void *item);
/** /**
* @brief Change item by index. * @brief Replaces the item at the specified index with a copy of the provided data.
* *
* @param[in] vector Pointer to main structure of vector data. * @warning Modifies the existing item *in-place* — no new memory allocation occurs.
* @param[in] index Index of item for change. * Only the data is overwritten (via `memcpy`). The item size must match the vector’s `unit`.
* @param[in] item Pointer to new data of item.
* *
* @return ESP_OK if success or an error code otherwise. * @param[in,out] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
* @param[in] index Index of the item to replace (must be < `(*vector)->size`).
* @param[in] item Pointer to new data to copy into the item. Must not be `NULL`.
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL`, `item == NULL`, `index >= (*vector)->size` or `*vector == NULL` (not initialized).
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
esp_err_t zh_vector_change_item(zh_vector_t *vector, uint16_t index, void *item); esp_err_t zh_vector_change_item(zh_vector_t **vector, uint16_t index, const void *item);
/** /**
* @brief Get item by index. * @brief Retrieves the item at the specified index by copying it into the user-provided buffer.
* *
* @param[in] vector Pointer to main structure of vector data. * @note Thread-safe: internally locks/unlocks the mutex.
* @param[in] index Index of item for get. * @note This function **copies** the element — no pointers are returned or stored.
* *
* @return Pointer to item or NULL otherwise. * @param[in] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
* @param[in] index Index of the item to retrieve (0-based).
* @param[out] item Pointer to a buffer of at least `unit` bytes, where the item will be copied.
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL`, `item == NULL`, `index >= (*vector)->size` or `*vector == NULL` (not initialized).
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
void *zh_vector_get_item(zh_vector_t *vector, uint16_t index); esp_err_t zh_vector_get_item(zh_vector_t **vector, uint16_t index, void *item);
/** /**
* @brief Delete item by index and shifts all elements in vector. * @brief Deletes the item at the specified index and shifts subsequent items one position left.
* *
* @param[in] vector Pointer to main structure of vector data. * The deleted item’s memory is freed.
* @param[in] index Index of item for delete. * If the size drops below half of the capacity (and size > 0), the capacity is reduced via `_resize(size)`.
* If the size reaches 0, capacity is set to 0 and the pointer array is freed.
* *
* @return ESP_OK if success or an error code otherwise. * @note Thread-safe: internally locks/unlocks the mutex.
*
* @param[in,out] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
* @param[in] index Index of the item to delete (must be < `(*vector)->size`).
*
* @return ESP_OK on success.
* @return ESP_ERR_INVALID_ARG if `vector == NULL`, `index >= (*vector)->size` or `*vector == NULL` (not initialized).
* @return ESP_ERR_NO_MEM if memory allocation fails.
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
*/ */
esp_err_t zh_vector_delete_item(zh_vector_t *vector, uint16_t index); esp_err_t zh_vector_delete_item(zh_vector_t **vector, uint16_t index);
#ifdef __cplusplus #ifdef __cplusplus
} }
+1 -1
View File
@@ -1 +1 @@
1.3.0 2.0.0
+165 -105
View File
@@ -13,167 +13,202 @@ static const char *TAG = "zh_vector";
return err; \ return err; \
} }
static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity); /**
* @brief Internal representation of a thread-safe, dynamically resizing vector of *copied* elements.
*
* Stores pointers to heap-allocated *copies* of elements (not raw pointers).
* Elements (stored in items[i]) are allocated via heap_caps_calloc(1, unit, ...) and freed via heap_caps_free.
* Supports push front/back, change, delete and size queries.
* Thread safety via FreeRTOS mutex.
*
* @note Opaque type: only zh_vector_t (typedef struct _zh_vector_t* zh_vector_t) is exposed.
* @note Elements are deep-copied — ownership of input item is NOT transferred.
* @note All public functions lock the mutex internally — no external locking required.
* Internal functions _resize() and _calc_new_capacity() are not thread-safe and must be called
* only while the vector's mutex is held.
* @note Internal function _resize() guarantees invariant: 0 ≤ size ≤ capacity.
* In particular, _resize(..., 0) always sets size = 0, capacity = 0, and frees all element buffers.
* @note The capacity may exceed size after deletions (memory is not shrunk immediately),
* and is reduced only via _resize() on explicit request (e.g., during delete).
*
* @warning Do not access fields directly — always use public API.
* @warning unit must match the actual element size — mismatch causes heap corruption.
* @note capacity and size are limited to uint16_t (max 65535 elements), to save memory on embedded devices.
* @note items is allocated via heap_caps_realloc as `void*`, but logically treated as `void**`.
* Each valid items[i] (0 ≤ i < size) points to a heap buffer of exactly `unit` bytes (allocated via heap_caps_calloc(1, unit, ...)).
* Only the first `unit` bytes are used for the copied item.
* @warning Actual memory usage depends on allocator overhead and alignment.
* Rough estimate: `sizeof(zh_vector_t) + capacity * sizeof(void*) + size * (unit + item_overhead)`.
* Typical heap overhead per item: ~16 bytes (metadata + alignment).
* @note Capacity reduction is triggered when `size < capacity / 2` (integer division). For example:
* - capacity=4, size=1 → capacity=1 (4/2=2 > 1)
* - capacity=2, size=1 → capacity stays 2 (2/2=1 not > 1)
* - capacity=1, size=0 → capacity=0 (handled separately: size==0 && capacity>0)
* @note When size reaches 0, capacity is always set to 0, even without explicit resize request.
*/
struct _zh_vector_t
{
void **items; /*!< Array of element pointers. items[0..size-1] are valid and non-NULL. Initially NULL; allocated via heap_caps_realloc (as `void*`, cast to `void**`). When capacity > old_capacity, new slots (items[old_capacity..capacity-1]) are zeroed (NULL). */
uint16_t capacity; /*!< Current allocated capacity (number of slots). Grows on insertion, shrinks on delete (see _resize). Limited to uint16_t (max 65535). */
uint16_t size; /*!< Current number of valid elements (0 ≤ size ≤ capacity). Always kept in sync: _resize(..., 0) sets size = 0; after push operations size++; after delete size--. */
uint16_t unit; /*!< Size (in bytes) of a single element. Set once in zh_vector_init() and immutable. Must match the actual element size — mismatch causes heap corruption. */
SemaphoreHandle_t mutex; /*!< FreeRTOS mutex. Created in zh_vector_init() and deleted in zh_vector_free(). All public functions acquire it before accessing/modifying the vector state. The mutex itself does not affect logical state (`size`, `capacity`). */
};
esp_err_t zh_vector_init(zh_vector_t *vector, uint16_t unit, ...) static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity);
static inline uint16_t _calc_new_capacity(uint16_t current);
esp_err_t zh_vector_init(zh_vector_t **vector, uint16_t unit) // -V2008
{ {
ZH_LOGI("Vector initialization begin."); ZH_LOGI("Vector initialization begin.");
ZH_ERROR_CHECK(vector != NULL && unit != 0, ESP_ERR_INVALID_ARG, NULL, "Vector initialization failed. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && unit > 0, ESP_ERR_INVALID_ARG, NULL, "Vector initialization failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == false, ESP_ERR_INVALID_STATE, NULL, "Vector initialization failed. Vector is already initialized."); ZH_ERROR_CHECK(*vector == NULL, ESP_ERR_INVALID_STATE, NULL, "Vector initialization failed. Vector is already initialized.");
vector->mutex = xSemaphoreCreateMutex(); *vector = heap_caps_calloc(1, sizeof(zh_vector_t), MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(vector->mutex != NULL, ESP_ERR_NO_MEM, NULL, "Vector initialization failed. Failed to create mutex."); ZH_ERROR_CHECK(*vector != NULL, ESP_ERR_NO_MEM, NULL, "Vector initialization failed. Failed to allocate vector structure.");
vector->items = NULL; (*vector)->mutex = xSemaphoreCreateMutex();
vector->capacity = 0; ZH_ERROR_CHECK((*vector)->mutex != NULL, ESP_ERR_NO_MEM, heap_caps_free(*vector); *vector = NULL, "Vector initialization failed. Failed to create mutex.");
vector->size = 0; (*vector)->items = NULL;
vector->unit = unit; (*vector)->capacity = 0;
vector->is_initialized = true; (*vector)->size = 0;
(*vector)->unit = unit;
ZH_LOGI("Vector initialization success."); ZH_LOGI("Vector initialization success.");
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_vector_free(zh_vector_t *vector) esp_err_t zh_vector_free(zh_vector_t **vector)
{ {
ZH_LOGI("Vector deletion begin."); ZH_LOGI("Vector deletion begin.");
ZH_ERROR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Vector deletion failed. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && *vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Vector deletion failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Vector deletion fail. Vector not initialized."); ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Vector deletion failed. Failed to acquire mutex.");
ZH_ERROR_CHECK(xSemaphoreTake(vector->mutex, portMAX_DELAY) == pdTRUE, ESP_FAIL, NULL, "Vector deletion fail. Failed to acquire mutex."); for (uint16_t i = 0; i < (*vector)->size; ++i)
for (uint16_t i = 0; i < vector->size; ++i)
{ {
if (vector->items[i] != NULL) if ((*vector)->items[i] != NULL)
{ {
heap_caps_free(vector->items[i]); heap_caps_free((*vector)->items[i]);
vector->items[i] = NULL; (*vector)->items[i] = NULL;
} }
} }
heap_caps_free(vector->items); heap_caps_free((*vector)->items);
vector->items = NULL; (*vector)->items = NULL;
vector->size = 0; (*vector)->size = 0;
vector->capacity = 0; (*vector)->capacity = 0;
vSemaphoreDelete(vector->mutex); vSemaphoreDelete((*vector)->mutex);
vector->mutex = NULL; (*vector)->mutex = NULL;
vector->is_initialized = false; heap_caps_free(*vector);
*vector = NULL;
ZH_LOGI("Vector deletion success."); ZH_LOGI("Vector deletion success.");
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_vector_get_size(zh_vector_t *vector) esp_err_t zh_vector_get_size(zh_vector_t **vector, uint16_t *size)
{ {
ZH_LOGI("Getting vector size begin."); ZH_LOGI("Getting vector size begin.");
ZH_ERROR_CHECK(vector != NULL, ESP_FAIL, NULL, "Getting vector size fail. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && *vector != NULL && size != NULL, ESP_ERR_INVALID_ARG, NULL, "Getting vector size failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == true, ESP_FAIL, NULL, "Getting vector size fail. Vector not initialized."); ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Getting vector size failed. Failed to acquire mutex.");
ZH_ERROR_CHECK(xSemaphoreTake(vector->mutex, portMAX_DELAY) == pdTRUE, ESP_FAIL, NULL, "Getting vector size fail. Failed to acquire mutex."); *size = (*vector)->size;
size_t size = vector->size; xSemaphoreGive((*vector)->mutex);
xSemaphoreGive(vector->mutex);
ZH_LOGI("Getting vector size success."); ZH_LOGI("Getting vector size success.");
return (esp_err_t)size; return ESP_OK;
} }
esp_err_t zh_vector_push_front(zh_vector_t *vector, void *item) // -V2008 esp_err_t zh_vector_push_front(zh_vector_t **vector, const void *item)
{ {
ZH_LOGI("Adding item to beginning of vector begin."); ZH_LOGI("Adding item to beginning of vector begin.");
ZH_ERROR_CHECK(vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Adding item to beginning of vector fail. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && *vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Adding item to beginning of vector failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Adding item to beginning of vector fail. Vector not initialized."); ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Adding item to beginning of vector failed. Failed to acquire mutex.");
ZH_ERROR_CHECK(xSemaphoreTake(vector->mutex, portMAX_DELAY) == pdTRUE, ESP_FAIL, NULL, "Adding item to beginning of vector fail. Failed to acquire mutex."); ZH_ERROR_CHECK((*vector)->size < UINT16_MAX, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Adding item to beginning of vector failed. Vector is full.");
if (vector->capacity == vector->size) if ((*vector)->capacity == (*vector)->size)
{ {
ZH_ERROR_CHECK(_resize(vector, vector->capacity + 1) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive(vector->mutex), "Adding item to beginning of vector fail. Memory allocation fail or no free memory in the heap."); uint16_t new_capacity = _calc_new_capacity((*vector)->capacity);
ZH_ERROR_CHECK(_resize(*vector, new_capacity) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Adding item to beginning of vector failed. Memory reallocation failed.");
} }
for (uint16_t i = vector->size; i > 0; --i) for (uint16_t i = (*vector)->size; i > 0; --i)
{ {
vector->items[i] = vector->items[i - 1]; (*vector)->items[i] = (*vector)->items[i - 1];
} }
vector->items[0] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); (*vector)->items[0] = heap_caps_calloc(1, (*vector)->unit, MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(vector->items[0] != NULL, ESP_ERR_NO_MEM, xSemaphoreGive(vector->mutex), "Adding item to beginning of vector fail. Memory allocation fail or no free memory in the heap."); ZH_ERROR_CHECK((*vector)->items[0] != NULL, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Adding item to beginning of vector failed. Element allocation failed.");
memcpy(vector->items[0], item, vector->unit); memcpy((*vector)->items[0], item, (*vector)->unit);
vector->size++; (*vector)->size++;
xSemaphoreGive(vector->mutex); xSemaphoreGive((*vector)->mutex);
ZH_LOGI("Adding item to beginning of vector success."); ZH_LOGI("Adding item to beginning of vector success.");
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_vector_push_back(zh_vector_t *vector, void *item) // -V2008 esp_err_t zh_vector_push_back(zh_vector_t **vector, const void *item)
{ {
ZH_LOGI("Adding item to vector begin."); ZH_LOGI("Adding item to vector begin.");
ZH_ERROR_CHECK(vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Adding item to vector fail. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && *vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Adding item to vector failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Adding item to vector fail. Vector not initialized."); ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Adding item to vector failed. Failed to acquire mutex.");
ZH_ERROR_CHECK(xSemaphoreTake(vector->mutex, portMAX_DELAY) == pdTRUE, ESP_FAIL, NULL, "Adding item to vector fail. Failed to acquire mutex."); ZH_ERROR_CHECK((*vector)->size < UINT16_MAX, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Adding item to vector failed. Vector is full.");
if (vector->capacity == vector->size) if ((*vector)->capacity == (*vector)->size)
{ {
ZH_ERROR_CHECK(_resize(vector, vector->capacity + 1) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive(vector->mutex), "Adding item to vector fail. Memory allocation fail or no free memory in the heap."); uint16_t new_capacity = _calc_new_capacity((*vector)->capacity);
ZH_ERROR_CHECK(_resize(*vector, new_capacity) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Adding item to vector failed. Memory reallocation failed.");
} }
uint16_t idx = vector->size; uint16_t idx = (*vector)->size;
vector->items[idx] = heap_caps_calloc(1, vector->unit, MALLOC_CAP_8BIT); (*vector)->items[idx] = heap_caps_calloc(1, (*vector)->unit, MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(vector->items[idx] != NULL, ESP_ERR_NO_MEM, xSemaphoreGive(vector->mutex), "Adding item to vector fail. Memory allocation fail or no free memory in the heap."); ZH_ERROR_CHECK((*vector)->items[idx] != NULL, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Adding item to vector failed. Element allocation failed.");
memcpy(vector->items[idx], item, vector->unit); memcpy((*vector)->items[idx], item, (*vector)->unit);
vector->size++; (*vector)->size++;
xSemaphoreGive(vector->mutex); xSemaphoreGive((*vector)->mutex);
ZH_LOGI("Adding item to vector success."); ZH_LOGI("Adding item to vector success.");
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_vector_change_item(zh_vector_t *vector, uint16_t index, void *item) // -V2008 esp_err_t zh_vector_change_item(zh_vector_t **vector, uint16_t index, const void *item)
{ {
ZH_LOGI("Changing item in vector begin."); ZH_LOGI("Changing item in vector begin.");
ZH_ERROR_CHECK(vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Changing item in vector fail. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && *vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Changing item in vector failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Changing item in vector fail. Vector not initialized."); ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Changing item in vector failed. Failed to acquire mutex.");
ZH_ERROR_CHECK(xSemaphoreTake(vector->mutex, portMAX_DELAY) == pdTRUE, ESP_FAIL, NULL, "Changing item in vector fail. Failed to acquire mutex."); ZH_ERROR_CHECK(index < (*vector)->size, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Changing item in vector failed. Index out of bounds.");
ZH_ERROR_CHECK(index < vector->size, ESP_FAIL, NULL, "Changing item in vector fail. Index does not exist."); ZH_ERROR_CHECK((*vector)->items[index] != NULL, ESP_ERR_INVALID_STATE, xSemaphoreGive((*vector)->mutex), "Changing item in vector failed. Item is NULL.");
memcpy(vector->items[index], item, vector->unit); memcpy((*vector)->items[index], item, (*vector)->unit);
xSemaphoreGive(vector->mutex); xSemaphoreGive((*vector)->mutex);
ZH_LOGI("Changing item in vector success."); ZH_LOGI("Changing item in vector success.");
return ESP_OK; return ESP_OK;
} }
void *zh_vector_get_item(zh_vector_t *vector, uint16_t index) // -V2008 esp_err_t zh_vector_get_item(zh_vector_t **vector, uint16_t index, void *item)
{ {
ZH_LOGI("Getting item from vector begin."); ZH_LOGI("Getting item from vector begin.");
if (vector == NULL) ZH_ERROR_CHECK(vector != NULL && *vector != NULL && item != NULL, ESP_ERR_INVALID_ARG, NULL, "Getting item from vector failed. Invalid argument.");
{ ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Getting item from vector failed. Failed to acquire mutex.");
ZH_LOGE("Getting item from vector fail. Invalid argument.", ESP_ERR_INVALID_ARG); ZH_ERROR_CHECK(index < (*vector)->size, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Getting item from vector failed. Index out of bounds.");
return NULL; ZH_ERROR_CHECK((*vector)->items[index] != NULL, ESP_ERR_INVALID_STATE, xSemaphoreGive((*vector)->mutex), "Getting item from vector failed. Item is NULL.");
} memcpy(item, (*vector)->items[index], (*vector)->unit);
if (vector->is_initialized == false) xSemaphoreGive((*vector)->mutex);
{
ZH_LOGE("Getting item from vector fail. Vector not initialized.", ESP_ERR_INVALID_STATE);
return NULL;
}
if (xSemaphoreTake(vector->mutex, portMAX_DELAY) != pdTRUE)
{
ZH_LOGE("Getting item from vector fail. Failed to acquire mutex.", ESP_FAIL);
return NULL;
}
void *item = NULL;
if (index >= vector->size)
{
xSemaphoreGive(vector->mutex);
ZH_LOGE("Getting item from vector fail. Index does not exist.", ESP_FAIL);
return NULL;
}
item = vector->items[index];
xSemaphoreGive(vector->mutex);
ZH_LOGI("Getting item from vector success."); ZH_LOGI("Getting item from vector success.");
return item; return ESP_OK;
} }
esp_err_t zh_vector_delete_item(zh_vector_t *vector, uint16_t index) // -V2008 esp_err_t zh_vector_delete_item(zh_vector_t **vector, uint16_t index)
{ {
ZH_LOGI("Deleting item in vector begin."); ZH_LOGI("Deleting item in vector begin.");
ZH_ERROR_CHECK(vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Deleting item in vector fail. Invalid argument."); ZH_ERROR_CHECK(vector != NULL && *vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Deleting item in vector failed. Invalid argument.");
ZH_ERROR_CHECK(vector->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "Deleting item in vector fail. Vector not initialized."); ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Deleting item in vector failed. Failed to acquire mutex.");
ZH_ERROR_CHECK(xSemaphoreTake(vector->mutex, portMAX_DELAY) == pdTRUE, ESP_FAIL, NULL, "Deleting item in vector fail. Failed to acquire mutex."); ZH_ERROR_CHECK(index < (*vector)->size, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Deleting item in vector failed. Index out of bounds.");
ZH_ERROR_CHECK(index < vector->size, ESP_FAIL, NULL, "Deleting item in vector fail. Index does not exist."); uint16_t last_idx = (*vector)->size - 1;
void *freed_item = vector->items[index]; void *freed_item = (*vector)->items[index];
for (uint16_t i = index; i < (vector->size - 1); ++i) if (index != last_idx)
{ {
vector->items[i] = vector->items[i + 1]; for (uint16_t i = index; i < last_idx; ++i)
{
(*vector)->items[i] = (*vector)->items[i + 1];
}
} }
(*vector)->items[last_idx] = NULL;
heap_caps_free(freed_item); heap_caps_free(freed_item);
vector->items[--vector->size] = NULL; --(*vector)->size;
if (vector->capacity > vector->size) if ((*vector)->size > 0 && (*vector)->capacity / 2 > (*vector)->size)
{ {
ZH_ERROR_CHECK(_resize(vector, vector->size) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive(vector->mutex), "Deleting item in vector fail. Memory allocation fail or no free memory in the heap."); ZH_ERROR_CHECK(_resize(*vector, (*vector)->size) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Deleting item in vector failed. Memory reallocation failed.");
} }
xSemaphoreGive(vector->mutex); else if ((*vector)->size == 0 && (*vector)->capacity > 0)
{
_resize(*vector, 0);
}
xSemaphoreGive((*vector)->mutex);
ZH_LOGI("Deleting item in vector success."); ZH_LOGI("Deleting item in vector success.");
return ESP_OK; return ESP_OK;
} }
@@ -182,14 +217,23 @@ static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity)
{ {
if (capacity == 0) if (capacity == 0)
{ {
if (vector->items != NULL)
{
for (uint16_t i = 0; i < vector->size; ++i)
{
heap_caps_free(vector->items[i]);
vector->items[i] = NULL;
}
}
heap_caps_free(vector->items); heap_caps_free(vector->items);
vector->items = NULL; vector->items = NULL;
vector->size = 0;
vector->capacity = 0; vector->capacity = 0;
return ESP_OK; return ESP_OK;
} }
uint16_t old_capacity = vector->capacity;
void *new_items = heap_caps_realloc(vector->items, sizeof(void *) * capacity, MALLOC_CAP_8BIT); void *new_items = heap_caps_realloc(vector->items, sizeof(void *) * capacity, MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(new_items != NULL, ESP_ERR_NO_MEM, NULL, "Memory allocation fail or no free memory in the heap."); ZH_ERROR_CHECK(new_items != NULL, ESP_ERR_NO_MEM, NULL, "Memory reallocation failed.");
uint16_t old_capacity = vector->capacity;
vector->items = new_items; vector->items = new_items;
if (capacity > old_capacity) if (capacity > old_capacity)
{ {
@@ -198,3 +242,19 @@ static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity)
vector->capacity = capacity; vector->capacity = capacity;
return ESP_OK; return ESP_OK;
} }
static inline uint16_t _calc_new_capacity(uint16_t current)
{
if (current == 0)
{
return 4;
}
else if (current > UINT16_MAX / 2)
{
return UINT16_MAX;
}
else
{
return current * 2;
}
}