248 lines
4.4 KiB
C
248 lines
4.4 KiB
C
/* 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
|