Str8 Str8_Wrap(S64 count, U8 *data) { Str8 result; result.data = data; result.count = count; return result; } Str8 Str8_WrapRange(U8 *start, U8 *end) { Str8 result; result.data = start; result.count = cast(S64) (end - start); return result; } internal S64 Str8_CountZ(U8 *data) { S64 result = 0; while (data[result] != 0) { result += 1; } return result; } Str8 Str8_WrapZ(U8 *data) { Str8 result; result.data = data; result.count = Str8_CountZ(data); return result; } #define FNV_OFFSET_BIAS ((U64) 0xCBF29CE484222325) #define FNV_PRIME ((U64) 0x100000001B3) U64 Str8_Hash(Str8 v) { U64 result = FNV_OFFSET_BIAS; for (S64 it = 0; it < v.count; ++it) { result ^= v.data[it]; result *= FNV_PRIME; } return result; } Str8 Str8_Copy(M_Arena *arena, Str8 s) { Str8 result; result.count = s.count; result.data = M_ArenaPush(arena, U8, .count = s.count + 1); M_CopySize(result.data, s.data, s.count); return result; } Str8 Str8_Format(M_Arena *arena, const char *format, ...) { va_list args; va_start(args, format); Str8 result = Str8_FormatArgs(arena, format, args); va_end(args); return result; } internal S64 Str8_ProcessFormat(Str8 out, const char *format, va_list args) { S64 result = vsnprintf((char *) out.data, (int) out.count, format, args); return result; } Str8 Str8_FormatArgs(M_Arena *arena, const char *format, va_list args) { Str8 result; va_list copy; va_copy(copy, args); U64 offset = M_ArenaOffset(arena); result.count = KB(1); result.data = M_ArenaPush(arena, U8, .count = result.count); S64 needed = Str8_ProcessFormat(result, format, args); if (needed >= result.count) { M_ArenaPop(arena, offset); result.count = needed; result.data = M_ArenaPush(arena, U8, .count = result.count + 1); Str8_ProcessFormat(result, format, copy); } else { U64 size = result.count - needed - 1; M_ArenaPopSize(arena, size); result.count = needed; } return result; } B32 Str8_Equal(Str8 a, Str8 b, Str8_EqualFlags flags) { B32 result = (a.count == b.count); if (result) { B32 ignore_case = (flags & STR8_EQUAL_IGNORE_CASE) != 0; for (S64 it = 0; it < a.count; ++it) { U8 ac = ignore_case ? Chr_ToLowercase(a.data[it]) : a.data[it]; U8 bc = ignore_case ? Chr_ToLowercase(b.data[it]) : b.data[it]; if (ac != bc) { result = false; break; } } } return result; } Str8 Str8_Prefix(Str8 s, S64 count) { Str8 result; result.data = s.data; result.count = Min(s.count, count); return result; } Str8 Str8_Suffix(Str8 s, S64 count) { Str8 result; result.count = Min(s.count, count); result.data = s.data + (s.count - result.count); return result; } Str8 Str8_RemoveAfterLast(Str8 s, U8 c) { Str8 result; result.data = s.data; result.count = s.count; for (S64 it = s.count - 1; it >= 0; --it) { if (result.data[it] == c) { result.count = it; break; } } return result; } B32 Str8_EndsWith(Str8 s, Str8 suffix) { B32 result = Str8_Equal(Str8_Suffix(s, suffix.count), suffix, 0); return result; } U8 Chr_ToUppercase(U8 c) { U8 result = (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c; return result; } U8 Chr_ToLowercase(U8 c) { U8 result = (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c; return result; }