#define STB_SPRINTF_IMPLEMENTATION #include "third_party/stb_sprintf.h" //~ sixten: Char funcitons inline b32 IsWhitespace(char C) { b32 Result = ((C == ' ') || (C == '\n') || (C == '\t') || (C == '\r')); return(Result); } inline b32 IsDigit(char C) { b32 Result = ((C >= '0') && (C <= '9')); return(Result); } inline b32 IsLetter(char C) { b32 Result = ((C >= 'A') && (C <= 'Z')) || ((C >= 'a') && (C <= 'z')); return(Result); } //~ sixten: String functions //- sixten: Basic constructors inline string MakeString(u8 *Data, s64 Count) { string Result = {Count, Data}; return(Result); } inline string MakeString(char *CString) { string Result = {StringLength(CString), (u8 *)CString}; return(Result); } //- sixten: Equality static 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); } //- sixten: Substring static string Substring(string String, range1_s64 Range) { string Result = MakeString(String.Data + Range.Min, DimOfRange(Range)); return(Result); } static string Prefix(string String, s64 Count) { range1_s64 Range = Range1S64(0, Count); string Result = Substring(String, Range); return(Result); } static string Suffix(string String, s64 Count) { range1_s64 Range = Range1S64(String.Count - Count, String.Count); string Result = Substring(String, Range); return(Result); } //- sixten: Hashing static 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); } //- sixten: Searching static 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); } static 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); } static s64 FirstIndexOf(string String, string Sub) { s64 Result = -1; if(String.Count >= Sub.Count) { for(s64 Index = 0; Index < String.Count - Sub.Count; ++Index) { string ToCheck = Substring(String, Range1S64(Index, Index + Sub.Count)); if(AreEqual(ToCheck, Sub)) { Result = Index; break; } } } return(Result); } static s64 LastIndexOf(string String, string Sub) { s64 Result = -1; if(String.Count >= Sub.Count) { for(s64 Index = String.Count - Sub.Count - 1; Index >= 0; --Index) { string ToCheck = Substring(String, Range1S64(Index, Index + Sub.Count)); if(AreEqual(ToCheck, Sub)) { Result = Index; break; } } } return(Result); } //- sixten: Allocation static string PushString(memory_arena *Arena, string String) { string Result; Result.Data = PushArray(Arena, u8, String.Count, NoClear()); Result.Count = String.Count; Copy(Result.Data, String.Data, String.Count); return(Result); } static string PushFormatVariadic(memory_arena *Arena, char *Format, va_list Arguments) { va_list ArgumentsCopy; va_copy(ArgumentsCopy, Arguments); string Result; Result.Count = stbsp_vsnprintf(0, 0, Format, ArgumentsCopy); Result.Data = PushArray(Arena, u8, Result.Count + 1, NoClear()); Result.Data[Result.Count] = 0; stbsp_vsnprintf((char *)Result.Data, (s32)Result.Count + 1, Format, Arguments); return(Result); } static string PushFormat(memory_arena *Arena, char *Format, ...) { va_list Arguments; va_start(Arguments, Format); string Result = PushFormatVariadic(Arena, Format, Arguments); va_end(Arguments); return(Result); } static string PushCString(memory_arena *Arena, char *CString) { string String = MakeString(CString); string Result = PushString(Arena, String); return(Result); } //- sixten: Conversion static s64 ConvertStringToS64(string String) { s64 Result = 0; b32 IsNegative = false; s64 Index = 0; if(String.Data[Index] == '-') { IsNegative = true; ++Index; } for(;Index < String.Count; ++Index) { u8 Char = String.Data[Index]; Assert(IsDigit(Char)); Result = Result*10 + (Char-'0'); } if(IsNegative) { Result = -Result;; } return(Result); } static string ConvertS64ToString(memory_arena *Arena, s64 Value) { b32 IsNegative = (Value < 0); if(IsNegative) { Value = -Value; } s64 DigitCount = (s64)Floor(Log(Max(Value, 1LL)) / Log(10)) + 1; s64 TotalBufferCount = DigitCount + IsNegative; string String = {TotalBufferCount, PushArray(Arena, u8, TotalBufferCount + 1)}; String.Data[TotalBufferCount] = 0; if(IsNegative) { String.Data[0] = '-'; } for(s64 Index = 0; Index < DigitCount; ++Index) { String.Data[TotalBufferCount - 1 - Index] = '0' + (Value % 10); Value /= 10; } return(String); } static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint) { char Buffer[5] = {}; UTF8FromCodepoint((u8 *)Buffer, Codepoint); string Result = PushCString(Arena, Buffer); return(Result); } //- sixten: "C Style" strings static s64 StringLength(char *String) { s64 Result = 0; while(*String++) { ++Result; } return(Result); } //~ sixten: String list static void AppendString(string_list *List, string String, memory_arena *Arena) { string_node *Node = PushStruct(Arena, string_node); Node->String = String; List->TotalCount += String.Count; DLLInsertLast(List->First, List->Last, Node); } static string JoinStringList(string_list *List, memory_arena *Arena) { u8 *Buffer = PushArray(Arena, u8, List->TotalCount + 1); Buffer[List->TotalCount] = 0; s64 GlobalIndex = 0; for(string_node *Node = List->First; Node != 0; Node = Node->Next) { string String = Node->String; for(s64 Index = 0; Index < String.Count; ++Index) { Buffer[GlobalIndex++] = String.Data[Index]; } } string Result = MakeString(Buffer, List->TotalCount); return(Result); } //~ sixten: Unicode static utf8_iterator IterateUTF8String(string String) { utf8_iterator Iter = {}; Iter.Data = String; Advance(&Iter); return(Iter); } static 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; } } static b32 IsValid(utf8_iterator *Iter) { b32 Result = (Iter->Codepoint != 0); 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); }