From 1a1351b60f3b22800fbeffdc0bbb505c4f0b8657 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Sat, 17 Oct 2026 09:08:58 +0300 Subject: [PATCH] doc: added wiki --- wiki_ru.md | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 wiki_ru.md diff --git a/wiki_ru.md b/wiki_ru.md new file mode 100644 index 0000000..d043f43 --- /dev/null +++ b/wiki_ru.md @@ -0,0 +1,217 @@ +# Описание компонента zh_vector + +## Общие сведения + +**zh_vector** — это компонент для ESP-IDF (фреймворк для программирования микроконтроллеров ESP32), реализующий динамический вектор (динамический массив) с автоматическим управлением памятью и потокобезопасностью. + +Компонент предоставляет универсальную структуру данных «вектор», которая может хранить элементы любого типа через указатели `void`, автоматически увеличивает и уменьшает свою ёмкость, а также обеспечивает потокобезопасную работу с помощью мьютексов FreeRTOS. + +## Основные возможности + +1. **Универсальность типов** — поддержка любых типов данных через указатели `void`. +2. **Динамическая ёмкость** — автоматическое увеличение и уменьшение выделенной памяти. +3. **Максимальная ёмкость** — до 65 535 элементов (используется 16-битный индекс `uint16_t`). +4. **Потокобезопасность** — все операции защищены мьютексом FreeRTOS. +5. **Автоматическое управление памятью** — используется ESP-IDF функция `heap_caps` для работы с кучей ESP32. +6. **Гибкая вставка** — поддержка вставки элементов как в начало, так и в конец вектора. +7. **Удаление дубликатов и поиск** — возможность удаления дубликатов и поиска элементов по содержимому или по полю внутри структуры. + +## Внутреннее устройство + +### Структура `zh_vector_t` + +Внутренняя структура вектора содержит следующие поля: + +| Поле | Тип | Описание | +|------|-----|----------| +| `items` | `void **` | Массив указателей, каждый из которых указывает на отдельно выделенную память для фактических данных элемента | +| `capacity` | `uint16_t` | Текущая выделенная ёмкость массива `items` (максимум 65 535) | +| `size` | `uint16_t` | Текущее количество элементов в векторе | +| `unit` | `uint16_t` | Размер одного элемента в байтах | +| `mutex` | `SemaphoreHandle_t` | Мьютекс FreeRTOS для потокобезопасности | +| `lock` | `portMUX_TYPE` | Секция критической защиты для флагов удаления и счётчика ссылок | +| `deleting` | `bool` | Флаг, указывающий, что вектор удаляется и новые операции должны быть отклонены | +| `refcount` | `uint16_t` | Счётчик операций, находящихся в процессе выполнения | + +### Управление памятью + +Каждый элемент вектора хранится как **отдельное выделение памяти**. Это означает, что: +- Массив `items` содержит указатели на элементы. +- Каждый элемент выделяется отдельно через `heap_caps_calloc()`. +- При удалении элемента его память освобождается через `heap_caps_free()`. +- При удалении всего вектора последовательно освобождаются все элементы, затем массив `items` и сама структура `zh_vector_t`. + +## API (интерфейс) + +### Инициализация и освобождение + +| Функция | Описание | +|---------|----------| +| `zh_vector_init()` | Инициализирует новый вектор. Принимает указатель на указатель вектора и размер элемента в байтах. Создаёт структуру, выделяет нулевую ёмкость и создаёт мьютекс. | +| `zh_vector_free()` | Освобождает все ресурсы: элементы, массив, мьютекс и структуру. Устанавливает флаг `deleting` и ожидает завершения всех текущих операций (до тех пор, пока `refcount` не станет нулём). | + +### Получение информации + +| Функция | Описание | +|---------|----------| +| `zh_vector_get_size()` | Возвращает текущее количество элементов в векторе. | +| `zh_vector_get_capacity()` | Возвращает текущую выделенную ёмкость (максимальное количество элементов, для которого выделена память). | + +### Вставка элементов + +| Функция | Описание | +|---------|----------| +| `zh_vector_push_front()` | Вставляет копию элемента в начало вектора (индекс 0). Все существующие элементы сдвигаются на одну позицию вправо. Если ёмкость исчерпана, массив увеличивается. | +| `zh_vector_push_back()` | Вставляет копию элемента в конец вектора. Если ёмкость исчерпана, массив увеличивается. | + +### Доступ и модификация + +| Функция | Описание | +|---------|----------| +| `zh_vector_get_item()` | Копирует элемент по указанному индексу в предоставленный буфер. | +| `zh_vector_change_item()` | Заменяет содержимое элемента по указанному индексу новыми данными. | + +### Удаление элементов + +| Функция | Описание | +|---------|----------| +| `zh_vector_delete_item()` | Удаляет элемент по указанному индексу. Освобождает память элемента, сдвигает оставшиеся элементы влево. Обновляет `size`. | +| `zh_vector_delete_back()` | Удаляет последний элемент вектора. | +| `zh_vector_delete_front()` | Удаляет первый элемент вектора. Сдвигает оставшиеся элементы влево. | + +### Поиск и очистка + +| Функция | Описание | +|---------|----------| +| `zh_vector_remove_duplicates()` | Удаляет дубликаты элементов. Сравнивает элементы побайтово через `memcmp`. При обнаружении дубликата он удаляется. | +| `zh_vector_find_item()` | Ищет первый элемент, побайтово совпадающий с заданным. Возвращает индекс или `-1`, если элемент не найден. | +| `zh_vector_find_item_in_field()` | Ищет элемент по значению конкретного поля внутри структуры. Позволяет искать по любому полю структуры, вычисляя смещение поля от начала структуры. | + +## Потокобезопасность + +Все публичные функции работают с вектором через двухуровневую систему синхронизации: + +1. **`_zh_vector_take()` / `_zh_vector_give()`** — механизм счётчика ссылок. + - Перед началом любой операции вызывается `_zh_vector_take()`, который увеличивает `refcount` и проверяет, что вектор не удаляется (флаг `deleting` равен `false`). + - После завершения операции вызывается `_zh_vector_give()`, который уменьшает `refcount`. + - Функция `zh_vector_free()` устанавливает `deleting = true` и ожидает, пока `refcount` не станет нулём. Это гарантирует, что все текущие операции завершатся перед освобождением памяти. + +2. **Мьютекс FreeRTOS** — защищает внутренние данные вектора (`items`, `capacity`, `size`) от одновременного доступа из разных потоков. + +3. **Критическая секция (`portMUX_TYPE`)** — используется для атомарных операций со счётчиком ссылок и флагом удаления (на уровне одного ядра, без блокировки других ядер). + +## Алгоритмы изменения ёмкости + +### Увеличение ёмкости + +- При первой вставке элемента начальная ёмкость устанавливается в **4 элемента**. +- При каждом последующем заполнении ёмкость удваивается (`capacity * 2`). +- Максимальная ёмкость ограничена значением `UINT16_MAX` (65 535). + +### Уменьшение ёмкости + +- Ёмкость уменьшается при удалении элемента, если: + - `capacity > 4` и `capacity / 2 >= size * 2` (то есть выделенная память больше нужной более чем в 2 раза). + - Новая ёмкость рассчитывается как `size * 2`, но не менее 4. +- При достижении `size == 0` вся память полностью освобождается. + +## Примеры использования + +### Базовый пример (целые числа) + +```c +zh_vector_t *vector = NULL; +zh_vector_init(&vector, sizeof(int)); + +int val1 = 10, val2 = 20, val3 = 30; +zh_vector_push_back(vector, &val1); +zh_vector_push_back(vector, &val2); +zh_vector_push_back(vector, &val3); + +// Получение элемента +int item_value = 0; +zh_vector_get_item(vector, 1, &item_value); // item_value = 20 + +// Изменение элемента +int new_val = 100; +zh_vector_change_item(vector, 1, &new_val); // элемент по индексу 1 теперь = 100 + +// Удаление элемента +zh_vector_delete_item(vector, 0); // удалён элемент со значением 10 + +// Очистка +zh_vector_free(&vector); +``` + +### Работа со структурами + +```c +typedef struct { + int id; + char name[32]; + float value; +} my_struct_t; + +zh_vector_t *vector = NULL; +zh_vector_init(&vector, sizeof(my_struct_t)); + +my_struct_t item1 = {1, "Item 1", 1.5f}; +zh_vector_push_back(vector, &item1); + +// Поиск по полю структуры +int search_id = 1; +int32_t found_index = -1; +my_struct_t sample = {0}; +zh_vector_find_item_in_field(vector, &sample, &sample.id, sizeof(sample.id), &search_id, 0, &found_index); +// found_index = 0, так как элемент с id=1 находится по индексу 0 + +zh_vector_free(&vector); +``` + +## Логирование + +Компонент использует ESP-IDF логирование с тегом `"zh_vector"`. Уровень логирования можно настроить: + +```c +esp_log_level_set("zh_vector", ESP_LOG_ERROR); // только ошибки +``` + +## Ошибки + +Все функции возвращают `esp_err_t`. Основные коды ошибок: + +| Код | Описание | +|-----|----------| +| `ESP_OK` | Успех | +| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL-указатель, некорректный индекс и т.д.) | +| `ESP_ERR_INVALID_STATE` | Неверное состояние (вектор удаляется, мьютекс не получен) | +| `ESP_ERR_NO_MEM` | Не удалось выделить память | +| `ESP_ERR_NOT_FOUND` | Элемент не найден | + +## Ограничения + +1. **Максимум 65 535 элементов** — из-за использования `uint16_t` для индексов и ёмкости. +2. **Побайтовое сравнение** — `memcmp` сравнивает сырые байты, что может не учитывать выравнивание структур. +3. **Копирование данных** — все операции вставки и получения копируют данные, что может быть неэффективно для очень больших элементов. +4. **Зависимость от ESP-IDF** — компонент работает только в среде ESP-IDF с FreeRTOS. + +## Требования для сборки + +- ESP-IDF (фреймворк для ESP32) +- FreeRTOS (входит в состав ESP-IDF) +- Компонент должен находиться в директории `components/zh_vector` проекта + +## Установка + +Для добавления компонента в проект: + +```bash +cd ваш_проект/components +git clone https://github.com/aZholtikov/zh_vector +``` + +Затем в коде подключить заголовочный файл: + +```c +#include "zh_vector.h" +```