Files
zh_vector/WIKI_RU.md
T

33 KiB

zh_vector - Компонент вектора (динамического массива) для ESP-IDF

Содержание


Обзор

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

Структура объявляется как 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);
    uint16_t size = 0;
    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 = 0;
        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 = {0};
    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);
    uint16_t size = 0;
    ret = zh_vector_get_size(&vector, &size);
    if (ret == ESP_OK)
    {
        // Печать всех строк
        for (int i = 0; i < size; i++)
        {
            char str_value[100] = {0};
            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 = 0;
    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 = 0;
        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;
    int32_t found_index = -1;
    ret = zh_vector_find_item(&vector, &search_item, &found_index);
    if (ret == ESP_OK)
    {
        printf("Элемент %d найден по индексу %ld\n", search_item, found_index);
    }
    else
    {
        printf("Элемент %d не найден (index=%ld)\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 найден по индексу %ld\n", search_item, found_index);
    }
    else
    {
        printf("Элемент %d не найден (index=%ld)\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;
    int32_t found_index = -1;
    // Вычисление смещения поля 'id' внутри структуры
    my_struct_t sample = {0};
    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 найдена по индексу %ld\n", search_id, found_index);
        // Получение найденной структуры
        my_struct_t found_item = {0};
        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=%ld)\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 найдена по индексу %ld\n", search_id, found_index);
    }
    else
    {
        printf("Структура с id=%d не найдена (index=%ld)\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)

Вклад в проект

Вклад приветствуется! Чтобы внести свой вклад:

  1. Сделайте форк репозитория
  2. Создайте ветку функции (git checkout -b feature/AmazingFeature)
  3. Закоммитьте ваши изменения (git commit -m 'Add some AmazingFeature')
  4. Отправьте в ветку (git push origin feature/AmazingFeature)
  5. Откройте 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.1