/* 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 . */ #pragma once #include #include #include // 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 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 String class * String class that can be used to store strings. */ class string { private: char *Data{}; size_t Length{}; size_t Capacity{}; public: static const size_t npos = -1; 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 string created: \"%s\" (data: %#lx, length: %d, capacity: %d)", this, this->Data, this->Data, this->Length, this->Capacity); } ~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 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 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 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); } 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 string(); if (Count == npos) Count = this->Length - Pos; if (Pos + Count > this->Length) Count = this->Length - Pos; 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 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); } string operator+(const string &Other) const { 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; } string operator+(const char *Other) const { 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; } string &operator+=(const 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; } 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; } 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] */ string &operator=(const string &Other) = default; // string &operator=(const 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; // } 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; } string &operator<<(const 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; } 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 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 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); } }; }