#include "string.h" Str str_empty(void) { static const U8 empty_; static const Str str = {(U8 *)&empty_, 0}; return str; } Str str_slice(Str str, U32 start, U32 len) { Assert(start <= str.len); Assert(len <= str.len - start); Str new_str = str_create(&str.str[start], len); return new_str; } Str str_concat(Allocator *alloc, Str first, Str second) { Str str; Assert(first.len <= U32_Max - second.len); 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, str.len, 1); MemCopy(mem, str.str, str.len); return str_create(mem, str.len); } static INLINE bool char_is_ascii_whitespace(U8 byte) { return byte == ' ' || byte == '\t' || byte == '\v' || byte == '\f' || byte == '\r' || byte == '\n'; } Str str_ascii_trim_left(Str str) { U8 *start = str.str; U8 *end = str.str + str.len; while (start != end) { if (!char_is_ascii_whitespace(*start)) { break; } start++; } return str_create(start, (U32)(end - start)); } Str str_ascii_trim_right(Str str) { U8 *start = str.str; U8 *end = str.str + str.len; while (start != end) { if (!char_is_ascii_whitespace(*(end - 1))) { break; } end--; } return str_create(start, (U32)(end - start)); } Str str_ascii_trim(Str str) { Str new_str = str_ascii_trim_left(str); new_str = str_ascii_trim_right(new_str); return new_str; } S64 str_index(Str haystack, Str needle) { if (needle.len == 0) { return 0; } if (needle.len == 1) { return str_find_byte(haystack, needle.str[0]); } if (needle.len > haystack.len) { return -1; } U8 *found = MemFind(haystack.str, haystack.len, needle.str, needle.len); if (found != NULL) { return (S64)(found - haystack.str); } return -1; } // 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_slice(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_slice(str, start_pos, str.len - start_pos); vec->strings[vec->len] = sub_str; vec->len++; } } Str str_join(Allocator *allocator, StrVec strings, Str separator) { U32 joined_str_len = 0; for (U32 i = 0; i < strings.len; i++) { U32 part_len = strings.strings[i].len; Assert(joined_str_len <= U32_Max - part_len); // overflow joined_str_len += part_len; } if (strings.len > 1) { U32 separator_count = strings.len - 1; Assert(separator.len <= U32_Max / separator_count); // overflow Assert(joined_str_len <= U32_Max - separator.len * separator_count); // overflow joined_str_len += separator.len * separator_count; } U8 *joined_str = allocator_push(allocator, joined_str_len, 1); if (strings.len > 0) { U32 pos = 0; Str *str = &strings.strings[0]; MemCopy(&joined_str[pos], str->str, str->len); pos += str->len; for (U32 i = 1; i < strings.len; i++) { str = &strings.strings[i]; MemCopy(&joined_str[pos], separator.str, separator.len); pos += separator.len; MemCopy(&joined_str[pos], str->str, str->len); pos += str->len; } } return str_create(joined_str, joined_str_len); }