a998f6b981
Release / release (push) Successful in 8s
## Summary Standardize naming conventions across the entire wizapp-stdlib codebase by replacing inconsistent prefixes and snake_case with a unified `wp` prefix + CamelCase scheme. ## Changes ### Naming convention applied | Pattern | Before | After | |---|---|---| | Public functions | `wapp_module_function` | `wpModuleFunction` | | Public types | `GenericXxx`, bare `Xxx` | `WpXxx` | | Constants / enum values | `WAPP_XXX`, `SHELL_XXX` | `WP_XXX`, `WP_SHELL_XXX` | | Internal functions | `_module_function` | `_moduleFunction` | | Storage-class macros | `wapp_extern`, `wapp_intern` | `wp_extern`, `wp_intern` | ### Modules affected All 20 modules were renamed: `arena`, `array`, `dbl_list`, `queue`, `str8`, `mem_allocator`, `mem_utils`, `mem_os`, `file`, `cpath`, `log`, `shell_commander`, `shell_termcolour`, `shell_utils`, `prng/xorshift`, `uuid`, `tester`, `aliases`, `assert`, `misc_utils`, `platform` — plus their test files. ### Backward compatibility Added `src/oldnames.h` with `#define OLD_NAME NEW_NAME` for every renamed symbol, organized by module under Constants → Types → Functions sections. Existing code that includes this file will compile without changes. Reviewed-on: #12 Co-authored-by: Abdelrahman <said.abdelrahman89@gmail.com> Co-committed-by: Abdelrahman <said.abdelrahman89@gmail.com>
481 lines
12 KiB
C
481 lines
12 KiB
C
// vim:fileencoding=utf-8:foldmethod=marker
|
|
|
|
#include "str8.h"
|
|
#include "../../array/array.h"
|
|
#include "../../mem/allocator/mem_allocator.h"
|
|
#include "../../../common/aliases/aliases.h"
|
|
#include "../../../common/assert/assert.h"
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(WpStr8) + sizeof(c8) * CAPACITY)
|
|
|
|
WpStr8 *wpStr8AllocBuf(const WpAllocator *allocator, u64 capacity) {
|
|
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
|
|
|
|
WpStr8 *str = wpMemAllocatorAlloc(allocator, STR8_BUF_ALLOC_SIZE(capacity));
|
|
if (!str) {
|
|
goto RETURN_STR8;
|
|
}
|
|
|
|
str->buf = (u8 *)str + sizeof(WpStr8);
|
|
str->size = 0;
|
|
str->capacity = capacity;
|
|
|
|
RETURN_STR8:
|
|
return str;
|
|
}
|
|
|
|
WpStr8 *wpStr8AllocAndFillBuf(const WpAllocator *allocator, u64 capacity) {
|
|
WpStr8 *out = wpStr8AllocBuf(allocator, capacity);
|
|
if (out) {
|
|
memset(out->buf, 0, capacity);
|
|
out->size = capacity;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
WpStr8 *wpStr8AllocCstr(const WpAllocator *allocator, const char *str) {
|
|
wpDebugAssert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
|
|
|
|
u64 length = strlen(str);
|
|
WpStr8 *output = wpStr8AllocBuf(allocator, length * 2);
|
|
if (!output) {
|
|
goto RETURN_ALLOC_CSTR;
|
|
}
|
|
|
|
output->size = length;
|
|
memcpy(output->buf, str, length);
|
|
|
|
RETURN_ALLOC_CSTR:
|
|
return output;
|
|
}
|
|
|
|
WpStr8 *wpStr8AllocStr8(const WpAllocator *allocator, WpStr8RO *str) {
|
|
wpDebugAssert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
|
|
|
|
WpStr8 *output = wpStr8AllocBuf(allocator, str->capacity);
|
|
if (!output) {
|
|
goto RETURN_ALLOC_STR8;
|
|
}
|
|
|
|
output->size = str->size;
|
|
memcpy(output->buf, str->buf, str->size);
|
|
|
|
RETURN_ALLOC_STR8:
|
|
return output;
|
|
}
|
|
|
|
WpStr8 *wpStr8AllocSubstr(const WpAllocator *allocator, WpStr8RO *str, u64 start, u64 end) {
|
|
wpDebugAssert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
|
|
|
|
WpStr8 *output = NULL;
|
|
|
|
if (start >= str->size || start >= end) {
|
|
goto RETURN_ALLOC_SUBSTR;
|
|
}
|
|
|
|
if (end > str->size) {
|
|
end = str->size;
|
|
}
|
|
|
|
output = wpStr8AllocBuf(allocator, str->capacity);
|
|
if (!output) {
|
|
goto RETURN_ALLOC_SUBSTR;
|
|
}
|
|
|
|
output->size = end - start;
|
|
memcpy(output->buf, str->buf + start, output->size);
|
|
|
|
RETURN_ALLOC_SUBSTR:
|
|
return output;
|
|
}
|
|
|
|
void wpStr8DeallocBuf(const WpAllocator *allocator, WpStr8 **str) {
|
|
wpDebugAssert(allocator != NULL && str != NULL && (*str) != NULL, "Either `allocator` is NULL or `str` is an invalid double pointer");
|
|
wpMemAllocatorFree(allocator, (void **)str, STR8_BUF_ALLOC_SIZE((*str)->capacity));
|
|
}
|
|
|
|
c8 wpStr8Get(const WpStr8 *str, u64 index) {
|
|
if (index >= str->size) {
|
|
return '\0';
|
|
}
|
|
|
|
return str->buf[index];
|
|
}
|
|
|
|
void wpStr8Set(WpStr8 *str, u64 index, c8 c) {
|
|
if (index >= str->size) {
|
|
return;
|
|
}
|
|
|
|
str->buf[index] = c;
|
|
}
|
|
|
|
void wpStr8PushBack(WpStr8 *str, c8 c) {
|
|
if (!(str->size < str->capacity)) {
|
|
return;
|
|
}
|
|
|
|
u64 index = (str->size)++;
|
|
wpStr8Set(str, index, c);
|
|
}
|
|
|
|
b8 wpStr8Equal(WpStr8RO *s1, WpStr8RO *s2) {
|
|
if (s1->size != s2->size) {
|
|
return false;
|
|
}
|
|
|
|
return wpStr8EqualToCount(s1, s2, s1->size);
|
|
}
|
|
|
|
b8 wpStr8EqualToCount(WpStr8RO* s1, WpStr8RO* s2, u64 count) {
|
|
if (!s1 || !s2) {
|
|
return false;
|
|
}
|
|
|
|
return memcmp(s1->buf, s2->buf, count) == 0;
|
|
}
|
|
|
|
WpStr8 wpStr8Slice(WpStr8RO *str, u64 start, u64 end) {
|
|
if (start >= str->size || start >= end) {
|
|
start = str->size;
|
|
end = str->size;
|
|
}
|
|
|
|
if (end > str->size) {
|
|
end = str->size;
|
|
}
|
|
|
|
return (WpStr8RO){
|
|
.capacity = end - start,
|
|
.size = end - start,
|
|
.buf = str->buf + start,
|
|
};
|
|
}
|
|
|
|
WpStr8 *wpStr8AllocConcat(const WpAllocator *allocator, WpStr8 *dst, WpStr8RO *src) {
|
|
wpDebugAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
|
|
|
WpStr8 *output = NULL;
|
|
u64 remaining = dst->capacity - dst->size;
|
|
if (src->size <= remaining) {
|
|
output = dst;
|
|
goto SOURCE_STRING_STR8_CONCAT;
|
|
}
|
|
|
|
u64 capacity = dst->capacity + src->size;
|
|
|
|
output = wpStr8AllocBuf(allocator, capacity);
|
|
if (!output) {
|
|
goto RETURN_STR8_CONCAT;
|
|
}
|
|
|
|
wpStr8ConcatCapped(output, dst);
|
|
|
|
SOURCE_STRING_STR8_CONCAT:
|
|
wpStr8ConcatCapped(output, src);
|
|
|
|
RETURN_STR8_CONCAT:
|
|
return output;
|
|
}
|
|
|
|
void wpStr8ConcatCapped(WpStr8 *dst, WpStr8RO *src) {
|
|
wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
|
|
|
u64 remaining = dst->capacity - dst->size;
|
|
u64 to_copy = remaining < src->size ? remaining : src->size;
|
|
|
|
memcpy(dst->buf + dst->size, src->buf, to_copy);
|
|
dst->size += to_copy;
|
|
}
|
|
|
|
void wpStr8CopyCstrCapped(WpStr8 *dst, const char *src) {
|
|
wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
|
|
|
u64 length = strlen(src);
|
|
u64 to_copy = length <= dst->capacity ? length : dst->capacity;
|
|
|
|
memset(dst->buf, 0, dst->size);
|
|
memcpy(dst->buf, src, to_copy);
|
|
dst->size = to_copy;
|
|
}
|
|
|
|
void wpStr8CopyStr8Capped(WpStr8 *dst, WpStr8RO *src) {
|
|
wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
|
|
|
u64 to_copy = src->size <= dst->capacity ? src->size : dst->capacity;
|
|
|
|
memset(dst->buf, 0, dst->size);
|
|
memcpy(dst->buf, src->buf, to_copy);
|
|
dst->size = to_copy;
|
|
}
|
|
|
|
void wpStr8CopyToCstr(char *dst, WpStr8RO *src, u64 dst_capacity) {
|
|
wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
|
|
|
u64 to_copy = src->size < dst_capacity ? src->size : dst_capacity - 1;
|
|
|
|
memset(dst, 0, dst_capacity);
|
|
memcpy(dst, src->buf, to_copy);
|
|
}
|
|
|
|
void wpStr8Format(WpStr8 *dst, const char *format, ...) {
|
|
wpDebugAssert(dst != NULL && format != NULL, "`dst` and `format` should not be NULL");
|
|
|
|
va_list args1;
|
|
va_list args2;
|
|
|
|
va_start(args1, format);
|
|
va_copy(args2, args1);
|
|
|
|
u64 total_size = vsnprintf(NULL, 0, format, args1);
|
|
dst->size = total_size <= dst->capacity ? total_size : dst->capacity;
|
|
|
|
vsnprintf((char *)(dst->buf), dst->capacity, format, args2);
|
|
|
|
va_end(args1);
|
|
va_end(args2);
|
|
}
|
|
|
|
void wpStr8ToLower(WpStr8 *dst, WpStr8RO *src) {
|
|
wpDebugAssert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
|
|
wpDebugAssert(dst->capacity >= src->capacity, "`dst` does not have enough capacity");
|
|
|
|
dst->size = src->size;
|
|
|
|
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
|
// MSVC Spectre mitigation warnings
|
|
u64 index = 0;
|
|
b8 running = true;
|
|
while (running) {
|
|
wpStr8Set(dst, index, (u8)tolower(wpStr8Get(src, index)));
|
|
++index;
|
|
running = index < src->size;
|
|
}
|
|
}
|
|
|
|
void wpStr8ToUpper(WpStr8 *dst, WpStr8RO *src) {
|
|
wpDebugAssert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
|
|
wpDebugAssert(dst->capacity >= src->capacity, "`dst` does not have enough capacity");
|
|
|
|
dst->size = src->size;
|
|
|
|
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
|
// MSVC Spectre mitigation warnings
|
|
u64 index = 0;
|
|
b8 running = true;
|
|
while (running) {
|
|
wpStr8Set(dst, index, (u8)toupper(wpStr8Get(src, index)));
|
|
++index;
|
|
running = index < src->size;
|
|
}
|
|
}
|
|
|
|
void wpStr8FromBytes(WpStr8 *dst, const WpU8Array src) {
|
|
wpDebugAssert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
|
|
|
|
u64 size = wpArrayCount(src) * wpArrayItemSize(src);
|
|
|
|
wpDebugAssert(dst->capacity >= size, "`dst` does not have enough capacity");
|
|
|
|
dst->size = size;
|
|
memcpy(dst->buf, src, size);
|
|
}
|
|
|
|
i64 wpStr8Find(WpStr8RO *str, WpStr8RO substr) {
|
|
if (!str || substr.size > str->size) {
|
|
return -1;
|
|
}
|
|
|
|
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
|
// MSVC Spectre mitigation warnings
|
|
u64 char_index = 0;
|
|
b8 running = char_index < str->size;
|
|
while (running) {
|
|
const c8 *sub = str->buf + char_index;
|
|
if (memcmp(sub, substr.buf, substr.size) == 0) {
|
|
return char_index;
|
|
}
|
|
|
|
++char_index;
|
|
running = char_index < str->size;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
i64 wpStr8Rfind(WpStr8RO *str, WpStr8RO substr) {
|
|
if (!str || substr.size > str->size) {
|
|
return -1;
|
|
}
|
|
|
|
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
|
// MSVC Spectre mitigation warnings
|
|
i64 char_index = str->size - substr.size;
|
|
b8 running = char_index >= 0;
|
|
while (running) {
|
|
const c8 *sub = str->buf + char_index;
|
|
if (memcmp(sub, substr.buf, substr.size) == 0) {
|
|
return char_index;
|
|
}
|
|
|
|
--char_index;
|
|
running = char_index >= 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
WpStr8List *wpStr8SplitWithMax(const WpAllocator *allocator, WpStr8RO *str, WpStr8RO *delimiter, i64 max_splits) {
|
|
wpDebugAssert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL");
|
|
|
|
WpStr8List *output = wpDblListAlloc(WpStr8, allocator);
|
|
|
|
if (delimiter->size > str->size) {
|
|
WpStr8 *full = wpStr8AllocStr8(allocator, str);
|
|
if (full) {
|
|
wpDblListPushBackAlloc(WpStr8, allocator, output, full);
|
|
}
|
|
|
|
goto RETURN_STR8_SPLIT;
|
|
}
|
|
|
|
i64 start = 0;
|
|
i64 end = 0;
|
|
i64 splits = 0;
|
|
WpStr8 *rest = wpStr8AllocStr8(allocator, str);
|
|
WpStr8 *before_str;
|
|
|
|
while ((end = wpStr8Find(rest, *delimiter)) != -1) {
|
|
if (max_splits > 0 && splits >= max_splits) {
|
|
break;
|
|
}
|
|
|
|
before_str = wpStr8AllocSubstr(allocator, str, start, start + end);
|
|
if (before_str) {
|
|
wpDblListPushBackAlloc(WpStr8, allocator, output, before_str);
|
|
}
|
|
|
|
wpMemAllocatorFree(allocator, (void **)&rest, sizeof(WpStr8));
|
|
rest = wpStr8AllocSubstr(allocator, str, start + end + delimiter->size, str->size);
|
|
start += end + delimiter->size;
|
|
|
|
++splits;
|
|
}
|
|
|
|
// Ensure the last part of the string after the delimiter is added to the list
|
|
rest = wpStr8AllocSubstr(allocator, str, start, str->size);
|
|
if (rest) {
|
|
wpDblListPushBackAlloc(WpStr8, allocator, output, rest);
|
|
}
|
|
|
|
RETURN_STR8_SPLIT:
|
|
return output;
|
|
}
|
|
|
|
WpStr8List *wpStr8RsplitWithMax(const WpAllocator *allocator, WpStr8RO *str, WpStr8RO *delimiter, i64 max_splits) {
|
|
wpDebugAssert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL");
|
|
|
|
WpStr8List *output = wpDblListAlloc(WpStr8, allocator);
|
|
|
|
if (delimiter->size > str->size) {
|
|
WpStr8 *full = wpStr8AllocStr8(allocator, str);
|
|
if (full) {
|
|
wpDblListPushBackAlloc(WpStr8, allocator, output, full);
|
|
}
|
|
|
|
goto RETURN_STR8_SPLIT;
|
|
}
|
|
|
|
i64 end = 0;
|
|
i64 splits = 0;
|
|
WpStr8 *rest = wpStr8AllocStr8(allocator, str);
|
|
WpStr8 *after_str;
|
|
|
|
while ((end = wpStr8Rfind(rest, *delimiter)) != -1) {
|
|
if (max_splits > 0 && splits >= max_splits) {
|
|
break;
|
|
}
|
|
|
|
after_str = wpStr8AllocSubstr(allocator, rest, end + delimiter->size, str->size);
|
|
if (after_str) {
|
|
wpDblListPushFrontAlloc(WpStr8, allocator, output, after_str);
|
|
}
|
|
|
|
wpMemAllocatorFree(allocator, (void **)&rest, sizeof(WpStr8));
|
|
rest = wpStr8AllocSubstr(allocator, rest, 0, end);
|
|
|
|
++splits;
|
|
}
|
|
|
|
rest = wpStr8AllocSubstr(allocator, str, 0, rest->size);
|
|
if (rest) {
|
|
wpDblListPushFrontAlloc(WpStr8, allocator, output, rest);
|
|
}
|
|
|
|
RETURN_STR8_SPLIT:
|
|
return output;
|
|
}
|
|
|
|
WpStr8 *wpStr8Join(const WpAllocator *allocator, const WpStr8List *list, WpStr8RO *delimiter) {
|
|
wpDebugAssert(allocator != NULL && list != NULL && delimiter != NULL, "`allocator`, `list` and `delimiter` should not be NULL");
|
|
|
|
u64 capacity = wpStr8ListTotalSize(list) + (delimiter->size * (list->node_count - 1));
|
|
WpStr8 *output = wpStr8AllocBuf(allocator, capacity * 2);
|
|
|
|
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
|
// MSVC Spectre mitigation warnings
|
|
WpStr8 *node;
|
|
u64 node_index = 0;
|
|
b8 running = node_index < list->node_count;
|
|
while (running) {
|
|
node = wpDblListGet(WpStr8, list, node_index);
|
|
if (!node) {
|
|
break;
|
|
}
|
|
|
|
wpStr8ConcatCapped(output, node);
|
|
|
|
// NOTE (Abdelrahman): Comparison extracted to variable to silence
|
|
// MSVC Spectre mitigation warnings
|
|
b8 not_last = node_index + 1 < list->node_count;
|
|
if (not_last) {
|
|
wpStr8ConcatCapped(output, delimiter);
|
|
}
|
|
|
|
++node_index;
|
|
running = node_index < list->node_count;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
u64 wpStr8ListTotalSize(const WpStr8List *list) {
|
|
if (!list) {
|
|
return 0;
|
|
}
|
|
|
|
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
|
// MSVC Spectre mitigation warnings
|
|
WpStr8 *node;
|
|
u64 node_index = 0;
|
|
u64 output = 0;
|
|
b8 running = node_index < list->node_count;
|
|
while (running) {
|
|
node = wpDblListGet(WpStr8, list, node_index);
|
|
if (!node) {
|
|
break;
|
|
}
|
|
|
|
output += node->size;
|
|
++node_index;
|
|
running = node_index < list->node_count;
|
|
}
|
|
|
|
return output;
|
|
}
|