125 lines
3.9 KiB
C
125 lines
3.9 KiB
C
#include <c_StringList.h>
|
|||
|
|
#include <c_Memory.h>
|
||
|
|
|
||
|
|
c_err_t c_StringList_Init(c_StringList* list, c_size_t initial_capacity) {
|
||
|
|
if (!list) return C_ERR_PARAM;
|
||
|
|
list->size = 0;
|
||
|
|
list->capacity = initial_capacity;
|
||
|
|
if (initial_capacity > 0) {
|
||
|
|
list->strings = (char**)C_ALLOC(initial_capacity * sizeof(char*));
|
||
|
|
if (!list->strings) {
|
||
|
|
list->capacity = 0;
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
list->strings = NULL;
|
||
|
|
}
|
||
|
|
return C_ERR_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_StringList_Destroy(c_StringList* list) {
|
||
|
|
if (!list) return;
|
||
|
|
if (list->strings) {
|
||
|
|
for (c_size_t i = 0; i < list->size; i++) {
|
||
|
|
C_FREE(list->strings[i]);
|
||
|
|
}
|
||
|
|
C_FREE(list->strings);
|
||
|
|
}
|
||
|
|
list->size = 0;
|
||
|
|
list->capacity = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_err_t c_StringList_Append(c_StringList* list, const char* str) {
|
||
|
|
if (!list || !str) return C_ERR_PARAM;
|
||
|
|
if (list->size >= list->capacity) {
|
||
|
|
c_size_t new_capacity = (list->capacity == 0) ? 4 : list->capacity * 2;
|
||
|
|
char** new_array = (char**)C_REALLOC(list->strings, new_capacity * sizeof(char*));
|
||
|
|
if (!new_array) return C_ERR_NOMEM;
|
||
|
|
list->strings = new_array;
|
||
|
|
list->capacity = new_capacity;
|
||
|
|
}
|
||
|
|
char* copy = (char*)C_ALLOC(strlen(str) + 1);
|
||
|
|
if (!copy) return C_ERR_NOMEM;
|
||
|
|
strcpy(copy, str);
|
||
|
|
list->strings[list->size++] = copy;
|
||
|
|
return C_ERR_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Insert a new null-terminated string copy row at the very front of the collection list (Index 0)
|
||
|
|
*/
|
||
|
|
c_err_t c_StringList_Prepend(c_StringList* list, const char* str) {
|
||
|
|
if (!list || !str) {
|
||
|
|
return C_ERR_PARAM;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 1. Dynamic scale check and array reallocation if capacity bounds are reached
|
||
|
|
if (list->size >= list->capacity) {
|
||
|
|
c_size_t new_capacity = (list->capacity == 0) ? 4 : list->capacity * 2;
|
||
|
|
char** new_array = (char**)C_REALLOC(list->strings, new_capacity * sizeof(char*));
|
||
|
|
if (!new_array) {
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
list->strings = new_array;
|
||
|
|
list->capacity = new_capacity;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Allocate an isolated deep-copy heap buffer for the incoming string characters
|
||
|
|
char* str_copy = (char*)C_ALLOC(strlen(str) + 1);
|
||
|
|
if (!str_copy) {
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
strcpy(str_copy, str);
|
||
|
|
|
||
|
|
// 3. Shift all existing string pointer entries rightward by 1 to make room at index 0
|
||
|
|
for (c_size_t i = list->size; i > 0; i--) {
|
||
|
|
list->strings[i] = list->strings[i - 1];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 4. Place the newly allocated string capsule at the front and increment tracking metrics
|
||
|
|
list->strings[0] = str_copy;
|
||
|
|
list->size++;
|
||
|
|
|
||
|
|
return C_ERR_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove the first occurrence of a string value from the collection.
|
||
|
|
* Cleans up memory allocations and tightly shifts elements to prevent layout leaks.
|
||
|
|
*/
|
||
|
|
c_err_t c_StringList_Remove(c_StringList* list, const char* str) {
|
||
|
|
if (!list || !list->strings || !str) {
|
||
|
|
return C_ERR_PARAM;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_size_t target_idx = (c_size_t)-1;
|
||
|
|
|
||
|
|
// 1. Linearly scan the string array to locate a matching value match
|
||
|
|
for (c_size_t i = 0; i < list->size; i++) {
|
||
|
|
if (list->strings[i] != NULL && strcmp(list->strings[i], str) == 0) {
|
||
|
|
target_idx = i;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// If the targeted string value does not exist, return an error code parameter
|
||
|
|
if (target_idx == (c_size_t)-1) {
|
||
|
|
return C_ERR_PARAM;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Safely free the individual string characters heap capsule
|
||
|
|
C_FREE(list->strings[target_idx]); // Safe macro automatically sets index entry to NULL
|
||
|
|
|
||
|
|
// 3. Shift subsequent array entries leftward to maintain dense cache prefetching locality
|
||
|
|
for (c_size_t i = target_idx; i < list->size - 1; i++) {
|
||
|
|
list->strings[i] = list->strings[i + 1];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 4. Update trailing metadata bounds
|
||
|
|
list->size--;
|
||
|
|
list->strings[list->size] = NULL; // Ensure the newly vacant tail slot is nullified safely
|
||
|
|
|
||
|
|
return C_ERR_OK;
|
||
|
|
}
|