2024-03-19 02:33:57 +02:00

718 lines
16 KiB
Plaintext

/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
#include <convert.h>
#include <debug.h>
// Show debug messages
// #define DEBUG_CPP_STRING 1
// #define DEBUG_CPP_STRING_VERBOSE 1
#ifdef DEBUG_CPP_STRING
#define strdbg(m, ...) debug(m, ##__VA_ARGS__)
#else
#define strdbg(m, ...)
#endif
#ifdef DEBUG_CPP_STRING_VERBOSE
#define v_strdbg(m, ...) debug(m, ##__VA_ARGS__)
#else
#define v_strdbg(m, ...)
#endif
// TODO: Somewhere the delete is called twice, causing a double free error.
namespace std
{
template <typename T>
char *to_string(T value)
{
static char buffer[1024];
bool isNegative = false;
int index = 0;
if (value < 0)
{
isNegative = true;
value = -value;
}
if (value == 0)
buffer[index++] = '0';
else
{
while (value > 0)
{
buffer[index++] = (char)(48 /*'0'*/ + (value % 10));
value /= 10;
}
}
if (isNegative)
buffer[index++] = '-';
int start = isNegative ? 1 : 0;
int end = index - 1;
while (start < end)
{
char temp = buffer[start];
buffer[start] = buffer[end];
buffer[end] = temp;
start++;
end--;
}
buffer[index] = '\0';
return buffer;
}
/**
* @brief Basic string class
* String class that can be used to store strings.
*/
class basic_string
{
private:
char *Data{};
size_t Length{};
size_t Capacity{};
public:
static const size_t npos = -1;
basic_string(const char *Str = "")
{
this->Length = strlen(Str);
this->Capacity = this->Length + 1;
this->Data = new char[this->Capacity];
strcpy(this->Data, Str);
strdbg("%#lx: New basic_string created: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
~basic_string()
{
strdbg("%#lx: String deleted: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
delete[] this->Data, this->Data = nullptr;
}
size_t length()
{
v_strdbg("%#lx: String length: %d",
this, this->Length);
return this->Length;
}
size_t capacity()
{
v_strdbg("%#lx: String capacity: %d",
this, this->Capacity);
return this->Capacity;
}
const char *c_str() const
{
v_strdbg("%#lx: String data: \"%s\"",
this, this->Data);
return this->Data;
}
void resize(size_t NewLength)
{
strdbg("%#lx: String resize: %d",
this, NewLength);
if (NewLength < this->Capacity)
{
this->Length = NewLength;
this->Data[this->Length] = '\0';
strdbg("%#lx: String resized: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return;
}
size_t newCapacity = NewLength + 1;
char *newData = new char[newCapacity];
strcpy(newData, this->Data);
strdbg("%#lx: old: %#lx, new: %#lx",
this, this->Data, newData);
delete[] this->Data;
this->Data = newData;
this->Length = NewLength;
this->Capacity = newCapacity;
strdbg("%#lx: String resized: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
void concat(const basic_string &Other)
{
size_t NewLength = this->Length + Other.Length;
this->resize(NewLength);
strcat(this->Data, Other.Data);
strdbg("%#lx: String concatenated: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
bool empty()
{
strdbg("%#lx: String empty: %d",
this, this->Length == 0);
return this->Length == 0;
}
size_t size()
{
strdbg("%#lx: String size: %d",
this, this->Length);
return this->Length;
}
void clear()
{
strdbg("%#lx: String clear", this);
this->resize(0);
}
size_t find(const char *Str, size_t Pos = 0) const
{
strdbg("%#lx: String find: \"%s\", %d",
this, Str, Pos);
if (Pos >= this->Length)
return npos;
for (size_t i = Pos; i < this->Length; i++)
{
bool found = true;
for (size_t j = 0; Str[j] != '\0'; j++)
{
if (this->Data[i + j] != Str[j])
{
found = false;
break;
}
}
if (found)
return i;
}
return npos;
}
size_t find(const basic_string &Str, size_t Pos = 0) const
{
strdbg("%#lx: String find: \"%s\", %d",
this, Str.c_str(), Pos);
return this->find(Str.c_str(), Pos);
}
void erase(int Index, int Count = 1)
{
strdbg("%#lx: String erase: %d, %d",
this, Index, Count);
if (Index < 0 || (size_t)Index >= this->Length)
return;
if (Count < 0)
return;
if ((size_t)(Index + Count) > this->Length)
Count = (int)this->Length - Index;
for (size_t i = Index; i < this->Length - Count; i++)
this->Data[i] = this->Data[i + Count];
this->Length -= Count;
this->Data[this->Length] = '\0';
strdbg("%#lx: String erased: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
size_t find_last_not_of(const char *Str, size_t Pos = npos) const
{
strdbg("%#lx: String find_last_not_of: \"%s\", %d",
this, Str, Pos);
if (Pos == npos)
Pos = this->Length - 1;
for (int i = (int)Pos; i >= 0; i--)
{
bool found = false;
for (size_t j = 0; Str[j] != '\0'; j++)
{
if (this->Data[i] == Str[j])
{
found = true;
break;
}
}
if (!found)
return i;
}
return npos;
}
size_t find_first_not_of(const char *Str, size_t Pos = 0) const
{
strdbg("%#lx: String find_first_not_of: \"%s\", %d",
this, Str, Pos);
if (Pos >= this->Length)
return npos;
for (size_t i = Pos; i < this->Length; i++)
{
bool found = false;
for (size_t j = 0; Str[j] != '\0'; j++)
{
if (this->Data[i] == Str[j])
{
found = true;
break;
}
}
if (!found)
return i;
}
return npos;
}
size_t find_first_of(const char *Str, size_t Pos = 0) const
{
strdbg("%#lx: String find_first_of: \"%s\", %d",
this, Str, Pos);
if (Pos >= this->Length)
return npos;
for (size_t i = Pos; i < this->Length; i++)
{
bool found = false;
for (size_t j = 0; Str[j] != '\0'; j++)
{
if (this->Data[i] == Str[j])
{
found = true;
break;
}
}
if (found)
return i;
}
return npos;
}
size_t find_last_of(const char *Str, size_t Pos = npos) const
{
strdbg("%#lx: String find_last_of: \"%s\", %d",
this, Str, Pos);
if (Pos == npos)
Pos = this->Length - 1;
for (int i = (int)Pos; i >= 0; i--)
{
bool found = false;
for (int j = 0; Str[j] != '\0'; j++)
{
if (this->Data[i] == Str[j])
{
found = true;
break;
}
}
if (found)
return i;
}
return npos;
}
size_t find_first_of(char C, size_t Pos = 0) const
{
strdbg("%#lx: String find_first_of: '%c', %d",
this, C, Pos);
if (Pos >= this->Length)
return npos;
for (size_t i = Pos; i < this->Length; i++)
{
if (this->Data[i] == C)
return i;
}
return npos;
}
size_t find_last_of(char C, size_t Pos = npos) const
{
strdbg("%#lx: String find_last_of: '%c', %d",
this, C, Pos);
if (Pos == npos)
Pos = this->Length - 1;
for (int i = (int)Pos; i >= 0; i--)
{
if (this->Data[i] == C)
return i;
}
return npos;
}
size_t substr(const char *Str, size_t Pos = 0) const
{
strdbg("%#lx: String substr: \"%s\", %d",
this, Str, Pos);
if (Pos >= this->Length)
return npos;
for (size_t i = Pos; i < this->Length; i++)
{
bool found = true;
for (size_t j = 0; Str[j] != '\0'; j++)
{
if (this->Data[i + j] != Str[j])
{
found = false;
break;
}
}
if (found)
return i;
}
return npos;
}
size_t substr(const basic_string &Str, size_t Pos = 0) const
{
strdbg("%#lx: String substr: \"%s\", %d",
this, Str.c_str(), Pos);
return this->substr(Str.c_str(), Pos);
}
basic_string substr(size_t Pos = 0, size_t Count = npos) const
{
strdbg("%#lx: String substr: %d, %d",
this, Pos, Count);
if (Pos >= this->Length)
return basic_string();
if (Count == npos)
Count = this->Length - Pos;
if (Pos + Count > this->Length)
Count = this->Length - Pos;
basic_string ret;
ret.resize(Count);
for (size_t i = 0; i < Count; i++)
ret.Data[i] = this->Data[Pos + i];
ret.Data[Count] = '\0';
return ret;
}
void replace(size_t Pos, size_t Count, const char *Str)
{
strdbg("%#lx: String replace: %d, %d, \"%s\"",
this, Pos, Count, Str);
if (Pos >= this->Length)
return;
if ((int64_t)Count <= 0)
return;
if (Pos + Count > this->Length)
Count = this->Length - Pos;
size_t NewLength = this->Length - Count + strlen(Str);
this->resize(NewLength);
for (size_t i = this->Length - 1; i >= Pos + strlen(Str); i--)
this->Data[i] = this->Data[i - strlen(Str) + Count];
for (unsigned long i = 0; i < strlen(Str); i++)
this->Data[Pos + i] = Str[i];
strdbg("%#lx: String replaced: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
void replace(size_t Pos, size_t Count, const basic_string &Str)
{
strdbg("%#lx: String replace: %d, %d, \"%s\"",
this, Pos, Count, Str.Data);
if (Pos >= this->Length)
return;
if ((int64_t)Count <= 0)
return;
if (Pos + Count > this->Length)
Count = this->Length - Pos;
size_t NewLength = this->Length - Count + Str.Length;
this->resize(NewLength);
for (size_t i = this->Length - 1; i >= Pos + Str.Length; i--)
this->Data[i] = this->Data[i - Str.Length + Count];
for (size_t i = 0; i < Str.Length; i++)
this->Data[Pos + i] = Str.Data[i];
strdbg("%#lx: String replaced: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
void pop_back()
{
strdbg("%#lx: String pop_back", this);
if (this->Length > 0)
{
this->Data[this->Length - 1] = '\0';
this->Length--;
}
}
void insert(size_t Index, size_t Count, char Ch)
{
strdbg("%#lx: String insert: %d, %d, '%c'",
this, Index, Count, Ch);
if (Index > this->Length)
return;
size_t NewLength = this->Length + Count;
this->resize(NewLength);
for (size_t i = this->Length - 1; i >= Index + Count; i--)
this->Data[i] = this->Data[i - Count];
for (size_t i = 0; i < Count; i++)
this->Data[Index + i] = Ch;
strdbg("%#lx: String inserted: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
}
basic_string operator+(const basic_string &Other) const
{
basic_string result = *this;
result.concat(Other);
strdbg("%#lx: String added: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, result.Data, result.Data, result.Length, result.Capacity);
return result;
}
basic_string operator+(const char *Other) const
{
basic_string result = *this;
result.concat(Other);
strdbg("%#lx: String added: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, result.Data, result.Data, result.Length, result.Capacity);
return result;
}
basic_string &operator+=(const basic_string &Other)
{
this->concat(Other);
strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return *this;
}
basic_string &operator+=(const char *Other)
{
this->concat(Other);
strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return *this;
}
basic_string &operator+=(char Other)
{
const char str[2] = {Other, '\0'};
this->concat(str);
strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return *this;
}
/* warning: implicitly-declared 'constexpr String::String(const String&)' is deprecated [-Wdeprecated-copy] */
basic_string &operator=(const basic_string &Other) = default;
// basic_string &operator=(const basic_string &Other)
// {
// if (this != &Other)
// {
// delete[] this->Data;
// this->Data = Other.Data;
// this->Length = Other.Length;
// this->Capacity = Other.Capacity;
// strdbg("%#lx: String assigned: \"%s\" (data: %#lx, length: %d, capacity: %d)",
// this, this->Data, this->Data, this->Length, this->Capacity);
// }
// return *this;
// }
basic_string &operator=(const char *Other)
{
this->Length = strlen(Other);
this->Capacity = this->Length + 1;
delete[] this->Data;
this->Data = new char[this->Capacity];
strcpy(this->Data, Other);
strdbg("%#lx: String assigned: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return *this;
}
basic_string &operator<<(const basic_string &Other)
{
this->concat(Other);
strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return *this;
}
basic_string &operator<<(const char *Other)
{
this->concat(Other);
strdbg("%#lx: String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)",
this, this->Data, this->Data, this->Length, this->Capacity);
return *this;
}
char &operator[](int Index)
{
strdbg("%#lx: String index: %d", this, Index);
return this->Data[Index];
}
const char &operator[](int Index) const
{
strdbg("%#lx: String index: %d", this, Index);
return this->Data[Index];
}
char &operator[](size_t Index)
{
strdbg("%#lx: String index: %d", this, Index);
return this->Data[Index];
}
const char &operator[](size_t Index) const
{
strdbg("%#lx: String index: %d", this, Index);
return this->Data[Index];
}
bool operator==(const basic_string &Other) const
{
strdbg("%#lx: String compared: \"%s\" == \"%s\"",
this, this->Data, Other.Data);
return strcmp(this->Data, Other.Data) == 0;
}
bool operator!=(const char *Other) const
{
strdbg("%#lx: String compared: \"%s\" != \"%s\"",
this, this->Data, Other);
return strcmp(this->Data, Other) != 0;
}
bool operator!=(const basic_string &Other) const
{
strdbg("%#lx: String compared: \"%s\" != \"%s\"",
this, this->Data, Other.Data);
return strcmp(this->Data, Other.Data) != 0;
}
bool operator==(const char *Other) const
{
strdbg("%#lx: String compared: \"%s\" == \"%s\"",
this, this->Data, Other);
return strcmp(this->Data, Other) == 0;
}
class iterator
{
private:
char *Pointer;
public:
iterator(char *Pointer) : Pointer(Pointer) {}
iterator &operator++()
{
++this->Pointer;
strdbg("%#lx: String iterator incremented: %#lx",
this, this->Pointer);
return *this;
}
char &operator*()
{
strdbg("%#lx: String iterator dereferenced: %#lx",
this, this->Pointer);
return *this->Pointer;
}
bool operator!=(const iterator &Other) const
{
strdbg("%#lx: String iterator compared: %#lx != %#lx",
this, this->Pointer, Other.Pointer);
return this->Pointer != Other.Pointer;
}
bool operator==(const iterator &Other) const
{
strdbg("%#lx: String iterator compared: %#lx == %#lx",
this, this->Pointer, Other.Pointer);
return this->Pointer == Other.Pointer;
}
};
iterator begin()
{
strdbg("%#lx: String iterator begin: %#lx",
this, this->Data);
return iterator(this->Data);
}
iterator end()
{
strdbg("%#lx: String iterator end: %#lx",
this, this->Data + this->Length);
return iterator(this->Data + this->Length);
}
};
typedef basic_string string;
template <class CharT>
class char_traits
{
public:
static size_t length(const CharT *s)
{
size_t len = 0;
while (s[len] != 0)
len++;
return len;
}
};
}