feat: added finding specific field in a vector of structures

This commit is contained in:
aZholtikov committed 2026-07-15 11:51:59 +03:00
1 parent c0267639e5
commit 847cccc34e
6 files changed
+235 -5

No files matched your search

+87 -1
View File
@@ -281,6 +281,31 @@ Finds the first occurrence of an element in the vector.
---
### zh_vector_find_item_in_field()
Finds the first occurrence of a value in a specific field within structures stored in the vector.
**Parameters:**
- `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
- `sample_struct` - Pointer to a sample structure of the same type as stored in the vector. Must not be NULL.
- `field` - Pointer to the field within the structure to search. Must be a valid member address within sample_struct.
- `size` - Size (in bytes) of the field to compare. Must be > 0.
- `item` - Pointer to the value to search for. Must not be NULL.
- `start` - Starting index for the search (0-based). Must be < vector size.
- `index` - Pointer to variable to store the found index. Will be set to -1 if value is not found. Must not be NULL.
**Returns:**
- `ESP_OK` - Success (value found)
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL pointer, zero size, or invalid start index)
- `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
- `ESP_ERR_NOT_FOUND` - Value not found (index set to -1)
**Note:** This function calculates the offset of the field within the structure using sample_struct and item pointers, then searches for the specified value in that field across all vector elements starting from the given index. Uses memcmp for comparison. Useful for searching in vectors of structures without copying the entire structure.
---
### zh_vector_remove_duplicates()
Removes duplicate elements from the vector, keeping only the first occurrence of each element.
@@ -535,6 +560,67 @@ void app_main(void)
---
### Find Item in Field Example
```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;
// Initialize vector for structs
esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
if (ret != ESP_OK) {
printf("Vector initialization error\n");
return;
}
// Add struct elements
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);
// Find struct by field value (searching by id field)
int search_id = 2;
int16_t found_index = -1;
// Calculate offset of 'id' field within the structure
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("Struct with id=%d found at index %d\n", search_id, found_index);
// Get the found struct
my_struct_t found_item;
ret = zh_vector_get_item(&vector, (uint16_t)found_index, &found_item);
if (ret == ESP_OK) {
printf("Found item: id=%d, name=%s, value=%.1f\n", found_item.id, found_item.name, found_item.value);
}
} else {
printf("Struct with id=%d not found (index=%d)\n", search_id, found_index);
}
// Find non-existing 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("Struct with id=%d found at index %d\n", search_id, found_index);
} else {
printf("Struct with id=%d not found (index=%d)\n", search_id, found_index);
}
// Cleanup
zh_vector_free(&vector);
}
```
---
## Technical Specifications
| Parameter | Value |
@@ -610,4 +696,4 @@ limitations under the License.
---
*Generated for zh_vector v2.3.0*
*Generated for zh_vector v2.4.0*
+88 -2
View File
@@ -281,6 +281,31 @@ if (ret != ESP_OK) {
---
### 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()
Удаляет дублирующиеся элементы из вектора, оставляя только первое вхождение каждого элемента.
@@ -406,7 +431,7 @@ void app_main(void)
printf("Ошибка инициализации вектора\n");
return;
}
// Добавление строк
// Добавление стро��
strcpy(buffer, "Привет");
zh_vector_push_front(&vector, &buffer);
strcpy(buffer, "Мир");
@@ -535,6 +560,67 @@ void app_main(void)
---
### Пример поиска элемента по полю
```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};
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);
}
```
---
## Технические характеристики
| Параметр | Значение |
@@ -610,4 +696,4 @@ void app_main(void)
---
*Сгенерировано для zh_vector v2.3.0*
*Сгенерировано для zh_vector v2.4.0*
+1 -1
View File
@@ -1,6 +1,6 @@
description: ESP32 ESP-IDF component for vector (dynamic array)
url: https://github.com/aZholtikov/zh_vector
version: "2.3.0"
version: "2.4.0"
license: "Apache-2.0"
maintainers:
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
+33
View File
@@ -232,6 +232,39 @@ extern "C"
*/
esp_err_t zh_vector_find_item(zh_vector_t **vector, const void *item, int16_t *index);
/**
* @brief Searches for an item in a vector of structures by comparing a specific field.
*
* This function is intended for vectors that store structures (not primitive types).
* It takes a sample structure and a pointer to one of its fields, computes the field offset,
* and then scans the vector starting from the given index. For each element, it compares
* the bytes of the field with the provided value using `memcmp`. If a match is found,
* its index (0‑based) is written to `*index` and `ESP_OK` is returned. If no match is found,
* `*index` is set to `-1` and `ESP_ERR_NOT_FOUND` is returned.
*
* @note The vector must contain elements of a structure type. The `sample_struct` and `field`
* pointers must belong to the same structure definition as the elements stored in the vector.
* The function computes the field offset as `(uint8_t*)field - (uint8_t*)sample_struct`.
* @note The `size` parameter must be the exact size in bytes of the field (e.g., `sizeof(sample.id)`). If `size` is 0, the function returns an error.
* @note This function is thread-safe: internally locks/unlocks the mutex for the entire search.
* @note The search is linear O(n) and starts from the given `start` index to the end.
* @note To find all occurrences, call this function repeatedly with an updated `start` index (found index + 1) until `ESP_ERR_NOT_FOUND` is returned.
*
* @param[in] vector Double pointer to the vector structure (must be initialized).
* @param[in] sample_struct Pointer to a sample structure of the same type as stored in the vector. Used only to compute the field offset. The contents are not used.
* @param[in] field Pointer to the specific field inside the `sample_struct`.
* @param[in] size Size in bytes of the field. Must be > 0.
* @param[in] item Pointer to the value to search for in the field.
* @param[in] start Index (0‑based) from which to start searching. Must be < vector size.
* @param[out] index Pointer to store the found index (0‑based) or `-1` if not found.
*
* @return ESP_OK if a matching element is found (index is set).
* @return ESP_ERR_NOT_FOUND if no element with a matching field value is found.
* @return ESP_ERR_INVALID_ARG if any pointer argument is NULL, `*vector` is NULL (not initialized), `size == 0`, `start >= vector size`, or the field extends beyond the element size.
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired.
*/
esp_err_t zh_vector_find_item_in_field(zh_vector_t **vector, const void *sample_struct, const void *field, size_t size, const void *item, uint16_t start, int16_t *index);
#ifdef __cplusplus
}
#endif
+1 -1
View File
@@ -1 +1 @@
2.3.0
2.4.0
+25
View File
@@ -263,6 +263,31 @@ esp_err_t zh_vector_find_item(zh_vector_t **vector, const void *item, int16_t *i
return ESP_ERR_NOT_FOUND;
}
esp_err_t zh_vector_find_item_in_field(zh_vector_t **vector, const void *sample_struct, const void *item, size_t size, const void *value, uint16_t start, int16_t *index)
{
ZH_LOGI("Finding field in structure begin.");
ZH_ERROR_CHECK(vector != NULL && *vector != NULL && sample_struct != NULL && item != NULL && value != NULL && index != NULL && size > 0, ESP_ERR_INVALID_ARG, NULL, "Finding field in structure failed. Invalid argument.");
ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Finding field in structure failed. Mutex acquire failed.");
ZH_ERROR_CHECK(start < (*vector)->size, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Finding field in structure failed. Start index out of bounds.");
size_t offset = (const uint8_t *)item - (const uint8_t *)sample_struct;
ZH_ERROR_CHECK((offset + size) <= (*vector)->unit, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Finding field in structure failed. Field exceeds element size.");
*index = -1;
for (uint16_t i = start; i < (*vector)->size; ++i)
{
const uint8_t *elem = (const uint8_t *)(*vector)->items[i];
if (memcmp(elem + offset, value, size) == 0)
{
*index = (int16_t)i;
xSemaphoreGive((*vector)->mutex);
ZH_LOGI("Finding field in structure success (found).");
return ESP_OK;
}
}
xSemaphoreGive((*vector)->mutex);
ZH_LOGI("Finding field in structure success (not found).");
return ESP_ERR_NOT_FOUND;
}
static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity)
{
ZH_ERROR_CHECK(capacity >= vector->size, ESP_ERR_INVALID_ARG, NULL, "Invalid argument.");