/* date = May 7th 2023 9:01 pm */ #ifndef VN_STRING_H #define VN_STRING_H inline b32 IsWhitespace(char C) { b32 Result = ((C == ' ') || (C == '\n') || (C == '\t') || (C == '\r')); return(Result); } inline s64 StringLength(char *String) { s64 Result = 0; while(*String++) { ++Result; } return(Result); } inline u64 HashString(string String) { u64 Result = 5731; for(s64 Index = 0; Index < String.Count; ++Index) { Result += String.Data[Index]; Result ^= Result << 13; Result ^= Result >> 7; Result ^= Result << 17; } return(Result); } inline string MakeStringFromCString(char *Data) { string Result = {StringLength(Data), (u8 *)Data}; return(Result); } inline b32 AreEqual(string A, string B) { b32 Result = false; if(A.Count == B.Count) { Result = true; for(s64 Index = 0; Index < A.Count; ++Index) { if(A.Data[Index] != B.Data[Index]) { Result = false; break; } } } return(Result); } inline s64 FirstIndexOf(string String, char Char) { s64 Result = -1; for(s64 Index = 0; Index < String.Count; ++Index) { if(String.Data[Index] == Char) { Result = Index; break; } } return(Result); } inline s64 LastIndexOf(string String, char Char) { s64 Result = -1; for(s64 Index = String.Count-1; Index >= 0; --Index) { if(String.Data[Index] == Char) { Result = Index; break; } } return(Result); } inline s64 LastIndexOf(string String, string Substring) { s64 Result = -1; if(String.Count >= Substring.Count) { for(s64 Index = String.Count-Substring.Count; Index >= 0; --Index) { string ToCheck = MakeString((char *)String.Data + Index, Substring.Count); if(AreEqual(ToCheck, Substring)) { Result = Index; break; } } } return(Result); } static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint) { s64 Length = 0; if(Codepoint <= 0x7F) { Out[0] = (u8)Codepoint; Length = 1; } else if(Codepoint <= 0x7FF) { Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F); Out[1] = 0x80 | ( Codepoint & 0x3F); Length = 2; } else if(Codepoint <= 0xFFFF) { Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F); Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F); Out[2] = 0x80 | ( Codepoint & 0x3F); Length = 3; } else if(Codepoint <= 0x10FFFF) { Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07); Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F); Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F); Out[3] = 0x80 | ( Codepoint & 0x3F); Length = 4; } else { Out[0] = '?'; Length = 1; } return(Length); } inline s64 GetCodepointSize(u32 Codepoint) { s64 Result = 0; if(Codepoint <= 0x7F) { Result = 1; } else if(Codepoint <= 0x7FF) { Result = 2; } else if(Codepoint <= 0xFFFF) { Result = 3; } else if(Codepoint <= 0x10FFFF) { Result = 4; } else { Result = 1; } return(Result); } // sixten(TODO): Remove this forward decl. inline string PushCString(struct memory_arena *Arena, char *CString); inline string StringFromCodepoint(struct memory_arena *Arena, u32 Codepoint) { char Buffer[5] = {}; UTF8FromCodepoint((u8 *)Buffer, Codepoint); string Result = PushCString(Arena, Buffer); return(Result); } struct utf8_iterator { string Data; s64 Index; u32 Codepoint; }; inline void Advance(utf8_iterator *Iter) { u8 *At = Iter->Data.Data + Iter->Index; if(Iter->Index < Iter->Data.Count) { if((At[0] & 0x80) == 0x00) { Iter->Codepoint = (At[0] & 0x7F); Iter->Index += 1; } else if((At[0] & 0xE0) == 0xC0) { Iter->Codepoint = ((At[0] & 0x1F) << 6)|(At[1] & 0x3F); Iter->Index += 2; } else if((At[0] & 0xF0) == 0xE0) { Iter->Codepoint = ((At[0] & 0x0F) << 12)|((At[1] & 0x3F) << 6)|(At[2] & 0x3F); Iter->Index += 3; } else if((Iter->Data.Data[Iter->Index] & 0xF8) == 0xF0) { Iter->Codepoint = ((At[0] & 0x0F) << 18)|((At[1] & 0x3F) << 12)|((At[2] & 0x3F) << 6)|(At[3] & 0x3F); Iter->Index += 4; } } else { Iter->Codepoint = 0; } } inline utf8_iterator IterateUTF8String(string String) { utf8_iterator Iter = {}; Iter.Data = String; Advance(&Iter); return(Iter); } #endif //VN_STRING_H