feat: added duplicate removing
This commit is contained in:
1 parent
6263d23d65
commit
f83572e0e8
6 files changed
+239
-59
No files matched your search
+74
-18
@@ -260,6 +260,24 @@ Deletes an element at a specific index and shifts all subsequent elements.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### zh_vector_remove_duplicates()
|
||||||
|
|
||||||
|
Removes duplicate elements from the vector, keeping only the first occurrence of each element.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
- `vector` - Pointer to pointer to vector structure (`zh_vector_t **`). Must not be NULL.
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
- `ESP_OK` - Success
|
||||||
|
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL vector pointer or NULL vector)
|
||||||
|
- `ESP_ERR_INVALID_STATE` - Failed to acquire mutex (rare system error)
|
||||||
|
|
||||||
|
**Note:** Uses memcmp to compare elements. Only the first occurrence of each unique element is preserved. The function preserves the order of first occurrences.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### Basic Example: Integer Vector
|
### Basic Example: Integer Vector
|
||||||
@@ -270,16 +288,13 @@ Deletes an element at a specific index and shifts all subsequent elements.
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
|
||||||
zh_vector_t *vector = NULL;
|
zh_vector_t *vector = NULL;
|
||||||
|
|
||||||
// Initialize vector for integers
|
// Initialize vector for integers
|
||||||
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
|
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
printf("Vector initialization error\n");
|
printf("Vector initialization error\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add elements
|
// Add elements
|
||||||
int val1 = 10;
|
int val1 = 10;
|
||||||
int val2 = 20;
|
int val2 = 20;
|
||||||
@@ -287,13 +302,11 @@ void app_main(void)
|
|||||||
zh_vector_push_front(&vector, &val1);
|
zh_vector_push_front(&vector, &val1);
|
||||||
zh_vector_push_back(&vector, &val2);
|
zh_vector_push_back(&vector, &val2);
|
||||||
zh_vector_push_back(&vector, &val3);
|
zh_vector_push_back(&vector, &val3);
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
ret = zh_vector_get_size(&vector, &size);
|
ret = zh_vector_get_size(&vector, &size);
|
||||||
if (ret == ESP_OK) {
|
if (ret == ESP_OK) {
|
||||||
printf("Vector size: %zu\n", size);
|
printf("Vector size: %zu\n", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access elements
|
// Access elements
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
int item_value;
|
int item_value;
|
||||||
@@ -304,14 +317,11 @@ void app_main(void)
|
|||||||
printf("Error getting element %d: %s\n", i, esp_err_to_name(err));
|
printf("Error getting element %d: %s\n", i, esp_err_to_name(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change element
|
// Change element
|
||||||
int new_val = 100;
|
int new_val = 100;
|
||||||
zh_vector_change_item(&vector, 1, &new_val);
|
zh_vector_change_item(&vector, 1, &new_val);
|
||||||
|
|
||||||
// Delete element
|
// Delete element
|
||||||
zh_vector_delete_item(&vector, 0);
|
zh_vector_delete_item(&vector, 0);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
zh_vector_free(&vector);
|
zh_vector_free(&vector);
|
||||||
}
|
}
|
||||||
@@ -333,22 +343,18 @@ typedef struct {
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
|
||||||
zh_vector_t *vector = NULL;
|
zh_vector_t *vector = NULL;
|
||||||
|
|
||||||
// Initialize vector for structs
|
// Initialize vector for structs
|
||||||
esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
|
esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
printf("Vector initialization error\n");
|
printf("Vector initialization error\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add struct elements
|
// Add struct elements
|
||||||
my_struct_t item1 = {1, "Item 1", 1.5f};
|
my_struct_t item1 = {1, "Item 1", 1.5f};
|
||||||
my_struct_t item2 = {2, "Item 2", 2.5f};
|
my_struct_t item2 = {2, "Item 2", 2.5f};
|
||||||
zh_vector_push_front(&vector, &item1);
|
zh_vector_push_front(&vector, &item1);
|
||||||
zh_vector_push_back(&vector, &item2);
|
zh_vector_push_back(&vector, &item2);
|
||||||
|
|
||||||
// Access and modify
|
// Access and modify
|
||||||
my_struct_t item_value;
|
my_struct_t item_value;
|
||||||
esp_err_t err = zh_vector_get_item(&vector, 0, &item_value);
|
esp_err_t err = zh_vector_get_item(&vector, 0, &item_value);
|
||||||
@@ -356,7 +362,6 @@ void app_main(void)
|
|||||||
item_value.value = 10.5f;
|
item_value.value = 10.5f;
|
||||||
zh_vector_change_item(&vector, 0, &item_value);
|
zh_vector_change_item(&vector, 0, &item_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
zh_vector_free(&vector);
|
zh_vector_free(&vector);
|
||||||
}
|
}
|
||||||
@@ -372,23 +377,19 @@ void app_main(void)
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
|
||||||
zh_vector_t *vector = NULL;
|
zh_vector_t *vector = NULL;
|
||||||
char buffer[100] = {0};
|
char buffer[100] = {0};
|
||||||
|
|
||||||
// Initialize vector for strings (100 char max)
|
// Initialize vector for strings (100 char max)
|
||||||
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
|
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
printf("Vector initialization error\n");
|
printf("Vector initialization error\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add strings
|
// Add strings
|
||||||
strcpy(buffer, "Hello");
|
strcpy(buffer, "Hello");
|
||||||
zh_vector_push_front(&vector, &buffer);
|
zh_vector_push_front(&vector, &buffer);
|
||||||
strcpy(buffer, "World");
|
strcpy(buffer, "World");
|
||||||
zh_vector_push_back(&vector, &buffer);
|
zh_vector_push_back(&vector, &buffer);
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
ret = zh_vector_get_size(&vector, &size);
|
ret = zh_vector_get_size(&vector, &size);
|
||||||
if (ret == ESP_OK) {
|
if (ret == ESP_OK) {
|
||||||
@@ -403,7 +404,62 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove duplicates (if any)
|
||||||
|
zh_vector_remove_duplicates(&vector);
|
||||||
|
// Cleanup
|
||||||
|
zh_vector_free(&vector);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Remove Duplicates Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "zh_vector.h"
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
zh_vector_t *vector = NULL;
|
||||||
|
// Initialize vector for integers
|
||||||
|
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
printf("Vector initialization error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Add elements with duplicates
|
||||||
|
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);
|
||||||
|
size_t size;
|
||||||
|
ret = zh_vector_get_size(&vector, &size);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
printf("Vector size before removing duplicates: %zu\n", size);
|
||||||
|
}
|
||||||
|
// Remove duplicates
|
||||||
|
zh_vector_remove_duplicates(&vector);
|
||||||
|
ret = zh_vector_get_size(&vector, &size);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
printf("Vector size after removing duplicates: %zu\n", size);
|
||||||
|
}
|
||||||
|
// Access remaining elements
|
||||||
|
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("Element %d: %d\n", i, item_value);
|
||||||
|
} else {
|
||||||
|
printf("Error getting element %d: %s\n", i, esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
// Cleanup
|
// Cleanup
|
||||||
zh_vector_free(&vector);
|
zh_vector_free(&vector);
|
||||||
}
|
}
|
||||||
@@ -485,4 +541,4 @@ limitations under the License.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Generated for zh_vector v2.0.0*
|
*Generated for zh_vector v2.2.0*
|
||||||
+75
-19
@@ -72,7 +72,7 @@ git clone https://github.com/aZholtikov/zh_vector
|
|||||||
| Поле | Тип | Описание |
|
| Поле | Тип | Описание |
|
||||||
|------|-----|----------|
|
|------|-----|----------|
|
||||||
| `items` | `void **` | Массив указателей на элементы вектора. Items[0..size-1] являются валидными. Выделяется через heap_caps_calloc, перераспределяется через heap_caps_realloc. |
|
| `items` | `void **` | Массив указателей на элементы вектора. Items[0..size-1] являются валидными. Выделяется через heap_caps_calloc, перераспределяется через heap_caps_realloc. |
|
||||||
| `capacity` | `uint16_t` | Текущая выделенная емкость (количество слотов). Увеличивается при вставке — может превышать size после удалений. |
|
| `capacity` | `uint16_t` | Текущая выделенная емкость (количество слотов). Увеличивае��ся при вставке — может превышать size после удалений. |
|
||||||
| `size` | `uint16_t` | Текущее количество элементов (0 ≤ size ≤ capacity). |
|
| `size` | `uint16_t` | Текущее количество элементов (0 ≤ size ≤ capacity). |
|
||||||
| `unit` | `uint16_t` | Размер (в байтах) одного элемента. Устанавливается при инициализации и не должен меняться. |
|
| `unit` | `uint16_t` | Размер (в байтах) одного элемента. Устанавливается при инициализации и не должен меняться. |
|
||||||
| `mutex` | `SemaphoreHandle_t` | FreeRTOS mutex. Создается в zh_vector_init, удаляется в zh_vector_free. Автоматически блокируется/разблокируется в публичных функциях. |
|
| `mutex` | `SemaphoreHandle_t` | FreeRTOS mutex. Создается в zh_vector_init, удаляется в zh_vector_free. Автоматически блокируется/разблокируется в публичных функциях. |
|
||||||
@@ -260,6 +260,24 @@ if (ret != ESP_OK) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### zh_vector_remove_duplicates()
|
||||||
|
|
||||||
|
Удаляет дублирующиеся элементы из вектора, оставляя только первое вхождение каждого элемента.
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
|
||||||
|
- `vector` - Указатель на указатель на структуру вектора (`zh_vector_t **`). Не должен быть NULL.
|
||||||
|
|
||||||
|
**Возвращает:**
|
||||||
|
|
||||||
|
- `ESP_OK` - Успех
|
||||||
|
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель на указатель на вектор или NULL указатель на вектор)
|
||||||
|
- `ESP_ERR_INVALID_STATE` - Не удалось захватить mutex (редкий системный сбой)
|
||||||
|
|
||||||
|
**Примечание:** Использует memcmp для сравнения элементов. Сохраняется только первое вхождение каждого уникального элемента. Функция сохраняет порядок первых вхождений.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Примеры использования
|
## Примеры использования
|
||||||
|
|
||||||
### Базовый пример: Вектор целых чисел
|
### Базовый пример: Вектор целых чисел
|
||||||
@@ -270,16 +288,13 @@ if (ret != ESP_OK) {
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
|
||||||
zh_vector_t *vector = NULL;
|
zh_vector_t *vector = NULL;
|
||||||
|
|
||||||
// Инициализация вектора для целых чисел
|
// Инициализация вектора для целых чисел
|
||||||
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
|
esp_err_t ret = zh_vector_init(&vector, sizeof(int));
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
printf("Ошибка инициализации вектора\n");
|
printf("Ошибка инициализации вектора\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавление элементов
|
// Добавление элементов
|
||||||
int val1 = 10;
|
int val1 = 10;
|
||||||
int val2 = 20;
|
int val2 = 20;
|
||||||
@@ -287,13 +302,11 @@ void app_main(void)
|
|||||||
zh_vector_push_front(&vector, &val1);
|
zh_vector_push_front(&vector, &val1);
|
||||||
zh_vector_push_back(&vector, &val2);
|
zh_vector_push_back(&vector, &val2);
|
||||||
zh_vector_push_back(&vector, &val3);
|
zh_vector_push_back(&vector, &val3);
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
ret = zh_vector_get_size(&vector, &size);
|
ret = zh_vector_get_size(&vector, &size);
|
||||||
if (ret == ESP_OK) {
|
if (ret == ESP_OK) {
|
||||||
printf("Размер вектора: %zu\n", size);
|
printf("Размер вектора: %zu\n", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Доступ к элементам
|
// Доступ к элементам
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
int item_value;
|
int item_value;
|
||||||
@@ -304,14 +317,11 @@ void app_main(void)
|
|||||||
printf("Ошибка получения элемента %d: %s\n", i, esp_err_to_name(err));
|
printf("Ошибка получения элемента %d: %s\n", i, esp_err_to_name(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Изменение элемента
|
// Изменение элемента
|
||||||
int new_val = 100;
|
int new_val = 100;
|
||||||
zh_vector_change_item(&vector, 1, &new_val);
|
zh_vector_change_item(&vector, 1, &new_val);
|
||||||
|
|
||||||
// Удаление элемента
|
// Удаление элемента
|
||||||
zh_vector_delete_item(&vector, 0);
|
zh_vector_delete_item(&vector, 0);
|
||||||
|
|
||||||
// Очистка
|
// Очистка
|
||||||
zh_vector_free(&vector);
|
zh_vector_free(&vector);
|
||||||
}
|
}
|
||||||
@@ -333,22 +343,18 @@ typedef struct {
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
|
||||||
zh_vector_t *vector = NULL;
|
zh_vector_t *vector = NULL;
|
||||||
|
|
||||||
// Инициализация вектора для структур
|
// Инициализация вектора для структур
|
||||||
esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
|
esp_err_t ret = zh_vector_init(&vector, sizeof(my_struct_t));
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
printf("Ошибка инициализации вектора\n");
|
printf("Ошибка инициализации вектора\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавление элементов-структур
|
// Добавление элементов-структур
|
||||||
my_struct_t item1 = {1, "Item 1", 1.5f};
|
my_struct_t item1 = {1, "Item 1", 1.5f};
|
||||||
my_struct_t item2 = {2, "Item 2", 2.5f};
|
my_struct_t item2 = {2, "Item 2", 2.5f};
|
||||||
zh_vector_push_front(&vector, &item1);
|
zh_vector_push_front(&vector, &item1);
|
||||||
zh_vector_push_back(&vector, &item2);
|
zh_vector_push_back(&vector, &item2);
|
||||||
|
|
||||||
// Доступ и модификация
|
// Доступ и модификация
|
||||||
my_struct_t item_value;
|
my_struct_t item_value;
|
||||||
esp_err_t err = zh_vector_get_item(&vector, 0, &item_value);
|
esp_err_t err = zh_vector_get_item(&vector, 0, &item_value);
|
||||||
@@ -356,7 +362,6 @@ void app_main(void)
|
|||||||
item_value.value = 10.5f;
|
item_value.value = 10.5f;
|
||||||
zh_vector_change_item(&vector, 0, &item_value);
|
zh_vector_change_item(&vector, 0, &item_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Очистка
|
// Очистка
|
||||||
zh_vector_free(&vector);
|
zh_vector_free(&vector);
|
||||||
}
|
}
|
||||||
@@ -372,23 +377,19 @@ void app_main(void)
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
esp_log_level_set("zh_vector", ESP_LOG_ERROR);
|
||||||
|
|
||||||
zh_vector_t *vector = NULL;
|
zh_vector_t *vector = NULL;
|
||||||
char buffer[100] = {0};
|
char buffer[100] = {0};
|
||||||
|
|
||||||
// Инициализация вектора для строк (макс. 100 символов)
|
// Инициализация вектора для строк (макс. 100 символов)
|
||||||
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
|
esp_err_t ret = zh_vector_init(&vector, sizeof(buffer));
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
printf("Ошибка инициализации вектора\n");
|
printf("Ошибка инициализации вектора\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавление строк
|
// Добавление строк
|
||||||
strcpy(buffer, "Привет");
|
strcpy(buffer, "Привет");
|
||||||
zh_vector_push_front(&vector, &buffer);
|
zh_vector_push_front(&vector, &buffer);
|
||||||
strcpy(buffer, "Мир");
|
strcpy(buffer, "Мир");
|
||||||
zh_vector_push_back(&vector, &buffer);
|
zh_vector_push_back(&vector, &buffer);
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
ret = zh_vector_get_size(&vector, &size);
|
ret = zh_vector_get_size(&vector, &size);
|
||||||
if (ret == ESP_OK) {
|
if (ret == ESP_OK) {
|
||||||
@@ -403,7 +404,62 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Удаление дубликатов (если есть)
|
||||||
|
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);
|
||||||
|
size_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);
|
zh_vector_free(&vector);
|
||||||
}
|
}
|
||||||
@@ -485,4 +541,4 @@ void app_main(void)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Сгенерировано для zh_vector v2.0.0*
|
*Сгенерировано для zh_vector v2.2.0*
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
description: ESP32 ESP-IDF component for vector (dynamic array)
|
description: ESP32 ESP-IDF component for vector (dynamic array)
|
||||||
url: https://github.com/aZholtikov/zh_vector
|
url: https://github.com/aZholtikov/zh_vector
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
license: "Apache-2.0"
|
license: "Apache-2.0"
|
||||||
maintainers:
|
maintainers:
|
||||||
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
|
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ extern "C"
|
|||||||
*
|
*
|
||||||
* Frees all item copies, the internal pointer array, and the mutex. Sets `*vector` to `NULL` before returning.
|
* Frees all item copies, the internal pointer array, and the mutex. Sets `*vector` to `NULL` before returning.
|
||||||
*
|
*
|
||||||
|
* @warning This function is NOT thread-safe. It must not be called concurrently with any other vector operation
|
||||||
|
* from different tasks or interrupts. The caller is responsible for ensuring that all other accesses to
|
||||||
|
* the vector have completed before invoking `zh_vector_free`. In a multi‑tasking environment, use an external
|
||||||
|
* mutex to protect the vector's lifecycle if concurrent calls are possible.
|
||||||
|
*
|
||||||
* @warning After this call, all previously obtained item pointers become invalid.
|
* @warning After this call, all previously obtained item pointers become invalid.
|
||||||
* @note Safe to call with `vector == NULL` or `*vector == NULL` (returns `ESP_OK`).
|
* @note Safe to call with `vector == NULL` or `*vector == NULL` (returns `ESP_OK`).
|
||||||
*
|
*
|
||||||
@@ -186,6 +191,26 @@ extern "C"
|
|||||||
*/
|
*/
|
||||||
esp_err_t zh_vector_delete_item(zh_vector_t **vector, uint16_t index);
|
esp_err_t zh_vector_delete_item(zh_vector_t **vector, uint16_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes duplicate items from the vector, keeping only the first occurrence of each value.
|
||||||
|
*
|
||||||
|
* The function compares items byte-by-byte using `memcmp(..., unit)`. All elements that are equal
|
||||||
|
* to a previously seen element are deleted. The relative order of the remaining elements is preserved.
|
||||||
|
*
|
||||||
|
* @note This operation is O(n^2) in the worst case and may be slow for large vectors.
|
||||||
|
* @note Memory of duplicate elements is freed, and the vector capacity may be reduced if the size drops
|
||||||
|
* below half of the capacity (same as in zh_vector_delete_item).
|
||||||
|
* @note Thread-safe: internally locks/unlocks the mutex.
|
||||||
|
*
|
||||||
|
* @param[in,out] vector Double pointer to vector structure (`zh_vector_t **`). Must not be `NULL`.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success.
|
||||||
|
* @return ESP_ERR_INVALID_ARG if `vector == NULL` or `*vector == NULL` (not initialized).
|
||||||
|
* @return ESP_ERR_INVALID_STATE if the internal mutex cannot be acquired (rare, indicates a system error).
|
||||||
|
* @return ESP_ERR_NO_MEM if memory allocation fails during capacity reduction.
|
||||||
|
*/
|
||||||
|
esp_err_t zh_vector_remove_duplicates(zh_vector_t **vector);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.1.0
|
2.2.0
|
||||||
+63
-20
@@ -56,6 +56,7 @@ struct _zh_vector_t
|
|||||||
};
|
};
|
||||||
|
|
||||||
static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity);
|
static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity);
|
||||||
|
static esp_err_t _delete(zh_vector_t *vector, uint16_t index);
|
||||||
static inline uint16_t _calc_new_capacity(uint16_t current);
|
static inline uint16_t _calc_new_capacity(uint16_t current);
|
||||||
|
|
||||||
esp_err_t zh_vector_init(zh_vector_t **vector, uint16_t unit) // -V2008
|
esp_err_t zh_vector_init(zh_vector_t **vector, uint16_t unit) // -V2008
|
||||||
@@ -199,33 +200,46 @@ esp_err_t zh_vector_delete_item(zh_vector_t **vector, uint16_t index) // -V2008
|
|||||||
ZH_ERROR_CHECK(vector != NULL && *vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Deleting item in vector failed. Invalid argument.");
|
ZH_ERROR_CHECK(vector != NULL && *vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Deleting item in vector failed. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Deleting item in vector failed. Failed to acquire mutex.");
|
ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Deleting item in vector failed. Failed to acquire mutex.");
|
||||||
ZH_ERROR_CHECK(index < (*vector)->size, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Deleting item in vector failed. Index out of bounds.");
|
ZH_ERROR_CHECK(index < (*vector)->size, ESP_ERR_INVALID_ARG, xSemaphoreGive((*vector)->mutex), "Deleting item in vector failed. Index out of bounds.");
|
||||||
uint16_t last_idx = (*vector)->size - 1;
|
ZH_ERROR_CHECK(_delete(*vector, index) == ESP_OK, ESP_ERR_INVALID_STATE, xSemaphoreGive((*vector)->mutex), "Deleting item in vector failed. Internal error.");
|
||||||
void *freed_item = (*vector)->items[index];
|
|
||||||
if (index != last_idx)
|
|
||||||
{
|
|
||||||
for (uint16_t i = index; i < last_idx; ++i)
|
|
||||||
{
|
|
||||||
(*vector)->items[i] = (*vector)->items[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(*vector)->items[last_idx] = NULL;
|
|
||||||
heap_caps_free(freed_item);
|
|
||||||
--(*vector)->size;
|
|
||||||
if ((*vector)->size > 0 && (*vector)->capacity / 2 > (*vector)->size)
|
|
||||||
{
|
|
||||||
ZH_ERROR_CHECK(_resize(*vector, (*vector)->size) == ESP_OK, ESP_ERR_NO_MEM, xSemaphoreGive((*vector)->mutex), "Deleting item in vector failed. Memory reallocation failed.");
|
|
||||||
}
|
|
||||||
else if ((*vector)->size == 0 && (*vector)->capacity > 0)
|
|
||||||
{
|
|
||||||
_resize(*vector, 0);
|
|
||||||
}
|
|
||||||
xSemaphoreGive((*vector)->mutex);
|
xSemaphoreGive((*vector)->mutex);
|
||||||
ZH_LOGI("Deleting item in vector success.");
|
ZH_LOGI("Deleting item in vector success.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t zh_vector_remove_duplicates(zh_vector_t **vector) // -V2008
|
||||||
|
{
|
||||||
|
ZH_LOGI("Removing duplicates from vector begin.");
|
||||||
|
ZH_ERROR_CHECK(vector != NULL && *vector != NULL, ESP_ERR_INVALID_ARG, NULL, "Removing duplicates from vector failed. Invalid argument.");
|
||||||
|
ZH_ERROR_CHECK(xSemaphoreTake((*vector)->mutex, portMAX_DELAY) == pdTRUE, ESP_ERR_INVALID_STATE, NULL, "Removing duplicates from vector failed. Failed to acquire mutex.");
|
||||||
|
if ((*vector)->size >= 2)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0; i < (*vector)->size - 1; ++i)
|
||||||
|
{
|
||||||
|
uint16_t j = i + 1;
|
||||||
|
while (j < (*vector)->size)
|
||||||
|
{
|
||||||
|
if (memcmp((*vector)->items[i], (*vector)->items[j], (*vector)->unit) == 0)
|
||||||
|
{
|
||||||
|
ZH_ERROR_CHECK(_delete(*vector, j) == ESP_OK, ESP_ERR_INVALID_STATE, xSemaphoreGive((*vector)->mutex), "Removing duplicates from vector failed. Internal error.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive((*vector)->mutex);
|
||||||
|
ZH_LOGI("Removing duplicates from vector success.");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity)
|
static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity)
|
||||||
{
|
{
|
||||||
|
if (capacity < vector->size)
|
||||||
|
{
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
if (capacity == 0)
|
if (capacity == 0)
|
||||||
{
|
{
|
||||||
if (vector->items != NULL)
|
if (vector->items != NULL)
|
||||||
@@ -254,6 +268,35 @@ static esp_err_t _resize(zh_vector_t *vector, uint16_t capacity)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t _delete(zh_vector_t *vector, uint16_t index)
|
||||||
|
{
|
||||||
|
if (index >= vector->size)
|
||||||
|
{
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
void *freed_item = vector->items[index];
|
||||||
|
uint16_t last_idx = vector->size - 1;
|
||||||
|
if (index != last_idx)
|
||||||
|
{
|
||||||
|
for (uint16_t i = index; i < last_idx; ++i)
|
||||||
|
{
|
||||||
|
vector->items[i] = vector->items[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vector->items[last_idx] = NULL;
|
||||||
|
heap_caps_free(freed_item);
|
||||||
|
--vector->size;
|
||||||
|
if (vector->size > 0 && vector->capacity / 2 > vector->size)
|
||||||
|
{
|
||||||
|
return _resize(vector, vector->size);
|
||||||
|
}
|
||||||
|
else if (vector->size == 0 && vector->capacity > 0)
|
||||||
|
{
|
||||||
|
_resize(vector, 0);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint16_t _calc_new_capacity(uint16_t current)
|
static inline uint16_t _calc_new_capacity(uint16_t current)
|
||||||
{
|
{
|
||||||
if (current == 0)
|
if (current == 0)
|
||||||
|
|||||||
Reference in new issue
Block a user