diff --git a/code/base/strings.c b/code/base/strings.c index 5c17513..71799ab 100644 --- a/code/base/strings.c +++ b/code/base/strings.c @@ -20,39 +20,39 @@ //~ NOTE(allen): String <-> Integer Tables read_only global U8 integer_symbols[16] = { - '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', }; // NOTE(allen): Includes reverses for uppercase and lowercase hex. read_only global U8 integer_symbol_reverse[128] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; read_only global U8 base64[64] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '_', '$', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '_', '$', }; read_only global U8 base64_reverse[128] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, - 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, - 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, - 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, + 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, }; //////////////////////////////// @@ -163,7 +163,7 @@ str8_skip_chop_whitespace(String8 string) String8 push_str8_cat(Arena* arena, String8 s1, String8 s2) { -#if MD_DONT_MAP_ANREA_TO_ALLOCATOR_IMPL +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL String8 str; str.size = s1.size + s2.size; str.str = push_array_no_zero(arena, U8, str.size + 1); @@ -178,7 +178,7 @@ push_str8_cat(Arena* arena, String8 s1, String8 s2) String8 push_str8_copy(Arena* arena, String8 s){ -#if MD_DONT_MAP_ANREA_TO_ALLOCATOR_IMPL +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL String8 str; str.size = s.size; str.str = push_array_no_zero(arena, U8, str.size + 1); @@ -192,7 +192,7 @@ push_str8_copy(Arena* arena, String8 s){ String8 push_str8fv(Arena* arena, char* fmt, va_list args){ -#if MD_DONT_MAP_ANREA_TO_ALLOCATOR_IMPL +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL va_list args2; va_copy(args2, args); U32 needed_bytes = raddbg_vsnprintf(0, 0, fmt, args) + 1; @@ -326,7 +326,7 @@ try_u64_from_str8_c_rules(String8 string, U64 *x) String8 str8_from_memory_size(Arena* arena, U64 z) { -#if MD_DONT_MAP_ANREA_TO_ALLOCATOR_IMPL +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL String8 result = {0}; if (z < KB(1)) { result = push_str8f(arena, "%llu b", z); @@ -548,7 +548,7 @@ str8_from_allocator_u64(AllocatorInfo ainfo, U64 u64, U32 radix, U8 min_digits, String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator) { -#if MD_DONT_MAP_ANREA_TO_ALLOCATOR_IMPL +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL String8 result = {0}; // TODO(rjf): preeeeetty sloppy... if(s64 < 0) { @@ -650,7 +650,7 @@ str8_list_concat_in_place(String8List* list, String8List* to_push) { String8Node* str8_list_push_aligner(Arena* arena, String8List* list, U64 min, U64 align) { -#if MD_DONT_MAP_ANREA_TO_ALLOCATOR_IMPL +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL String8Node* node = push_array_no_zero(arena, String8Node, 1); U64 new_size = list->total_size + min; U64 increase_size = 0; @@ -674,7 +674,7 @@ str8_list_push_aligner(Arena* arena, String8List* list, U64 min, U64 align) node->string.size = increase_size; return(node); #else - return str8_list_aligner(arena_allocator(arena), list, min, align) + return str8_list_aligner(arena_allocator(arena), list, min, align); #endif } @@ -741,7 +741,8 @@ str8_list_alloc_copy(AllocatorInfo ainfo, String8List* list) //~ rjf: String Splitting & Joining String8List -str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags){ +str8_split(Arena* arena, String8 string, U8* split_chars, U64 split_char_count, StringSplitFlags flags) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL String8List list = {0}; B32 keep_empties = (flags & StringSplitFlag_KeepEmpties); @@ -773,346 +774,329 @@ str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, ptr += 1; } return(list); +#else + return str8_split_alloc(arena_allocator(arena), string, split_chars, split_char_count, flags); +#endif } String8List -str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags){ - String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); - return list; -} - -String8List -str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags){ - String8List result = {0}; - for (String8Node *node = list.first; node != 0; node = node->next){ - String8List split = str8_split_by_string_chars(arena, node->string, split_chars, flags); - str8_list_concat_in_place(&result, &split); - } - return result; +str8_split_alloc(AllocatorInfo ainfo, String8 string, U8* split_chars, U64 split_char_count, StringSplitFlags flags) { + String8List list = {0}; + + B32 keep_empties = (flags & StringSplitFlag_KeepEmpties); + + U8* ptr = string.str; + U8* opl = string.str + string.size; + for (;ptr < opl;) + { + U8* first = ptr; + for (;ptr < opl; ptr += 1) + { + U8 c = *ptr; + B32 is_split = 0; + for (U64 i = 0; i < split_char_count; i += 1) { + if (split_chars[i] == c) { + is_split = 1; + break; + } + } + if (is_split){ + break; + } + } + + String8 string = str8_range(first, ptr); + if (keep_empties || string.size > 0){ + str8_list_alloc(ainfo, &list, string); + } + ptr += 1; + } + return(list); } String8 -str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ - StringJoin join = {0}; - if (optional_params != 0){ - MemoryCopyStruct(&join, optional_params); - } - - U64 sep_count = 0; - if (list->node_count > 0){ - sep_count = list->node_count - 1; - } - - String8 result; - result.size = join.pre.size + join.post.size + sep_count*join.sep.size + list->total_size; - U8 *ptr = result.str = push_array_no_zero(arena, U8, result.size + 1); - - MemoryCopy(ptr, join.pre.str, join.pre.size); - ptr += join.pre.size; - for (String8Node *node = list->first; - node != 0; - node = node->next){ - MemoryCopy(ptr, node->string.str, node->string.size); - ptr += node->string.size; - if (node->next != 0){ - MemoryCopy(ptr, join.sep.str, join.sep.size); - ptr += join.sep.size; - } - } - MemoryCopy(ptr, join.post.str, join.post.size); - ptr += join.post.size; - - *ptr = 0; - - return(result); -} - -void -str8_list_from_flags(Arena *arena, String8List *list, - U32 flags, String8 *flag_string_table, U32 flag_string_count){ - for (U32 i = 0; i < flag_string_count; i += 1){ - U32 flag = (1 << i); - if (flags & flag){ - str8_list_push(arena, list, flag_string_table[i]); - } - } -} - -//////////////////////////////// -//~ rjf; String Arrays - -internal String8Array -str8_array_from_list(Arena *arena, String8List *list) +str8_list_join(Arena* arena, String8List* list, StringJoin* optional_params) { - String8Array array; - array.count = list->node_count; - array.v = push_array_no_zero(arena, String8, array.count); - U64 idx = 0; - for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) - { - array.v[idx] = n->string; - } - return array; +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + StringJoin join = {0}; + if (optional_params != 0){ + memory_copy_struct(&join, optional_params); + } + + U64 sep_count = 0; + if (list->node_count > 0){ + sep_count = list->node_count - 1; + } + + String8 result; + result.size = join.pre.size + join.post.size + sep_count*join.sep.size + list->total_size; + U8 *ptr = result.str = push_array_no_zero(arena, U8, result.size + 1); + + MemoryCopy(ptr, join.pre.str, join.pre.size); + ptr += join.pre.size; + for (String8Node *node = list->first; node != 0; node = node->next) + { + memory_copy(ptr, node->string.str, node->string.size); + ptr += node->string.size; + if (node->next != 0) { + memory_copy(ptr, join.sep.str, join.sep.size); + ptr += join.sep.size; + } + } + memory_copy(ptr, join.post.str, join.post.size); + ptr += join.post.size; + *ptr = 0; + return(result); +#else + return str8_list_join_alloc(arena_allocator(arena), list, optional_params); +#endif } -internal String8Array -str8_array_reserve(Arena *arena, U64 count) +String8 +str8_list_join_alloc(AllocatorInfo ainfo, String8List* list, StringJoin* optional_params) { - String8Array arr; - arr.count = 0; - arr.v = push_array(arena, String8, count); - return arr; + StringJoin join = {0}; + if (optional_params != 0){ + MemoryCopyStruct(&join, optional_params); + } + + U64 sep_count = 0; + if (list->node_count > 0){ + sep_count = list->node_count - 1; + } + + String8 result; + result.size = join.pre.size + join.post.size + sep_count*join.sep.size + list->total_size; + U8* ptr = result.str = alloc_array_no_zero(ainfo, U8, result.size + 1); + + memory_copy(ptr, join.pre.str, join.pre.size); + ptr += join.pre.size; + for (String8Node *node = list->first; node != 0; node = node->next) + { + memory_copy(ptr, node->string.str, node->string.size); + ptr += node->string.size; + if (node->next != 0) { + memory_copy(ptr, join.sep.str, join.sep.size); + ptr += join.sep.size; + } + } + memory_copy(ptr, join.post.str, join.post.size); + ptr += join.post.size; + *ptr = 0; + return(result); } //////////////////////////////// //~ rjf: String Path Helpers -internal String8 -str8_chop_last_slash(String8 string){ - if (string.size > 0){ - U8 *ptr = string.str + string.size - 1; - for (;ptr >= string.str; ptr -= 1){ - if (*ptr == '/' || *ptr == '\\'){ - break; - } - } - if (ptr >= string.str){ - string.size = (U64)(ptr - string.str); - } - else{ - string.size = 0; - } - } - return(string); +String8 +str8_chop_last_slash(String8 string) { + if (string.size > 0) + { + U8* ptr = string.str + string.size - 1; + for (;ptr >= string.str; ptr -= 1) { + if (*ptr == '/' || *ptr == '\\') break; + } + if (ptr >= string.str) { + string.size = (U64)(ptr - string.str); + } + else { + string.size = 0; + } + } + return(string); } -internal String8 -str8_skip_last_slash(String8 string){ - if (string.size > 0){ - U8 *ptr = string.str + string.size - 1; - for (;ptr >= string.str; ptr -= 1){ - if (*ptr == '/' || *ptr == '\\'){ - break; - } - } - if (ptr >= string.str){ - ptr += 1; - string.size = (U64)(string.str + string.size - ptr); - string.str = ptr; - } - } - return(string); +String8 +str8_skip_last_slash(String8 string) { + if (string.size > 0) + { + U8* ptr = string.str + string.size - 1; + for (;ptr >= string.str; ptr -= 1) { + if (*ptr == '/' || *ptr == '\\') break; + } + if (ptr >= string.str) { + ptr += 1; + string.size = (U64)(string.str + string.size - ptr); + string.str = ptr; + } + } + return(string); } -internal String8 -str8_chop_last_dot(String8 string) +String8 +str8_chop_last_dot(String8 string) { + String8 result = string; + U64 p = string.size; + for (;p > 0;) { + p -= 1; + if (string.str[p] == '.') { + result = str8_prefix(string, p); + break; + } + } + return(result); +} + +String8 +str8_skip_last_dot(String8 string) { + String8 result = string; + U64 p = string.size; + for (;p > 0;) { + p -= 1; + if (string.str[p] == '.') { + result = str8_skip(string, p + 1); + break; + } + } + return(result); +} + +PathStyle +path_style_from_str8(String8 string) { + PathStyle result = PathStyle_Relative; + if (string.size >= 1 && string.str[0] == '/') { + result = PathStyle_UnixAbsolute; + } + else if (string.size >= 2 && char_is_alpha(string.str[0]) && string.str[1] == ':') + { + if (string.size == 2 || char_is_slash(string.str[2])) { + result = PathStyle_WindowsAbsolute; + } + } + return(result); +} + +void +str8_path_list_resolve_dots_in_place(String8List* path, PathStyle style) { - String8 result = string; - U64 p = string.size; - for (;p > 0;){ - p -= 1; - if (string.str[p] == '.'){ - result = str8_prefix(string, p); - break; - } - } - return(result); -} - -internal String8 -str8_skip_last_dot(String8 string){ - String8 result = string; - U64 p = string.size; - for (;p > 0;){ - p -= 1; - if (string.str[p] == '.'){ - result = str8_skip(string, p + 1); - break; - } - } - return(result); -} - -internal PathStyle -path_style_from_str8(String8 string){ - PathStyle result = PathStyle_Relative; - if (string.size >= 1 && string.str[0] == '/'){ - result = PathStyle_UnixAbsolute; - } - else if (string.size >= 2 && - char_is_alpha(string.str[0]) && - string.str[1] == ':'){ - if (string.size == 2 || - char_is_slash(string.str[2])){ - result = PathStyle_WindowsAbsolute; - } - } - return(result); -} - -internal String8List -str8_split_path(Arena *arena, String8 string){ - String8List result = str8_split(arena, string, (U8*)"/\\", 2, 0); - return(result); -} - -internal void -str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){ - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); + String8MetaNode* stack = 0; + String8MetaNode* free_meta_node = 0; + String8Node* first = path->first; - String8MetaNode *stack = 0; - String8MetaNode *free_meta_node = 0; - String8Node *first = path->first; - - MemoryZeroStruct(path); - for (String8Node *node = first, *next = 0; - node != 0; - node = next){ - // save next now - next = node->next; - - // cases: - if (node == first && style == PathStyle_WindowsAbsolute){ - goto save_without_stack; - } - if (node->string.size == 1 && node->string.str[0] == '.'){ - goto do_nothing; - } - if (node->string.size == 2 && node->string.str[0] == '.' && node->string.str[1] == '.'){ - if (stack != 0){ - goto eliminate_stack_top; - } - else{ - goto save_without_stack; - } - } - goto save_with_stack; - - - // handlers: - save_with_stack: - { - str8_list_push_node(path, node); - - String8MetaNode *stack_node = free_meta_node; - if (stack_node != 0){ - SLLStackPop(free_meta_node); - } - else{ - stack_node = push_array_no_zero(scratch.arena, String8MetaNode, 1); - } - SLLStackPush(stack, stack_node); - stack_node->node = node; - - continue; - } - - save_without_stack: - { - str8_list_push_node(path, node); - - continue; - } - - eliminate_stack_top: - { - path->node_count -= 1; - path->total_size -= stack->node->string.size; - - SLLStackPop(stack); - - if (stack == 0){ - path->last = path->first; - } - else{ - path->last = stack->node; - } - continue; - } - - do_nothing: continue; - } - scratch_end(scratch); + memory_zero_struct(path); + for (String8Node* node = first, *next = 0; node != 0; node = next) + { + // save next now + next = node->next; + + // cases: + if (node == first && style == PathStyle_WindowsAbsolute){ + goto save_without_stack; + } + + if (node->string.size == 1 && node->string.str[0] == '.') { + goto do_nothing; + } + if (node->string.size == 2 && node->string.str[0] == '.' && node->string.str[1] == '.') { + if (stack != 0) { + goto eliminate_stack_top; + } + else{ + goto save_without_stack; + } + } + goto save_with_stack; + + + // handlers: + save_with_stack: + { + str8_list_push_node(path, node); + + String8MetaNode *stack_node = free_meta_node; + if (stack_node != 0){ + sll_stack_pop(free_meta_node); + } + else{ + stack_node = push_array_no_zero(scratch.arena, String8MetaNode, 1); + } + sll_stack_push(stack, stack_node); + stack_node->node = node; + continue; + } + + save_without_stack: + { + str8_list_push_node(path, node); + continue; + } + + eliminate_stack_top: + { + path->node_count -= 1; + path->total_size -= stack->node->string.size; + + sll_stack_pop(stack); + if (stack == 0) { + path->last = path->first; + } + else { + path->last = stack->node; + } + continue; + } + do_nothing: continue; + } + scratch_end(scratch); } -internal String8 -str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){ - StringJoin params = {0}; - switch (style){ - case PathStyle_Relative: - case PathStyle_WindowsAbsolute: - { - params.sep = str8_lit("/"); - }break; - - case PathStyle_UnixAbsolute: - { - params.pre = str8_lit("/"); - params.sep = str8_lit("/"); - }break; - } - - String8 result = str8_list_join(arena, path, ¶ms); - return(result); +String8 +str8_path_list_join_by_style(Arena* arena, String8List* path, PathStyle style) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + StringJoin params = {0}; + switch (style) + { + case PathStyle_Relative: + case PathStyle_WindowsAbsolute: + { + params.sep = str8_lit("/"); + } + break; + + case PathStyle_UnixAbsolute: + { + params.pre = str8_lit("/"); + params.sep = str8_lit("/"); + } + break; + } + String8 result = str8_list_join(arena, path, ¶ms); + return(result); +#else + return str8_path_list_join_by_style_alloc(arena_allocator(arena), path, style); +#endif } -internal String8TxtPtPair -str8_txt_pt_pair_from_string(String8 string) -{ - String8TxtPtPair pair = {0}; - { - String8 file_part = {0}; - String8 line_part = {0}; - String8 col_part = {0}; - - // rjf: grab file part - for(U64 idx = 0; idx <= string.size; idx += 1) - { - U8 byte = (idx < string.size) ? (string.str[idx]) : 0; - U8 next_byte = ((idx+1 < string.size) ? (string.str[idx+1]) : 0); - if(byte == ':' && next_byte != '/' && next_byte != '\\') - { - file_part = str8_prefix(string, idx); - line_part = str8_skip(string, idx+1); - break; - } - else if(byte == 0) - { - file_part = string; - break; - } - } - - // rjf: grab line/column - { - U64 colon_pos = str8_find_needle(line_part, 0, str8_lit(":"), 0); - if(colon_pos < line_part.size) - { - col_part = str8_skip(line_part, colon_pos+1); - line_part = str8_prefix(line_part, colon_pos); - } - } - - // rjf: convert line/column strings to numerics - U64 line = 0; - U64 column = 0; - try_u64_from_str8_c_rules(line_part, &line); - try_u64_from_str8_c_rules(col_part, &column); - - // rjf: fill - pair.string = file_part; - pair.pt = txt_pt((S64)line, (S64)column); - if(pair.pt.line == 0) { pair.pt.line = 1; } - if(pair.pt.column == 0) { pair.pt.column = 1; } - } - return pair; +String8 +str8_path_list_join_by_style_alloc(AllocatorInfo ainfo, String8List* path, PathStyle style) { + StringJoin params = {0}; + switch (style) + { + case PathStyle_Relative: + case PathStyle_WindowsAbsolute: + { + params.sep = str8_lit("/"); + } + break; + + case PathStyle_UnixAbsolute: + { + params.pre = str8_lit("/"); + params.sep = str8_lit("/"); + } + break; + } + String8 result = str8_list_join_alloc(ainfo, path, ¶ms); + return(result); } //////////////////////////////// //~ rjf: UTF-8 & UTF-16 Decoding/Encoding read_only global U8 utf8_class[32] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, }; internal UnicodeDecode @@ -1873,3 +1857,4 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out) *block_out = str8_substr(string, range); return block_out->size; } + diff --git a/code/base/strings.h b/code/base/strings.h index 342b70c..f0b339a 100644 --- a/code/base/strings.h +++ b/code/base/strings.h @@ -505,45 +505,158 @@ str8_list_alloc_frontf(AllocatorInfo ainfo, String8List* list, char* fmt, ...) { //////////////////////////////// //~ rjf: String Splitting & Joining -String8List str8_split_arena(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags); +MD_API String8List str8_split (Arena* arena, String8 string, U8* split_chars, U64 split_char_count, StringSplitFlags flags); +MD_API String8List str8_split_alloc(AllocatorInfo ainfo, String8 string, U8* split_chars, U64 split_char_count, StringSplitFlags flags); -// Example pattern for general allocator variants +String8List str8_split_by_string_chars (Arena* arena, String8 string, String8 split_chars, StringSplitFlags flags); +String8List str8_split_by_string_chars_alloc (AllocatorInfo ainfo, String8 string, String8 split_chars, StringSplitFlags flags); +String8List str8_list_split_by_string_chars (Arena* arena, String8List list, String8 split_chars, StringSplitFlags flags); +String8List str8_list_split_by_string_chars_alloc(AllocatorInfo ainfo, String8List list, String8 split_chars, StringSplitFlags flags); -// String8List str8__split_ainfo(String8 string, U8* split_chars, U64 split_char_count, StringSplitFlags flags, AllocatorInfo allocator); -// #define str8_split_ainfo(string, split_chars, split_char_count, flags, ...) str8__split_ainfo(string, split_chars, split_char_count, flags, (AllocatorInfo){__VA_ARGS__}); +MD_API String8 str8_list_join (Arena* arena, String8List* list, StringJoin* optional_params); +MD_API String8 str8_list_join_alloc (AllocatorInfo ainfo, String8List* list, StringJoin* optional_params); + void str8_list_from_flags (Arena* arena, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count); + void str8_list_from_flags_alloc(AllocatorInfo ainfo, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count); -internal String8List str8_split_by_string_chars (Arena* arena, String8 string, String8 split_chars, StringSplitFlags flags); -internal String8List str8_list_split_by_string_chars(Arena* arena, String8List list, String8 split_chars, StringSplitFlags flags); -internal String8 str8_list_join (Arena* arena, String8List* list, StringJoin* optional_params); -internal void str8_list_from_flags (Arena* arena, String8List* list, U32 flags, String8 *flag_string_table, U32 flag_string_count); +inline String8List +str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); + return list; +#else + return str8_split_by_string_chars_alloc(arena_allocator(arena), string, split_chars, flags); +#endif +} + +inline String8List +str8_split_by_string_chars(AllocatorInfo ainfo, String8 string, String8 split_chars, StringSplitFlags flags) { + String8List list = str8_split_alloc(ainfo, string, split_chars.str, split_chars.size, flags); + return list; +} + +inline String8List +str8_list_split_by_string_chars(Arena* arena, String8List list, String8 split_chars, StringSplitFlags flags) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + String8List result = {0}; + for (String8Node *node = list.first; node != 0; node = node->next){ + String8List split = str8_split_by_string_chars(arena, node->string, split_chars, flags); + str8_list_concat_in_place(&result, &split); + } + return result; +#else + return str8_list_split_by_string_chars_alloc(arena_allocator(arena), list, split_chars, flags); +#endif +} + +inline String8List +str8_list_split_by_string_chars_alloc(AllocatorInfo ainfo, String8List list, String8 split_chars, StringSplitFlags flags) { + String8List result = {0}; + for (String8Node *node = list.first; node != 0; node = node->next){ + String8List split = str8_split_by_string_chars_alloc(ainfo, node->string, split_chars, flags); + str8_list_concat_in_place(&result, &split); + } + return result; +} + +void +str8_list_from_flags(Arena* arena, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + for (U32 i = 0; i < flag_string_count; i += 1) { + U32 flag = (1 << i); + if (flags & flag) { + str8_list_push(arena, list, flag_string_table[i]); + } + } +#else + return str8_list_from_flags_alloc(arena_allocator(arena), list, flags, flag_string_table, flag_string_count); +#endif +} + +void +str8_list_from_flags_alloc(AllocatorInfo ainfo, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count) { + for (U32 i = 0; i < flag_string_count; i += 1) { + U32 flag = (1 << i); + if (flags & flag) { + str8_list_alloc(ainfo, list, flag_string_table[i]); + } + } +} //////////////////////////////// //~ rjf; String Arrays -internal String8Array str8_array_from_list(Arena* arena, String8List* list); -internal String8Array str8_array_reserve (Arena* arena, U64 count); + +inline String8Array +str8_array_from_list(Arena* arena, String8List* list) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + String8Array array; + array.count = list->node_count; + array.v = push_array_no_zero(arena, String8, array.count); + U64 idx = 0; + for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) { + array.v[idx] = n->string; + } + return array; +#else + return str8_array_from_list_alloc(arena_allocator(arena), list); +#endif +} + +inline String8Array +str8_array_reserve(Arena *arena, U64 count) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + String8Array arr; + arr.count = 0; + arr.v = push_array(arena, String8, count); + return arr; +#else + return str8_array_reserve_alloc(arena_allocator(arena), count); +#endif +} + +inline String8Array +str8_array_from_list_alloc(AllocatorInfo ainfo, String8List* list) { + String8Array array; + array.count = list->node_count; + array.v = alloc_array_no_zero(ainfo, String8, array.count); + U64 idx = 0; + for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) { + array.v[idx] = n->string; + } + return array; +} + +inline String8Array +str8_array_reserve_alloc(AllocatorInfo ainfo, U64 count) { + String8Array arr; + arr.count = 0; + arr.v = alloc_array(ainfo, String8, count); + return arr; +} //////////////////////////////// //~ rjf: String Path Helpers -internal String8 str8_chop_last_slash(String8 string); -internal String8 str8_skip_last_slash(String8 string); -internal String8 str8_chop_last_dot (String8 string); -internal String8 str8_skip_last_dot (String8 string); +MD_API String8 str8_chop_last_slash(String8 string); +MD_API String8 str8_skip_last_slash(String8 string); +MD_API String8 str8_chop_last_dot (String8 string); +MD_API String8 str8_skip_last_dot (String8 string); -internal PathStyle path_style_from_str8 (String8 string); -internal String8List str8_split_path (Arena* arena, String8 string); -internal void str8_path_list_resolve_dots_in_place(String8List* path, PathStyle style); -internal String8 str8_path_list_join_by_style (Arena* arena, String8List* path, PathStyle style); +inline String8List str8_split_path(Arena* arena, String8 string) { String8List result = str8_split(arena, string, (U8*)"/\\", 2, 0); return(result); } + +MD_API PathStyle path_style_from_str8 (String8 string); +MD_API void str8_path_list_resolve_dots_in_place( String8List* path, PathStyle style); +MD_API String8 str8_path_list_join_by_style (Arena* arena, String8List* path, PathStyle style); +MD_API String8 str8_path_list_join_by_style_alloc (AllocatorInfo ainfo, String8List* path, PathStyle style); //////////////////////////////// //~ rjf: UTF-8 & UTF-16 Decoding/Encoding -internal UnicodeDecode utf8_decode (U8* str, U64 max); -internal UnicodeDecode utf16_decode (U16* str, U64 max); -internal U32 utf8_encode (U8* str, U32 codepoint); -internal U32 utf16_encode (U16* str, U32 codepoint); -internal U32 utf8_from_utf32_single(U8* buffer, U32 character); +UnicodeDecode utf8_decode (U8* str, U64 max); +UnicodeDecode utf16_decode (U16* str, U64 max); +U32 utf8_encode (U8* str, U32 codepoint); +U32 utf16_encode (U16* str, U32 codepoint); +U32 utf8_from_utf32_single(U8* buffer, U32 character); //////////////////////////////// //~ rjf: Unicode String Conversions @@ -619,40 +732,3 @@ internal U64 str8_deserial_read_block (String8 string, U64 off #define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)) * (count), sizeof( *(ptr))) #define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof( *(ptr))) - -//////////////////////////////// -//~ rjf: Text 2D Coordinates & Ranges - -typedef struct TxtPt TxtPt; -struct TxtPt -{ - S64 line; - S64 column; -}; - -typedef struct TxtRng TxtRng; -struct TxtRng -{ - TxtPt min; - TxtPt max; -}; - -//////////////////////////////// -//~ rjf: String Pair Types - -typedef struct String8TxtPtPair String8TxtPtPair; -struct String8TxtPtPair -{ - String8 string; - TxtPt pt; -}; - -//////////////////////////////// -//~ rjf: Text Path Helpers - -String8TxtPtPair str8_txt_pt_pair_from_string(String8 string); - -//////////////////////////////// -//~ rjf: Text Wrapping - -String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent); diff --git a/code/base/text.c b/code/base/text.c new file mode 100644 index 0000000..0086f4e --- /dev/null +++ b/code/base/text.c @@ -0,0 +1,156 @@ +#ifdef INTELLISENSE_DIRECTIVES +# include "text.h" +#endif + +//////////////////////////////// +//~ rjf: Text 2D Coordinate/Range Functions + +internal TxtPt +txt_pt(S64 line, S64 column) +{ + TxtPt p = {0}; + p.line = line; + p.column = column; + return p; +} + +internal B32 +txt_pt_match(TxtPt a, TxtPt b) +{ + return a.line == b.line && a.column == b.column; +} + +internal B32 +txt_pt_less_than(TxtPt a, TxtPt b) +{ + B32 result = 0; + if(a.line < b.line) + { + result = 1; + } + else if(a.line == b.line) + { + result = a.column < b.column; + } + return result; +} + +internal TxtPt +txt_pt_min(TxtPt a, TxtPt b) +{ + TxtPt result = b; + if(txt_pt_less_than(a, b)) + { + result = a; + } + return result; +} + +internal TxtPt +txt_pt_max(TxtPt a, TxtPt b) +{ + TxtPt result = a; + if(txt_pt_less_than(a, b)) + { + result = b; + } + return result; +} + +internal TxtRng +txt_rng(TxtPt min, TxtPt max) +{ + TxtRng range = {0}; + if(txt_pt_less_than(min, max)) + { + range.min = min; + range.max = max; + } + else + { + range.min = max; + range.max = min; + } + return range; +} + +internal TxtRng +txt_rng_intersect(TxtRng a, TxtRng b) +{ + TxtRng result = {0}; + result.min = txt_pt_max(a.min, b.min); + result.max = txt_pt_min(a.max, b.max); + if(txt_pt_less_than(result.max, result.min)) + { + MemoryZeroStruct(&result); + } + return result; +} + +internal TxtRng +txt_rng_union(TxtRng a, TxtRng b) +{ + TxtRng result = {0}; + result.min = txt_pt_min(a.min, b.min); + result.max = txt_pt_max(a.max, b.max); + return result; +} + +internal B32 +txt_rng_contains(TxtRng r, TxtPt pt) +{ + B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) && + txt_pt_less_than(pt, r.max)); + return result; +} + +//////////////////////////////// +//~ rjf: Text Path Helpers + +internal String8TxtPtPair +str8_txt_pt_pair_from_string(String8 string) +{ + String8TxtPtPair pair = {0}; + { + String8 file_part = {0}; + String8 line_part = {0}; + String8 col_part = {0}; + + // rjf: grab file part + for(U64 idx = 0; idx <= string.size; idx += 1) + { + U8 byte = (idx < string.size) ? (string.str[idx ]) : 0; + U8 next_byte = ((idx + 1 < string.size) ? (string.str[idx + 1]) : 0); + if(byte == ':' && next_byte != '/' && next_byte != '\\') { + file_part = str8_prefix(string, idx); + line_part = str8_skip(string, idx+1); + break; + } + else if(byte == 0) { + file_part = string; + break; + } + } + // rjf: grab line/column + { + U64 colon_pos = str8_find_needle(line_part, 0, str8_lit(":"), 0); + if(colon_pos < line_part.size) { + col_part = str8_skip (line_part, colon_pos + 1); + line_part = str8_prefix(line_part, colon_pos); + } + } + + // rjf: convert line/column strings to numerics + U64 line = 0; + U64 column = 0; + try_u64_from_str8_c_rules(line_part, &line); + try_u64_from_str8_c_rules(col_part, &column); + + // rjf: fill + pair.string = file_part; + pair.pt = txt_pt((S64)line, (S64)column); + if(pair.pt.line == 0) { pair.pt.line = 1; } + if(pair.pt.column == 0) { pair.pt.column = 1; } + } + return pair; +} diff --git a/code/base/text.h b/code/base/text.h new file mode 100644 index 0000000..5a77923 --- /dev/null +++ b/code/base/text.h @@ -0,0 +1,54 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "strings.h" +#endif + +//////////////////////////////// +//~ rjf: Text 2D Coordinates & Ranges + +typedef struct TxtPt TxtPt; +struct TxtPt +{ + S64 line; + S64 column; +}; + +typedef struct TxtRng TxtRng; +struct TxtRng +{ + TxtPt min; + TxtPt max; +}; + +//////////////////////////////// +//~ rjf: String Pair Types + +typedef struct String8TxtPtPair String8TxtPtPair; +struct String8TxtPtPair +{ + String8 string; + TxtPt pt; +}; + +//////////////////////////////// +//~ rjf: Text Path Helpers + +MD_API String8TxtPtPair str8_txt_pt_pair_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Text 2D Coordinate/Range Functions + +TxtPt txt_pt(S64 line, S64 column); +B32 txt_pt_match(TxtPt a, TxtPt b); +B32 txt_pt_less_than(TxtPt a, TxtPt b); +TxtPt txt_pt_min(TxtPt a, TxtPt b); +TxtPt txt_pt_max(TxtPt a, TxtPt b); +TxtRng txt_rng(TxtPt min, TxtPt max); +TxtRng txt_rng_intersect(TxtRng a, TxtRng b); +TxtRng txt_rng_union(TxtRng a, TxtRng b); +B32 txt_rng_contains(TxtRng r, TxtPt pt); + +//////////////////////////////// +//~ rjf: Text Wrapping + +String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);