# zh_vector - Компонент вектора (динамического массива) для ESP-IDF ## Содержание - [Обзор](#обзор) - [Возможности](#возможности) - [Установка](#установка) - [Справочник API](#справочник-api) - [Примеры использования](#примеры-использования) - [Технические характеристики](#технические-характеристики) - [Коды ошибок](#коды-ошибок) - [Вклад в проект](#вклад-в-проект) - [Лицензия](#лицензия) --- ## Обзор `zh_vector` — это легковесный и эффективный компонент вектора (динамического массива) для ESP-IDF (Espressif IoT Development Framework). Он предоставляет гибкий контейнер, который может хранить элементы любого типа данных с автоматическим управлением памятью. Вектор автоматически изменяет размер при добавлении или удалении элементов, что делает его идеальным для динамического управления данными во встраиваемых системах. Компонент разработан специально для микроконтроллеров ESP32 и использует функции управления кучей ESP-IDF для оптимального выделения памяти с различными параметрами памяти (внутренняя/внешняя RAM). --- ## Возможности - **Независимость от типа данных**: Поддерживает любой тип данных (целые числа, числа с плавающей точкой, структуры, пользовательские типы и т.д.) - **Автоматическое управление памятью**: Автоматическое выделение и освобождение памяти - **Динамическое изменение размера**: Емкость вектора увеличивается и уменьшается по мере необходимости - **Максимальная емкость**: До 65 535 элементов (ограничение 16-битного индекса) - **Оптимизировано под ESP-IDF**: Использует функции heap_caps для выделения памяти с параметрами памяти - **Обработка ошибок**: Комплексная проверка ошибок с детальным логированием - **Потокобезопасность**: Является потокобезопасным (использует FreeRTOS mutex) - **Минимальные накладные расходы**: Низкие накладные расходы на память и процессор --- ## Установка Перейдите в каталог компонентов вашего проекта: ```bash cd ../ваш_проект/components ``` Клонируйте репозиторий: ```bash git clone https://github.com/aZholtikov/zh_vector ``` В вашем приложении подключите заголовочный файл: ```c #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` - Ошибка выделения памяти **Пример:** ```c 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_remove_duplicates() Удаляет дублирующиеся элементы из вектора, оставляя только первое вхождение каждого элемента. **Параметры:** - `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL. **Возвращает:** - `ESP_OK` - Успех - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или NULL указатель на вектор) - `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой) **Примечание:** Использует memcmp для сравнения элементов. Сохраняется только первое вхождение каждого уникального элемента. Функция сохраняет порядок первых вхождений. --- ## Примеры использования ### Базовый пример: Вектор целых чисел ```c #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); } ``` --- ### Пример со структурой ```c #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); } ``` --- ### Пример со строками (массивы символов) ```c #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); } ``` --- ### Пример удаления дубликатов ```c #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); } ``` --- ### Пример поиска элемента ```c #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); } ``` --- ## Технические характеристики | Параметр | Значение | |----------|----------| | **Максимальная емкость** | 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](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.3.0*