doc: added wiki

This commit is contained in:
aZholtikov committed 2026-10-17 09:08:58 +03:00
1 parent 9e81485984
commit 1a1351b60f
1 file changed
+217
+217
View File
@@ -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"
```