diff --git a/src/main.c b/src/main.c index 2299920..2e140e9 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include "mini_arena.h" #include "platform.h" #include "pool.h" +#include "string.h" #include #include @@ -411,6 +412,38 @@ void apool_test_autogrow(void) } +void string_test_1(void) +{ + TRACEF("\n"); + + Str str1 = S_("Hello"); + printf("str1: %.*s len %d\n", str1.len, str1.str, str1.len); + U64 str1_index_of_l = str_find_byte(str1, 'l'); + U64 str1_index_of_g = str_find_byte(str1, 'g'); + printf("str1: index of l %ld, index of g: %ld\n", str1_index_of_l, str1_index_of_g); + + MARENA_DEFINE(arena, 512, 1); + Allocator alloc = marena_allocator(&arena); + Str str2 = str_dup(&alloc, S_(" World")); + Str str3 = str_concat(&alloc, str1, str2); + printf("str3: %.*s len %d\n", str3.len, str3.str, str3.len); +} + +void string_split_test_1(void) +{ + TRACEF("\n"); + + Str str1 = S_("a:bb|ccc"); + Str sep = S_("|:"); + STRVEC_DEFINE(strings, 16); + + str_split(str1, sep, &strings); + for (U32 i = 0; i < strings.len; i++) { + Str *str = &strings.strings[i]; + printf("split %u: '%.*s'\n", i, str->len, str->str); + } +} + int main(int argc, char *argv[]) { arena_test_1(); @@ -423,6 +456,8 @@ int main(int argc, char *argv[]) apool_test(); apool_test_autogrow(); apool_test_miniarena(); + string_test_1(); + string_split_test_1(); } diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..1bc3e13 --- /dev/null +++ b/src/string.c @@ -0,0 +1,72 @@ +#include "string.h" + +Str str_empty(void) +{ + static const U8 empty_; + static const Str str = {(U8 *)&empty_, 0}; + return str; +} + +Str str_substr(Str str, U32 start, U32 len) +{ + Assert(start < str.len); + Assert(len <= str.len); + + Str new_str = str_create(&str.str[start], len); + return new_str; +} + + +Str str_concat(Allocator *alloc, Str first, Str second) +{ + Str str; + + str.len = first.len + second.len; + str.str = allocator_push(alloc, str.len, 1);; + + MemCopy(str.str, first.str, first.len); + MemCopy(&str.str[first.len], second.str, second.len); + + return str; +} + +Str str_push(Allocator *alloc, Str str) +{ + U8 *mem = (U8 *)allocator_push(alloc, sizeof(Str) + str.len, alignof(Str)); + Str *new_str = (Str *)mem; + new_str->len = str.len; + new_str->str = &mem[sizeof(Str)]; + if (!str_is_empty(str)) { + MemCopy(new_str->str, str.str, str.len); + } + + return *new_str; +} + +// split @str on any byte in @separators, place split strings in @vec +void str_split(Str str, Str separators, StrVec *vec) +{ + if (vec->max_len == 0 || str.len == 0) { + return; + } + + U32 start_pos = 0; + for (U32 i = 0; i < str.len; i++) { + U8 byte = str.str[i]; + if (str_find_byte(separators, byte) != -1) { + if (vec->len >= vec->max_len) { + break; + } + + Str sub_str = str_substr(str, start_pos, i - start_pos); + vec->strings[vec->len] = sub_str; + vec->len++; + start_pos = i + 1; + } + } + if (start_pos < str.len && vec->len < vec->max_len) { + Str sub_str = str_substr(str, start_pos, str.len - start_pos); + vec->strings[vec->len] = sub_str; + vec->len++; + } +} diff --git a/src/string.h b/src/string.h new file mode 100644 index 0000000..8dd10ba --- /dev/null +++ b/src/string.h @@ -0,0 +1,78 @@ +#pragma once +#include "base_core.h" + +typedef struct Str Str; +struct Str { + U8 *str; + U32 len; +}; + +Str str_empty(void); +Str str_substr(Str str, U32 start, U32 len); +Str str_concat(Allocator *alloc, Str first, Str second); +Str str_push(Allocator *alloc, Str str); + +#define str_from_lit(str) str_create(((U8 *)str), sizeof(str) -1) +#define S_(str) str_from_lit(str) +#define cstr_len(str) (U32)strlen(str) +#define str_dup(alloc, str) str_push((alloc), (str)) + +static INLINE bool str_is_empty(Str str) +{ + return str.len == 0; +} + +static INLINE Str str_create(U8 *start, U32 len) +{ + Str str = {start, len}; + return str; +} + +static INLINE Str str_from_cstr(const char *cstr) +{ + Str str = str_create((U8 *)cstr, cstr_len(cstr)); + return str; +} + +static INLINE Str str_push_cstr(Allocator *alloc, const char *cstr) +{ + Str str = str_from_cstr(cstr); + return str_push(alloc, str); +} + +static INLINE S64 str_find_byte(Str str, U8 byte) +{ + for (U32 i = 0; i < str.len; i++) { + if (str.str[i] == byte) { + return i; + } + } + + return -1; +} + +static INLINE Str str_skip(Str str, U32 len) +{ + U32 skip_len = Min(str.len, len); + Str new_str = str_substr(str, skip_len, str.len - skip_len); + + return new_str; +} + + +// String Vector +typedef struct StrVec StrVec; +struct StrVec { + Str *strings; + U32 len; + U32 max_len; +}; +#define STRVEC_STATIC_INITIALIZER(strings_) STRVEC_INITIALIZER((strings_), ArraySize(strings_)) +#define STRVEC_INITIALIZER(strings_, len_) {.strings = (strings_), .len = 0, .max_len = (len_)} +#define STRVEC_DEFINE(var_name, len_) \ + struct { \ + Str strings[len_];\ + } var_name##_strvec_array; \ + StrVec var_name = STRVEC_STATIC_INITIALIZER(var_name##_strvec_array.strings) + +void str_split(Str str, Str separators, StrVec *vec);