33 KiB
zh_vector - Компонент вектора (динамического массива) для ESP-IDF
Содержание
- Обзор
- Возможности
- Установка
- Справочник API
- Примеры использования
- Технические характеристики
- Коды ошибок
- Вклад в проект
- Лицензия
Обзор
zh_vector — это легковесный и эффективный компонент вектора (динамического массива) для ESP-IDF (Espressif IoT Development Framework). Он предоставляет гибкий контейнер, который может хранить элементы любого типа данных с автоматическим управлением памятью. Вектор автоматически изменяет размер при добавлении или удалении элементов, что делает его идеальным для динамического управления данными во встраиваемых системах.
Компонент разработан специально для микроконтроллеров ESP32 и использует функции управления кучей ESP-IDF для оптимального выделения памяти с различными параметрами памяти (внутренняя/внешняя RAM).
Возможности
- Независимость от типа данных: Поддерживает любой тип данных (целые числа, числа с плавающей точкой, структуры, пользовательские типы и т.д.)
- Автоматическое управление памятью: Автоматическое выделение и освобождение памяти
- Динамическое изменение размера: Емкость вектора увеличивается и уменьшается по мере необходимости
- Максимальная емкость: До 65 535 элементов (ограничение 16-битного индекса)
- Оптимизировано под ESP-IDF: Использует функции heap_caps для выделения памяти с параметрами памяти
- Обработка ошибок: Комплексная проверка ошибок с детальным логированием
- Потокобезопасность: Является потокобезопасным (использует FreeRTOS mutex)
- Минимальные накладные расходы: Низкие накладные расходы на память и процессор
Установка
Перейдите в каталог компонентов вашего проекта:
cd ../ваш_проект/components
Клонируйте репозиторий:
git clone https://github.com/aZholtikov/zh_vector
В вашем приложении подключите заголовочный файл:
#include "zh_vector.h"
Компонент будет автоматически собран вместе с вашим проектом.
Справочник API
Все функции в этой библиотеке используют double pointer (zh_vector_t **) для параметра вектора, чтобы обеспечить правильное управление памятью и потокобезопасные операции.
zh_vector_t Structure
Структура объявляется как typedef struct _zh_vector_t zh_vector_t; и инкапсулирует внутренние детали реализации.
Поля (внутренние):
| Поле | Тип | Описание |
|---|---|---|
items |
void ** |
Массив указателей на элементы вектора. Items[0..size-1] являются валидными. Выделяется через heap_caps_calloc, перераспределяется через heap_caps_realloc. |
capacity |
uint16_t |
Текущая выделенная емкость (количество слотов). Увеличивается при вставке — может превышать size после удалений. |
size |
uint16_t |
Текущее количество элементов (0 ≤ size ≤ capacity). |
unit |
uint16_t |
Размер (в байтах) одного элемента. Устанавливается при инициализации и не должен меняться. |
mutex |
SemaphoreHandle_t |
FreeRTOS mutex. Создается в zh_vector_init, удаляется в zh_vector_free. Автоматически блокируется/разблокируется в публичных функциях. |
zh_vector_init()
Инициализирует вектор.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Если указатель на вектор равен NULL, будет выделена память.unit- Размер каждого элемента в байтах
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на вектор или нулевой размер unit)ESP_ERR_INVALID_STATE- Вектор уже инициализированESP_ERR_NO_MEM- Ошибка выделения памяти
Пример:
zh_vector_t *vector = NULL;
esp_err_t ret = zh_vector_init(&vector, sizeof(int)); // Для целых чисел
if (ret != ESP_OK) {
// Обработка ошибки
}
// Не забудьте освободить: zh_vector_free(&vector);
zh_vector_free()
Деинициализирует вектор и освобождает всю выделенную память. Устанавливает указатель на вектор в NULL.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или NULL указатель на вектор)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Вся динамически выделенная память элементов также освобождается. Указатель на вектор устанавливается в NULL после деинициализации.
zh_vector_get_capacity()
Получает текущую выделенную емкость вектора (максимальное количество элементов без перераспределения).
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.capacity- Указатель на переменную для сохранения емкости. Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или capacity)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Емкость может быть больше текущего размера (например, после удалений), и уменьшается лениво при size < capacity/2 (или когда size становится 0).
zh_vector_get_size()
Получает текущее количество элементов в векторе.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.size- Указатель на переменную для сохранения размера. Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или size)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
zh_vector_push_front()
Добавляет элемент в начало вектора.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.item- Указатель на элемент для добавления. Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или item)ESP_ERR_NO_MEM- Ошибка выделения памятиESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Функция выделяет память для копии элемента и копирует данные. Все существующие элементы сдвигаются на одну позицию вправо.
zh_vector_push_back()
Добавляет элемент в конец вектора.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.item- Указатель на элемент для добавления. Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или item)ESP_ERR_NO_MEM- Ошибка выделения памятиESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Функция выделяет память для копии элемента и копирует данные.
zh_vector_change_item()
Изменяет элемент по определенному индексу.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.index- Индекс элемента для изменения (начиная с 0). Должен быть < размера вектора.item- Указатель на новые данные элемента. Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор, item или неверный индекс)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
zh_vector_get_item()
Получает элемент по определенному индексу, копируя его в предоставленный буфер пользователя.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.index- Индекс элемента для получения (начиная с 0).item- Указатель на буфер размером не менееunitбайт, куда будет скопирован элемент. Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор, NULL указатель item или неверный индекс)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Эта функция копирует данные элемента в предоставленный буфер. Указатели не возвращаются.
zh_vector_delete_item()
Удаляет элемент по определенному индексу и сдвигает все последующие элементы.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.index- Индекс элемента для удаления (начиная с 0). Должен быть < размера вектора.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или неверный индекс)ESP_ERR_NO_MEM- Ошибка выделения памяти (при перераспределении)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Все элементы после удаляемого индекса сдвигаются влево на одну позицию. Память удаленного элемента освобождается.
zh_vector_find_item()
Находит первое вхождение элемента в векторе.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.item- Указатель на элемент для поиска. Не должен быть NULL.index- Указатель на переменную для сохранения найденного индекса. Будет установлен в -1, если элемент не найден. Не должен быть NULL.
Возвращает:
ESP_OK- Успех (элемент найден)ESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на вектор, NULL указатель item или NULL указатель index)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)ESP_ERR_NOT_FOUND- Элемент не найден (index установлен в -1)
Примечание: Использует memcmp для сравнения элементов. Возвращает индекс первого вхождения. Переменная index устанавливается в -1, если элемент не найден.
zh_vector_find_item_in_field()
Находит первое вхождение значения в определенном поле внутри структур, хранящихся в векторе.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.sample_struct- Указатель на образец структуры того же типа, что и хранится в векторе. Не должен быть NULL.field- Указатель на поле внутри структуры для поиска. Должен быть действительным адресом члена внутри sample_struct.size- Размер (в байтах) поля для сравнения. Должен быть > 0.item- Указатель на значение для поиска. Не должен быть NULL.start- Начальный индекс для поиска (начиная с 0). Должен быть < размера вектора.index- Указатель на переменную для сохранения найденного индекса. Будет установлен в -1, если значение не найдено. Не должен быть NULL.
Возвращает:
ESP_OK- Успех (значение найдено)ESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель, нулевой размер или неверный начальный индекс)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)ESP_ERR_NOT_FOUND- Значение не найдено (index установлен в -1)
Примечание: Эта функция вычисляет смещение поля внутри структуры, используя sample_struct и item указатели, затем ищет указанное значение в этом поле во всех элементах вектора, начиная с заданного индекса. Использует memcmp для сравнения. Полезно для поиска в векторах структур без копирования всей структуры.
zh_vector_remove_duplicates()
Удаляет дублирующиеся элементы из вектора, оставляя только первое вхождение каждого элемента.
Параметры:
vector- Указатель на указатель на структуру вектора (zh_vector_t **). Не должен быть NULL.
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель на указатель на вектор или NULL указатель на вектор)ESP_ERR_INVALID_STATE- Не удалось захватить mutex (редкий системный сбой)
Примечание: Использует memcmp для сравнения элементов. Сохраняется только первое вхождение каждого уникального элемента. Функция сохраняет порядок первых вхождений.
Примеры использования
Базовый пример: Вектор целых чисел
#include "zh_vector.h"
void app_main(void)
{
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для целых чисел
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление элементов
int val1 = 10;
int val2 = 20;
int val3 = 30;
zh_vector_push_front(&vector, &val1);
zh_vector_push_back(&vector, &val2);
zh_vector_push_back(&vector, &val3);
size_t size;
ret = zh_vector_get_size(&vector, &size);
if (ret == ESP_OK) {
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;
zh_vector_change_item(&vector, 1, &new_val);
// Удаление элемента
zh_vector_delete_item(&vector, 0);
// Очистка
zh_vector_free(&vector);
}
Пример со структурой
#include "zh_vector.h"
typedef struct {
int id;
char name[32];
float value;
} my_struct_t;
void app_main(void)
{
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для структур
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 item2 = {2, "Item 2", 2.5f};
zh_vector_push_front(&vector, &item1);
zh_vector_push_back(&vector, &item2);
// Доступ и модификация
my_struct_t item_value;
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(&vector);
}
Пример со строками (массивы символов)
#include "zh_vector.h"
void app_main(void)
{
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
char buffer[100] = {0};
// Инициализация вектора для строк (макс. 100 символов)
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление стро��
strcpy(buffer, "Привет");
zh_vector_push_front(&vector, &buffer);
strcpy(buffer, "Мир");
zh_vector_push_back(&vector, &buffer);
size_t size;
ret = zh_vector_get_size(&vector, &size);
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_remove_duplicates(&vector);
// Очистка
zh_vector_free(&vector);
}
Пример удаления дубликатов
#include "zh_vector.h"
void app_main(void)
{
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для целых чисел
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление элементов с дубликатами
int val1 = 10;
int val2 = 20;
int val3 = 10;
int val4 = 30;
int val5 = 20;
zh_vector_push_back(&vector, &val1);
zh_vector_push_back(&vector, &val2);
zh_vector_push_back(&vector, &val3);
zh_vector_push_back(&vector, &val4);
zh_vector_push_back(&vector, &val5);
uint16_t size;
ret = zh_vector_get_size(&vector, &size);
if (ret == ESP_OK) {
printf("Размер вектора перед удалением дубликатов: %zu\n", size);
}
// Удаление дубликатов
zh_vector_remove_duplicates(&vector);
ret = zh_vector_get_size(&vector, &size);
if (ret == ESP_OK) {
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));
}
}
// Очистка
zh_vector_free(&vector);
}
Пример поиска элемента
#include "zh_vector.h"
void app_main(void)
{
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для целых чисел
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
if (ret != ESP_OK) {
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление элементов
int val1 = 10;
int val2 = 20;
int val3 = 30;
zh_vector_push_back(&vector, &val1);
zh_vector_push_back(&vector, &val2);
zh_vector_push_back(&vector, &val3);
// Поиск элемента
int search_item = 20;
int16_t found_index = -1;
ret = zh_vector_find_item(&vector, &search_item, &found_index);
if (ret == ESP_OK) {
printf("Элемент %d найден по индексу %d\n", search_item, found_index);
} else {
printf("Элемент %d не найден (index=%d)\n", search_item, found_index);
}
// Поиск несуществующего элемента
search_item = 100;
found_index = -1;
ret = zh_vector_find_item(&vector, &search_item, &found_index);
if (ret == ESP_OK) {
printf("Элемент %d найден по индексу %d\n", search_item, found_index);
} else {
printf("Элемент %d не найден (index=%d)\n", search_item, found_index);
}
// Очистка
zh_vector_free(&vector);
}
Пример поиска элемента по полю
#include "zh_vector.h"
typedef struct {
int id;
char name[32];
float value;
} my_struct_t;
void app_main(void)
{
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
zh_vector_t *vector = NULL;
// Инициализация вектора для структур
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 item2 = {2, "Item 2", 2.5f};
my_struct_t item3 = {3, "Item 3", 3.5f};
zh_vector_push_back(&vector, &item1);
zh_vector_push_back(&vector, &item2);
zh_vector_push_back(&vector, &item3);
// Поиск структуры по значению поля (поиск по полю id)
int search_id = 2;
int16_t found_index = -1;
// Вычисление смещения поля 'id' внутри структуры
my_struct_t sample;
ret = zh_vector_find_item_in_field(&vector, &sample, &sample.id, sizeof(sample.id), &search_id, 0, &found_index);
if (ret == ESP_OK) {
printf("Структура с id=%d найдена по индексу %d\n", search_id, found_index);
// Получение найденной структуры
my_struct_t found_item;
ret = zh_vector_get_item(&vector, (uint16_t)found_index, &found_item);
if (ret == ESP_OK) {
printf("Найденный элемент: id=%d, name=%s, value=%.1f\n", found_item.id, found_item.name, found_item.value);
}
} else {
printf("Структура с id=%d не найдена (index=%d)\n", search_id, found_index);
}
// Поиск несуществующего id
search_id = 100;
found_index = -1;
ret = zh_vector_find_item_in_field(&vector, &sample, &sample.id, sizeof(sample.id), &search_id, 0, &found_index);
if (ret == ESP_OK) {
printf("Структура с id=%d найдена по индексу %d\n", search_id, found_index);
} else {
printf("Структура с id=%d не найдена (index=%d)\n", search_id, found_index);
}
// Очистка
zh_vector_free(&vector);
}
Технические характеристики
| Параметр | Значение |
|---|---|
| Максимальная емкость | 65 535 элементов |
| Тип индекса | uint16_t (16-бит) |
| Управление памятью | heap_caps_calloc, heap_caps_realloc, heap_caps_free |
| Параметры памяти | MALLOC_CAP_8BIT |
| Потокобезопасность | Является потокобезопасным (использует FreeRTOS mutex) |
| Версия ESP-IDF | >= 5.0 |
| Платформа | Серия ESP32 |
| Язык | C (C99) |
Коды ошибок
| Код ошибки | Описание |
|---|---|
ESP_OK |
Операция выполнена успешно |
ESP_ERR_INVALID_ARG |
Неверный аргумент (NULL указатель или нулевой размер) |
ESP_ERR_INVALID_STATE |
Не удалось захватить mutex (редкий системный сбой) |
ESP_ERR_NO_MEM |
Ошибка выделения памяти (не хватает памяти) |
ESP_ERR_NOT_FOUND |
Элемент не найден (для zh_vector_find_item) |
Вклад в проект
Вклад приветствуется! Чтобы внести свой вклад:
- Сделайте форк репозитория
- Создайте ветку функции (
git checkout -b feature/AmazingFeature) - Закоммитьте ваши изменения (
git commit -m 'Add some AmazingFeature') - Отправьте в ветку (
git push origin feature/AmazingFeature) - Откройте Pull Request
Пожалуйста, убедитесь, что ваш код следует существующему стилю и включает соответствующую документацию.
Лицензия
Этот проект лицензирован по лицензии Apache, версия 2.0 - см. файл LICENSE для подробной информации.
Apache License, Version 2.0
Авторское право (c) 2026 Алексей Жолтиков
Лицензировано по лицензии Apache License, Version 2.0 (далее — "Лицензия"); вы не можете использовать этот файл, кроме случаев, предусмотренных Лицензией. Копию Лицензии можно получить по адресу:
http://www.apache.org/licenses/LICENSE-2.0
Если иное не требуется действующим законодательством или не согласовано в письменном виде, программное обеспечение, распространяемое по Лицензии, распространяется на условиях "КАК ЕСТЬ", БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, явных или подразумеваемых, включая, но не ограничиваясь, гарантии ТОВАРНОГО СОСТОЯНИЯ, ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ И НЕНАРУШЕНИЯ ПРАВ. Смотрите Лицензию для получения конкретных прав и ограничений.
Дополнительные заметки
- Накладные расходы памяти: Каждый элемент требует дополнительной памяти для указателя во внутреннем массиве указателей
- Производительность: O(1) для получения/установки по индексу, O(n) для вставки/удаления в середине
- Лучшие практики:
- Всегда инициализируйте вектор перед использованием
- Освобождайте вектор по завершении, чтобы избежать утечек памяти
- Учитывайте ограничение максимального размера (65 535 элементов)
- Для обработки строк рассмотрите использование буферов фиксированного размера
Сгенерировано для zh_vector v2.4.0