diff --git a/src/app/app_win32.c b/src/app/app_win32.c index 4ce944c..a994500 100644 --- a/src/app/app_win32.c +++ b/src/app/app_win32.c @@ -350,9 +350,9 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int n ma_temp_t scratch = ma_begin_scratch(); s8_t dir = os_exe_dir(scratch.arena); for (os_iter_t *it = os_iter(scratch.arena, dir); it->is_valid; os_advance(it)) { - b32 is_dll = s8_ends_with(it->name, s8_lit(".dll"), false); - b32 is_pdb = s8_ends_with(it->name, s8_lit(".pdb"), false); - b32 is_rdi = s8_ends_with(it->name, s8_lit(".rdi"), false); + b32 is_dll = s8_ends_with(it->name, s8_lit(".dll")); + b32 is_pdb = s8_ends_with(it->name, s8_lit(".pdb")); + b32 is_rdi = s8_ends_with(it->name, s8_lit(".rdi")); b32 is_temp = s8_find(it->name, s8_lit("_temp_"), s8_seek_none) != -1; if (is_temp && (is_dll || is_pdb || is_rdi)) { b32 ok = os_delete(it->abs); diff --git a/src/core/core_platform_wasm.c b/src/core/core_platform_wasm.c index f78415a..bc44417 100644 --- a/src/core/core_platform_wasm.c +++ b/src/core/core_platform_wasm.c @@ -30,7 +30,7 @@ fn void os_error_box(char *str) { fn void os_console_log(char *str) { s8_t string = s8_from_char(str); - if (s8_ends_with(string, s8_lit("\n"), false)) { + if (s8_ends_with(string, s8_lit("\n"))) { string = s8_chop(string, 1); } wasm_write_to_console((isize)string.str, (i32)string.len); diff --git a/src/core/core_string.c b/src/core/core_string.c index 7d0a263..17f8484 100644 --- a/src/core/core_string.c +++ b/src/core/core_string.c @@ -45,13 +45,6 @@ fn b32 char_is_alphanumeric(char a) { return result; } -fn i64 wstr_len(wchar_t *string) { - i64 len = 0; - while (*string++ != 0) - len++; - return len; -} - fn s8_t s8_from_range(char *begin, char *end) { assert(end >= begin); intptr_t size = (intptr_t)end - (intptr_t)begin; @@ -66,21 +59,6 @@ fn s8_t s8_from_char(char *string) { return result; } -fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string) { - u16 *buffer = ma_push_array(ma, u16, string.len + 1); - i64 len = wstr_from_str(buffer, string.len + 1, string.str, string.len); - assert(len <= string.len); // @todo: verify - return (s16_t){buffer, len}; -} - -fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string) { - i64 buffer_size = (string.len + 1) * 2; - char *buffer = ma_push_array(ma, char, buffer_size); - i64 len = str_from_wstr(buffer, buffer_size, string.str, string.len); - assert(len < buffer_size); - return (s8_t){buffer, len}; -} - fn s8_t s8_copy(ma_arena_t *ma, s8_t string) { char *copy = (char *)ma_push_size(ma, sizeof(char) * (string.len + 1)); memory_copy(copy, string.str, string.len); @@ -89,7 +67,7 @@ fn s8_t s8_copy(ma_arena_t *ma, s8_t string) { return result; } -s8_t s8_copy_char(ma_arena_t *ma, char *s) { +fn s8_t s8_copy_char(ma_arena_t *ma, char *s) { int64_t len = str_len(s); char *copy = (char *)ma_push_size(ma, sizeof(char) * (len + 1)); memory_copy(copy, s, len); @@ -143,18 +121,26 @@ fn s8_t s8_skip(s8_t string, int64_t len) { return result; } -fn b32 s8_ends_with(s8_t a, s8_t end, b32 ignore_case) { +fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case) { s8_t a_end = s8_get_postfix(a, end.len); b32 result = s8_are_equal_ex(end, a_end, ignore_case); return result; } -fn b32 s8_starts_with(s8_t a, s8_t start, b32 ignore_case) { +fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case) { s8_t a_start = s8_get_prefix(a, start.len); b32 result = s8_are_equal_ex(start, a_start, ignore_case); return result; } +fn b32 s8_ends_with(s8_t a, s8_t end) { + return s8_ends_with_ex(a, end, false); +} + +fn b32 s8_starts_with(s8_t a, s8_t start) { + return s8_starts_with_ex(a, start, false); +} + fn void s8_normalize_path_unsafe(s8_t s) { for (int64_t i = 0; i < s.len; i++) { if (s.str[i] == '\\') @@ -297,34 +283,35 @@ fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag) { return result; } -fn s8_t s8_chop_last_slash(s8_t s) { +fn s8_t s8_chop_last_char(s8_t s, s8_t ch) { s8_t result = s; - s8_seek(s, s8_lit("/"), s8_seek_match_find_last, &result.len); + s8_seek(s, ch, s8_seek_match_find_last, &result.len); return result; } +fn s8_t s8_chop_last_slash(s8_t s) { + return s8_chop_last_char(s, s8_lit("/")); +} + fn s8_t s8_chop_last_period(s8_t s) { + return s8_chop_last_char(s, s8_lit(".")); +} + +fn s8_t s8_skip_to_last_char(s8_t s, s8_t ch) { + int64_t pos; s8_t result = s; - s8_seek(s, s8_lit("."), s8_seek_match_find_last, &result.len); + if (s8_seek(s, ch, s8_seek_match_find_last, &pos)) { + result = s8_skip(result, pos + 1); + } return result; } fn s8_t s8_skip_to_last_slash(s8_t s) { - int64_t pos; - s8_t result = s; - if (s8_seek(s, s8_lit("/"), s8_seek_match_find_last, &pos)) { - result = s8_skip(result, pos + 1); - } - return result; + return s8_skip_to_last_char(s, s8_lit("/")); } fn s8_t s8_skip_to_last_period(s8_t s) { - int64_t pos; - s8_t result = s; - if (s8_seek(s, s8_lit("."), s8_seek_match_find_last, &pos)) { - result = s8_skip(result, pos + 1); - } - return result; + return s8_skip_to_last_char(s, s8_lit(".")); } fn s8_t s8_get_name_no_ext(s8_t s) { @@ -333,10 +320,7 @@ fn s8_t s8_get_name_no_ext(s8_t s) { fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s) { s8_t copy = s8_copy(ma, s); - for (int64_t i = 0; i < copy.len; i++) { - if (copy.str[i] == '\\') - copy.str[i] = '/'; - } + s8_normalize_path_unsafe(copy); return copy; } @@ -489,9 +473,9 @@ fn f64 f64_from_s8(s8_t string) { return result; } -gb_read_only i64 fuzzy_closer_word_begin = 5; -gb_read_only i64 fuzzy_consecutive_multiplier = 3; -fn i64 fuzzy_rate_string(s8_t string, s8_t with) { +gb_read_only i64 s8_fuzzy_closer_word_begin = 5; +gb_read_only i64 s8_fuzzy_consecutive_multiplier = 3; +fn i64 s8_fuzzy_rate_string(s8_t string, s8_t with) { if (with.len == 0) return 0; i64 points = 0; @@ -499,26 +483,26 @@ fn i64 fuzzy_rate_string(s8_t string, s8_t with) { i64 with_i = 0; for (i64 i = 0; i < string.len; i++) { if (string.str[i] == with.str[with_i]) { - i64 closer_begin = CLAMP_BOT((i64)0, fuzzy_closer_word_begin - i); + i64 closer_begin = CLAMP_BOT((i64)0, s8_fuzzy_closer_word_begin - i); points += closer_begin; consecutive++; with_i += 1; } else { - points += consecutive * fuzzy_consecutive_multiplier; + points += consecutive * s8_fuzzy_consecutive_multiplier; consecutive = 0; with_i = 0; } if (with_i >= with.len) with_i = 0; } - points += consecutive * fuzzy_consecutive_multiplier; + points += consecutive * s8_fuzzy_consecutive_multiplier; return points; } -fn fuzzy_pair_t *fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i32 len) { +fn fuzzy_pair_t *s8_fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i32 len) { fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len); for (i32 i = 0; i < len; i += 1) { - pairs[i].rating = fuzzy_rate_string(array[i], needle); + pairs[i].rating = s8_fuzzy_rate_string(array[i], needle); pairs[i].index = i; } diff --git a/src/core/core_string.h b/src/core/core_string.h index 323b14c..5ec8566 100644 --- a/src/core/core_string.h +++ b/src/core/core_string.h @@ -4,18 +4,6 @@ struct s8_t { int64_t len; }; -typedef struct s16_t s16_t; -struct s16_t { - u16 *str; - i64 len; -}; - -typedef struct s32_t s32_t; -struct s32_t { - u32 *str; - i64 len; -}; - typedef struct sb8_node_t sb8_node_t; struct sb8_node_t { sb8_node_t *next; @@ -54,7 +42,6 @@ enum { s8_ignore_case = 1 }; // // char and char string operations fn i32 str_len(char *str); -fn i64 wstr_len(wchar_t *string); fn b32 str_eq(char *a, char *b); fn char char_to_lower_case(char a); fn char char_to_upper_case(char a); @@ -81,15 +68,15 @@ fn f64 f64_from_s8(s8_t string); fn s8_t s8_from_range(char *begin, char *end); fn s8_t s8_from_char(char *string); fn s8_t s8_copy(ma_arena_t *ma, s8_t string); -fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string); -fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string); // // conditional fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case); fn b32 s8_are_equal(s8_t a, s8_t b); -fn b32 s8_ends_with(s8_t a, s8_t end, b32 ignore_case); -fn b32 s8_starts_with(s8_t a, s8_t start, b32 ignore_case); +fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case); +fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case); +fn b32 s8_ends_with(s8_t a, s8_t end); +fn b32 s8_starts_with(s8_t a, s8_t start); fn b32 s8_is_pointer_inside(s8_t string, char *p);// @todo: maybe more general? // @@ -162,7 +149,6 @@ void *sbin_read_data(stream_t *stream, i64 size); #define S8_CODE(...) s8_lit(#__VA_ARGS__) #define S8_FILE s8_lit(__FILE__) #define S8_FILE_AND_LINE s8_lit(FILE_AND_LINE) -#define s16(str,len) (s16_t){str, len} #define S8_FMT(ma, str, result) \ va_list args1; \ diff --git a/src/core/core_string16.c b/src/core/core_string16.c index e69de29..d04b84b 100644 --- a/src/core/core_string16.c +++ b/src/core/core_string16.c @@ -0,0 +1,594 @@ +fn i64 wstr_len(wchar_t *string) { + i64 len = 0; + while (*string++ != 0) + len++; + return len; +} + +fn u16 u16_to_lower_case(u16 a) { + if (a >= 'A' && a <= 'Z') a += 32; + return a; +} + +fn u16 u16_to_upper_case(u16 a) { + if (a >= 'a' && a <= 'z') a -= 32; + return a; +} + +fn b32 u16_is_whitespace(u16 w) { + b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r'; + return result; +} + +fn b32 u16_is_alphabetic(u16 a) { + b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); + return result; +} + +fn b32 u16_is_ident(u16 a) { + b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_'; + return result; +} + +fn b32 u16_is_digit(u16 a) { + b32 result = a >= '0' && a <= '9'; + return result; +} + +fn b32 u16_is_alphanumeric(u16 a) { + b32 result = u16_is_digit(a) || u16_is_alphabetic(a); + return result; +} + +fn s16_t s16_from_range(u16 *begin, u16 *end) { + assert(end >= begin); + intptr_t size = (intptr_t)end - (intptr_t)begin; + s16_t result = {begin, size / 2}; + return result; +} + +fn s16_t s16_from_u16(u16 *string) { + s16_t result; + result.str = string; + result.len = wstr_len(string); + return result; +} + +fn s16_t s16_from_wstr(wchar_t *string) { + return s16_from_u16((u16 *)string); +} + +fn s16_t s16_copy(ma_arena_t *ma, s16_t string) { + i64 byte_size = sizeof(u16) * string.len; + u16 *copy = (u16 *)ma_push_size(ma, byte_size + sizeof(u16)); + memory_copy(copy, string.str, byte_size); + copy[string.len] = 0; + s16_t result = s16(copy, string.len); + return result; +} + +fn s16_t s16_copy_u16(ma_arena_t *ma, u16 *s) { + return s16_copy(ma, s16(s, wstr_len(s))); +} + +fn s16_t s16_copy_wstr(ma_arena_t *ma, wchar_t *s) { + return s16_copy(ma, s16(s, wstr_len(s))); +} + +fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case) { + if (a.len != b.len) return false; + for (i64 i = 0; i < a.len; i++) { + u16 A = a.str[i]; + u16 B = b.str[i]; + if (ignore_case) { + A = u16_to_lower_case(A); + B = u16_to_lower_case(B); + } + if (A != B) + return false; + } + return true; +} + +fn b32 s16_are_equal(s16_t a, s16_t b) { + return s16_are_equal_ex(a, b, false); +} + +fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string) { + u16 *buffer = ma_push_array(ma, u16, string.len + 1); + i64 len = wstr_from_str(buffer, string.len + 1, string.str, string.len); + assert(len <= string.len); // @todo: verify + return (s16_t){buffer, len}; +} + +fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string) { + i64 buffer_size = (string.len + 1) * 2; + char *buffer = ma_push_array(ma, char, buffer_size); + i64 len = str_from_wstr(buffer, buffer_size, string.str, string.len); + assert(len < buffer_size); + return (s8_t){buffer, len}; +} + +fn s16_t s16_get_postfix(s16_t string, i64 len) { + len = CLAMP_TOP(len, string.len); + i64 remain_len = string.len - len; + s16_t result = s16(string.str + remain_len, len); + return result; +} + +fn s16_t s16_get_prefix(s16_t string, i64 len) { + len = CLAMP_TOP(len, string.len); + s16_t result = s16(string.str, len); + return result; +} + +fn s16_t s16_chop(s16_t string, i64 len) { + len = CLAMP_TOP(len, string.len); + s16_t result = s16(string.str, string.len - len); + return result; +} + +fn s16_t s16_skip(s16_t string, i64 len) { + len = CLAMP_TOP(len, string.len); + i64 remain = string.len - len; + s16_t result = s16(string.str + len, remain); + return result; +} + +fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case) { + s16_t a_end = s16_get_postfix(a, end.len); + b32 result = s16_are_equal_ex(end, a_end, ignore_case); + return result; +} + +fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case) { + s16_t a_start = s16_get_prefix(a, start.len); + b32 result = s16_are_equal_ex(start, a_start, ignore_case); + return result; +} + +fn b32 s16_ends_with(s16_t a, s16_t end) { + return s16_ends_with_ex(a, end, false); +} + +fn b32 s16_starts_with(s16_t a, s16_t start) { + return s16_ends_with_ex(a, start, false); +} + +fn void s16_normalize_path_unsafe(s16_t s) { + for (i64 i = 0; i < s.len; i++) { + if (s.str[i] == '\\') + s.str[i] = '/'; + } +} + +fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s) { + s16_t copy = s16_copy(ma, s); + s16_normalize_path_unsafe(copy); + return copy; +} + +fn b32 s16_is_pointer_inside(s16_t string, u16 *p) { + uintptr_t pointer = (uintptr_t)p; + uintptr_t start = (uintptr_t)string.str; + uintptr_t stop = start + (uintptr_t)string.len * sizeof(u16); + b32 result = pointer >= start && pointer < stop; + return result; +} + +fn s16_t s16_cut_start(s16_t *in, i64 size) { + s16_t result = s16_get_prefix(*in, size); + *in = s16_skip(*in, result.len); + return result; +} + +fn s16_t s16_cut_end(s16_t *in, i64 size) { + s16_t result = s16_get_postfix(*in, size); + *in = s16_chop(*in, result.len); + return result; +} + +fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index) { + if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1; + if (first_index < 0) first_index = string.len + first_index; + assert(first_index < one_past_last_index); + assert(string.len > 0); + s16_t result = string; + if (string.len > 0) { + if (one_past_last_index > first_index) { + first_index = CLAMP_TOP(first_index, string.len - 1); + one_past_last_index = CLAMP_TOP(one_past_last_index, string.len); + result.str += first_index; + result.len = one_past_last_index - first_index; + } + else { + result.len = 0; + } + } + return result; +} + +fn s16_t s16_trim(s16_t string) { + if (string.len == 0) + return string; + + i64 whitespace_begin = 0; + for (; whitespace_begin < string.len; whitespace_begin++) { + if (!u16_is_whitespace(string.str[whitespace_begin])) { + break; + } + } + + i64 whitespace_end = string.len; + for (; whitespace_end != whitespace_begin; whitespace_end--) { + if (!u16_is_whitespace(string.str[whitespace_end - 1])) { + break; + } + } + + if (whitespace_begin == whitespace_end) { + string.len = 0; + } + else { + string = s16_slice(string, whitespace_begin, whitespace_end); + } + + return string; +} + +fn s16_t s16_trim_end(s16_t string) { + i64 whitespace_end = string.len; + for (; whitespace_end != 0; whitespace_end--) { + if (!u16_is_whitespace(string.str[whitespace_end - 1])) { + break; + } + } + + s16_t result = s16_get_prefix(string, whitespace_end); + return result; +} + +fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out) { + b32 ignore_case = flags & s16_seek_ignore_case ? true : false; + b32 result = false; + if (flags & s16_seek_match_find_last) { + for (int64_t i = string.len; i != 0; i--) { + int64_t index = i - 1; + s16_t substring = s16_slice(string, index, index + find.len); + if (s16_are_equal_ex(substring, find, ignore_case)) { + if (index_out) + *index_out = index; + result = true; + break; + } + } + } + else { + for (int64_t i = 0; i < string.len; i++) { + s16_t substring = s16_slice(string, i, i + find.len); + if (s16_are_equal_ex(substring, find, ignore_case)) { + if (index_out) + *index_out = i; + result = true; + break; + } + } + } + + return result; +} + +fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag) { + int64_t result = -1; + s16_seek(string, find, flag, &result); + return result; +} + +fn s16_t s16_chop_last_char(s16_t s, s16_t ch) { + s16_t result = s; + s16_seek(s, ch, s16_seek_match_find_last, &result.len); + return result; +} + +fn s16_t s16_chop_last_slash(s16_t s) { + return s16_chop_last_char(s, s16_lit("/")); +} + +fn s16_t s16_chop_last_period(s16_t s) { + return s16_chop_last_char(s, s16_lit(".")); +} + +fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch) { + int64_t pos; + s16_t result = s; + if (s16_seek(s, ch, s16_seek_match_find_last, &pos)) { + result = s16_skip(result, pos + 1); + } + return result; +} + +fn s16_t s16_skip_to_last_slash(s16_t s) { + return s16_skip_to_last_char(s, s16_lit("/")); +} + +fn s16_t s16_skip_to_last_period(s16_t s) { + return s16_skip_to_last_char(s, s16_lit(".")); +} + +fn s16_t s16_get_name_no_ext(s16_t s) { + return s16_skip_to_last_slash(s16_chop_last_period(s)); +} + +fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s) { + s16_t copy = s16_copy(ma, s); + for (int64_t i = 0; i < copy.len; i++) { + copy.str[i] = u16_to_lower_case(copy.str[i]); + } + return copy; +} + +fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s) { + s16_t copy = s16_copy(ma, s); + for (int64_t i = 0; i < copy.len; i++) { + copy.str[i] = u16_to_upper_case(copy.str[i]); + } + return copy; +} + +fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...) { + ma_temp_t scratch = ma_begin_scratch1(ma); + S8_FMT(scratch.arena, str, result); + s16_t result16 = s16_from_s8(ma, result); + ma_end_scratch(scratch); + return result16; +} + +fn u64 u64_from_s16(s16_t s, u64 base) { + assert(base >= 2 && base <= 16); + u64 acc = 0; + for (i64 i = 0; i < s.len; i++) { + u64 num = u64_from_hexchar((char)s.str[i]); + assert(num < base); + acc *= base; + acc += num; + } + return acc; +} + +fn f64 f64_from_s16(s16_t string) { + ma_temp_t scratch = ma_begin_scratch(); + s8_t num_string = s8_from_s16(scratch.arena, string); + f64 result = os_parse_float(num_string.str); + ma_end_scratch(scratch); + return result; +} + +gb_read_only i64 s16_fuzzy_closer_word_begin = 5; +gb_read_only i64 s16_fuzzy_consecutive_multiplier = 3; +fn i64 s16_fuzzy_rate(s16_t string, s16_t with) { + if (with.len == 0) return 0; + + i64 points = 0; + i64 consecutive = 0; + i64 with_i = 0; + for (i64 i = 0; i < string.len; i++) { + if (string.str[i] == with.str[with_i]) { + i64 closer_begin = CLAMP_BOT((i64)0, s16_fuzzy_closer_word_begin - i); + points += closer_begin; + consecutive++; + with_i += 1; + } else { + points += consecutive * s16_fuzzy_consecutive_multiplier; + consecutive = 0; + with_i = 0; + } + + if (with_i >= with.len) with_i = 0; + } + points += consecutive * s16_fuzzy_consecutive_multiplier; + return points; +} + +fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len) { + fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len); + for (i32 i = 0; i < len; i += 1) { + pairs[i].rating = s16_fuzzy_rate(array[i], needle); + pairs[i].index = i; + } + + for (i32 i = 0; i < len - 1; i++) { + for (i32 j = 0; j < len - 1; j++) { + if (pairs[j].rating < pairs[j + 1].rating) { + SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]); + } + } + } + + return pairs; +} + +fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str) { + sb16_node_t *node = ma_push_type(ma, sb16_node_t); + node->string = str; + return node; +} + +fn sb16_node_t *sb16_append(sb16_t *list, s16_t string) { + assert(list->arena != NULL); + sb16_node_t *node = sb16_create_node(list->arena, string); + SLLQ_APPEND(list->first, list->last, node); + return node; +} + +fn s16_t sb16_printf(sb16_t *sb, const char *str, ...) { + ma_temp_t scratch = ma_begin_scratch1(sb->arena); + S8_FMT(scratch.arena, str, result); + s16_t result16 = s16_from_s8(sb->arena, result); + sb16_append(sb, result16); + ma_end_scratch(scratch); + return result16; +} + +fn void sb16_indent(sb16_t *sb) { + sb16_printf(sb, "\n%.*s", sb->indent*4, " "); +} + +fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...) { + ma_temp_t scratch = ma_begin_scratch1(sb->arena); + S8_FMT(scratch.arena, str, result); + s16_t result16 = s16_from_s8(sb->arena, result); + sb16_indent(sb); + sb16_append(sb, result16); + ma_end_scratch(scratch); + return result16; +} + +fn int64_t sb16_char_size(sb16_t *sb) { + int64_t result = 0; + for (sb16_node_t *it = sb->first; it; it = it->next) { + result += it->len; + } + return result; +} + +fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb) { + int64_t size = sb16_char_size(sb) + 1; + i64 byte_size = size * sizeof(u16); + u16 *str = ma_push_size(arena, byte_size); + s16_t result = {str, 0}; + for (sb16_node_t *it = sb->first; it; it = it->next) { + memory_copy(result.str + result.len, it->str, it->len * sizeof(u16)); + result.len += it->len; + } + result.str[result.len] = 0; + return result; +} + +fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags) { + sb16_t result = (sb16_t){ma}; + int64_t index = 0; + + s16_seek_t find_flag = flags & s16_split_ignore_case ? s16_seek_ignore_case : s16_seek_none; + while (s16_seek(string, find, find_flag, &index)) { + s16_t before_match = s16(string.str, index); + sb16_append(&result, before_match); + if (flags & s16_split_inclusive) { + s16_t match = s16(string.str + index, find.len); + sb16_append(&result, match); + } + string = s16_skip(string, index + find.len); + } + if (string.len) sb16_append(&result, string); + return result; +} + +fn_test void test_string16(void) { + ma_temp_t scratch = ma_begin_scratch(); + + // string16 lit basic tests + { + s16_t a = s16_lit("memes"); + s16_t b = s16_lit("not memes"); + s16_t c = s16_lit("MEMES"); + assert(a.len == 5); + assert(a.str[0] == L'm'); + assert(a.str[4] == L's'); + assert(s16_are_equal(a, b) == false); + assert(s16_are_equal(a, a) == true); + assert(s16_are_equal_ex(a, c, true) == true); + assert(sizeof(wchar_t) == sizeof(u16)); + } + + { + assert(u16_to_upper_case('a') == L'A'); + assert(u16_to_upper_case('a') == 'A'); + assert(u16_to_upper_case(L'a') == 'A'); + assert(u16_is_digit('3')); + } + + { + s16_t a = s16_from_wstr(L"memes"); + assert(a.len == 5); + assert(s16_are_equal(a, s16_lit("memes")) == true); + + s16_t b = s16_copy(scratch.arena, a); + assert(a.str != b.str); + assert(b.len == a.len); + assert(s16_are_equal(a, b)); + + s16_t c = s16_from_range(a.str, a.str + a.len); + assert(s16_are_equal(a, c)); + } + + { + s16_t a = s16_lit("thing itself"); + assert(s16_starts_with_ex(a, s16_lit("thing"), false)); + assert(!s16_starts_with_ex(a, s16_lit("thing itself and"), false)); + assert(!s16_starts_with_ex(a, s16_lit("thing itself "), false)); + assert(s16_starts_with_ex(a, s16_lit("THING"), true)); + assert(!s16_starts_with_ex(a, s16_lit("a"), false)); + + assert(s16_ends_with_ex(a, s16_lit("itself"), false)); + assert(s16_ends_with_ex(a, s16_lit("thing itself"), false)); + assert(!s16_ends_with_ex(a, s16_lit("thing itselfa"), false)); + + s16_t b = s16_lit("memes"); + assert(s16_is_pointer_inside(b, b.str)); + assert(s16_is_pointer_inside(b, b.str + 4)); + assert(!s16_is_pointer_inside(b, b.str + 5)); + } + + { + s16_t a = s16_lit("C:\\Program Files\\Memes"); + s16_normalize_path_unsafe(a); + assert(a.str[2] == '/'); + } + + { + s16_t a = s16_lit(" thing "); + s16_t b = s16_trim(a); + assert(s16_are_equal(b, s16_lit("thing"))); + } + + { + s16_t a = s16_printf(scratch.arena, "%d", 432); + assert(s16_are_equal(a, s16_lit("432"))); + assert(f64_from_s16(s16_lit("432.0")) == 432.0); + assert(u64_from_s16(s16_lit("432"), 10) == 432); + } + + { + sb16_t *list = sb16_serial_begin(scratch.arena); + sb16_printf(list, "%d ", 987); + sb16_printf(list, "ter "); + sb16_printf(list, "|"); + s16_t string = sb16_serial_end(scratch.arena, list); + assert(s16_are_equal(string, s16_lit("987 ter |"))); + } + + { + s16_t a = s16_lit("A|B|dek|mek|vek|"); + sb16_t b = s16_split(scratch.arena, a, s16_lit("|"), s16_split_none); + assert(s16_are_equal(b.first->string, s16_lit("A"))); + assert(s16_are_equal(b.first->next->string, s16_lit("B"))); + assert(s16_are_equal(b.first->next->next->string, s16_lit("dek"))); + assert(s16_are_equal(b.first->next->next->next->string, s16_lit("mek"))); + assert(s16_are_equal(b.first->next->next->next->next->string, s16_lit("vek"))); + assert(b.first->next->next->next->next->next == NULL); + } + + { + s16_t a = s16_to_upper_case(scratch.arena, s16_lit("thing Meme")); + assert(s16_are_equal(a, s16_lit("THING MEME"))); + + a = s16_to_lower_case(scratch.arena, s16_lit("THING Meme")); + assert(s16_are_equal(a, s16_lit("thing meme"))); + } + + { + s16_t a = s16_lit("C:/thing/itself"); + assert(s16_are_equal(s16_chop_last_slash(a), s16_lit("C:/thing"))); + } + + ma_end_scratch(scratch); +} \ No newline at end of file diff --git a/src/core/core_string16.h b/src/core/core_string16.h index e69de29..9c0b943 100644 --- a/src/core/core_string16.h +++ b/src/core/core_string16.h @@ -0,0 +1,114 @@ +typedef struct s16_t s16_t; +struct s16_t { + u16 *str; + i64 len; +}; + +typedef struct sb16_node_t sb16_node_t; +struct sb16_node_t { + sb16_node_t *next; + union { + struct { u16 *str; int64_t len; }; + s16_t string; + }; +}; + +typedef struct sb16_t sb16_t; +struct sb16_t { + ma_arena_t *arena; + sb16_node_t *first; + sb16_node_t *last; + + // WARNING: remember to update typeinfo after editing this + i32 indent; +}; + +typedef i32 s16_seek_t; +enum { + s16_seek_none = 0, + s16_seek_ignore_case = 1, + s16_seek_match_find_last = 2, +}; + +typedef i32 s16_split_t; +enum { + s16_split_none = 0, + s16_split_ignore_case = 1, + s16_split_inclusive = 2, +}; + +enum { s16_ignore_case = 1 }; + + +typedef struct s32_t s32_t; +struct s32_t { + u32 *str; + i64 len; +}; + +#define s16(str,len) (s16_t){str, len} +#define s16_lit(str) (s16_t){L##str, sizeof(L##str) / sizeof(u16) - 1} +#define s16_invalid s16_lit("") + +#define sb16(ARENA) &(sb16_t){.arena = arena} +#define sb16_serial_begin(ARENA) &(sb16_t){.arena = ARENA} +#define sb16_serial_end(ARENA, SB) sb16_merge(ARENA, SB) + +fn i64 wstr_len(wchar_t *string); +fn u16 u16_to_lower_case(u16 a); +fn u16 u16_to_upper_case(u16 a); +fn b32 u16_is_whitespace(u16 w); +fn b32 u16_is_alphabetic(u16 a); +fn b32 u16_is_ident(u16 a); +fn b32 u16_is_digit(u16 a); +fn b32 u16_is_alphanumeric(u16 a); +fn s16_t s16_from_range(u16 *begin, u16 *end); +fn s16_t s16_from_u16(u16 *string); +fn s16_t s16_from_wstr(wchar_t *string); +fn s16_t s16_copy(ma_arena_t *ma, s16_t string); +fn s16_t s16_copy_u16(ma_arena_t *ma, u16 *s); +fn s16_t s16_copy_wstr(ma_arena_t *ma, wchar_t *s); +fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case); +fn b32 s16_are_equal(s16_t a, s16_t b); +fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string); +fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string); +fn s16_t s16_get_postfix(s16_t string, i64 len); +fn s16_t s16_get_prefix(s16_t string, i64 len); +fn s16_t s16_chop(s16_t string, i64 len); +fn s16_t s16_skip(s16_t string, i64 len); +fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case); +fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case); +fn b32 s16_ends_with(s16_t a, s16_t end); +fn b32 s16_starts_with(s16_t a, s16_t start); +fn void s16_normalize_path_unsafe(s16_t s); +fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s); +fn b32 s16_is_pointer_inside(s16_t string, u16 *p); +fn s16_t s16_cut_start(s16_t *in, i64 size); +fn s16_t s16_cut_end(s16_t *in, i64 size); +fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index); +fn s16_t s16_trim(s16_t string); +fn s16_t s16_trim_end(s16_t string); +fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out); +fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag); +fn s16_t s16_chop_last_char(s16_t s, s16_t ch); +fn s16_t s16_chop_last_slash(s16_t s); +fn s16_t s16_chop_last_period(s16_t s); +fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch); +fn s16_t s16_skip_to_last_slash(s16_t s); +fn s16_t s16_skip_to_last_period(s16_t s); +fn s16_t s16_get_name_no_ext(s16_t s); +fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s); +fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s); +fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...); +fn u64 u64_from_s16(s16_t s, u64 base); +fn f64 f64_from_s16(s16_t string); +fn i64 s16_fuzzy_rate(s16_t string, s16_t with); +fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len); +fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str); +fn sb16_node_t *sb16_append(sb16_t *list, s16_t string); +fn s16_t sb16_printf(sb16_t *sb, const char *str, ...); +fn void sb16_indent(sb16_t *sb); +fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...); +fn int64_t sb16_char_size(sb16_t *sb); +fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb); +fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags); \ No newline at end of file diff --git a/src/meta/meta_cfiles.c b/src/meta/meta_cfiles.c index 69d5969..3bbfa5b 100644 --- a/src/meta/meta_cfiles.c +++ b/src/meta/meta_cfiles.c @@ -48,7 +48,7 @@ fn mt_file_t *mt_find_file_exact(mt_files_t *root, s8_t path) { fn mt_file_t *mt_find_file(mt_files_t *root, s8_t name) { for (mt_file_t *it = root->first; it; it = it->next) { - if (s8_ends_with(name, it->path, false)) return it; + if (s8_ends_with(name, it->path)) return it; } return NULL; } diff --git a/src/testing/testing.gen.c b/src/testing/testing.gen.c index 5ed2072..1b1b98a 100644 --- a/src/testing/testing.gen.c +++ b/src/testing/testing.gen.c @@ -1,4 +1,5 @@ fn void run_tests(void) { + test_string16(); test_hash_table(); test_intern_table(); } diff --git a/src/text_editor/text_editor.gen.c b/src/text_editor/text_editor.gen.c index 256a74c..a48a534 100644 --- a/src/text_editor/text_editor.gen.c +++ b/src/text_editor/text_editor.gen.c @@ -7,6 +7,7 @@ gb_read_only mt_tweak_t tweak_table[] = { }; void run_all_tests(void) { + test_string16(); test_hash_table(); test_intern_table(); ui_test_text_replace(); diff --git a/src/ui/ui.meta.c b/src/ui/ui.meta.c index 3d5dddb..0057a5e 100644 --- a/src/ui/ui.meta.c +++ b/src/ui/ui.meta.c @@ -55,12 +55,12 @@ fn void mt_ui_stacks(ma_arena_t *arena, sb8_t *c, sb8_t *h) { // create `stack` and `node` columns for (ast_t *it = table->first; it; it = it->next) { s8_t type = mtts(it, "type"); - if (s8_ends_with(type, s8_lit("_t"), false)) { + if (s8_ends_with(type, s8_lit("_t"))) { type = s8_chop(type, 2); } s8_t ui_type = type; - if (!s8_starts_with(ui_type, s8_lit("ui_"), false)) { + if (!s8_starts_with(ui_type, s8_lit("ui_"))) { ui_type = s8_printf(arena, "ui_%S", ui_type); } @@ -136,7 +136,7 @@ fn void mt_ui_stacks(ma_arena_t *arena, sb8_t *c, sb8_t *h) { sb8_stmtf(c, "fn void ui_box_fill_with_colors(ui_box_t *box) {"); for (ast_t *it = table->first; it; it = it->next) { - if (!s8_ends_with(mtts(it, "name"), s8_lit("_color"), false)) { + if (!s8_ends_with(mtts(it, "name"), s8_lit("_color"))) { continue; } mt_stmtf(c, it, "box->@name = ui_top_@name();"); diff --git a/src/wasm_app/wasm_app.gen.c b/src/wasm_app/wasm_app.gen.c index 85e6f9f..dda8164 100644 --- a/src/wasm_app/wasm_app.gen.c +++ b/src/wasm_app/wasm_app.gen.c @@ -7,6 +7,7 @@ gb_read_only mt_tweak_t tweak_table[] = { }; void run_all_tests(void) { + test_string16(); test_hash_table(); test_intern_table(); ui_test_text_replace();