#pragma once struct String { char *data; int64_t len; String() = default; String(char *s) : data(s), len(strlen(s)) {} String(char *s, int64_t l) : data((char *)s), len(l) {} String(const char *s) : data((char *)s), len(strlen((char *)s)) {} String(const char *s, int64_t l) : data((char *)s), len(l) {} char &operator[](int64_t index) { Assert(index < len); return data[index]; } char *begin() { return data; } char *end() { return data + len; } struct ReverseIter { char *data; String *arr; ReverseIter operator++(int) { ReverseIter ret = *this; data -= 1; return ret; } ReverseIter &operator++() { data -= 1; return *this; } char &operator*() { return data[0]; } char *operator->() { return data; } friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; }; friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; }; ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; } ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; } }; ReverseIter reverse() { return {this->end() - 1, this}; } }; API char ToLowerCase(char a); API char ToUpperCase(char a); API bool IsWhitespace(char w); API bool IsAlphabetic(char a); API bool IsIdent(char a); API bool IsDigit(char a); API bool IsAlphanumeric(char a); API bool IsSymbol(char w); API bool IsNonWord(char w); API bool IsWord(char w); API bool IsBrace(char c); API bool IsParen(char c); API bool EndsWith(String a, String end, unsigned ignore_case = false); API bool StartsWith(String a, String start, unsigned ignore_case = false); API bool AreEqual(String a, String b, unsigned ignore_case = false); inline bool operator==(String a, String b) { return AreEqual(a, b); } inline bool operator!=(String a, String b) { return !AreEqual(a, b); } API String Trim(String string); API String TrimEnd(String string); API String Chop(String a, int64_t len); API String Skip(String a, int64_t len); API String GetPostfix(String a, int64_t len); API String GetPrefix(String a, int64_t len); API String GetSlice(String arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST); API String CutLastSlash(String *s); API String ChopLastSlash(String s); API String ChopLastPeriod(String s); API String SkipToLastSlash(String s); API String SkipToLastPeriod(String s); API String CutPrefix(String *string, int64_t len); API String CutPostfix(String *string, int64_t len); API String Copy(Allocator allocator, String string); API String Copy(Allocator allocator, char *string); API void NormalizePathInPlace(String s); API String NormalizePath(Allocator allocator, String s); API String FormatV(Allocator allocator, const char *data, va_list args1); API String Format(Allocator allocator, const char *data, ...); #define STRING_FORMAT(allocator, data, result) \ va_list args1; \ va_start(args1, data); \ String result = FormatV(allocator, data, args1); \ va_end(args1) typedef int SeekFlag; enum { SeekFlag_None = 0, SeekFlag_IgnoreCase = 1, SeekFlag_MatchFindLast = 2, }; API bool Seek(String string, String find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None); API Array Split(Allocator allocator, String string, String delimiter = " "); API String Merge(Allocator allocator, Array list, String separator); API Int GetSize(Array array);