434 lines
9.1 KiB
C++
434 lines
9.1 KiB
C++
|
#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, 1)) / 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);
|
||
|
}
|