diff --git a/Tests/String.cpp b/Tests/String.cpp new file mode 100644 index 0000000..69609bd --- /dev/null +++ b/Tests/String.cpp @@ -0,0 +1,110 @@ +#ifdef DEBUG + +#include +#include + +void TestString() +{ + String hw("Hello, world!"); + debug("String length: %d", hw.length()); + debug("String capacity: %d", hw.capacity()); + debug("String data: %s", hw.c_str()); + if (hw == "Hello, world!" && hw != "World, hello!") + debug("String comparison works!"); + else + { + error("String comparison doesn't work! \"%s\"", hw.c_str()); + while (1) + ; + } + + String hi("Hi"); + char chi[3]; + chi[0] = hi[0]; + chi[1] = hi[1]; + chi[2] = '\0'; + if (strcmp(chi, "Hi") == 0) + debug("String indexing works!"); + else + { + error("String indexing doesn't work! \"%s\" \"%s\"", chi, hi.c_str()); + while (1) + ; + } + + hi << " there!"; + if (hi == "Hi there!") + debug("String concatenation works!"); + else + { + error("String concatenation doesn't work! \"%s\"", hi.c_str()); + while (1) + ; + } + + hi << " " << hw; + if (hi == "Hi there! Hello, world!") + debug("String concatenation works!"); + else + { + error("String concatenation doesn't work! \"%s\"", hi.c_str()); + while (1) + ; + } + + String eq0("Hello, world!"); + String eq1("Hello, world!"); + String eq2("World, hello!"); + + if (eq0 == eq1) + debug("String equality works!"); + else + { + error("String equality doesn't work! \"%s\" \"%s\"", eq0.c_str(), eq1.c_str()); + while (1) + ; + } + + if (eq0 != eq2) + debug("String inequality works!"); + else + { + error("String inequality doesn't work! \"%s\" \"%s\"", eq0.c_str(), eq2.c_str()); + while (1) + ; + } + + char chw[14]; + int i = 0; + foreach (auto c in hw) + { + chw[i] = c; + i++; + } + chw[i] = '\0'; + + if (strcmp(chw, "Hello, world!") == 0) + debug("String iteration works!"); + else + { + error("String iteration doesn't work! \"%s\" \"%s\" %d", chw, hw.c_str(), i); + while (1) + ; + } + + String a("Hello"); + String b("World"); + String c; + c = a + ", " + b + "!"; + + if (c == "Hello, World!") + debug("String addition works!"); + else + { + error("String addition doesn't work! \"%s\"", c.c_str()); + while (1) + ; + } +} + +#endif // DEBUG diff --git a/Tests/TypeSize.cpp b/Tests/TypeSize.cpp index c06c9d9..4431f64 100644 --- a/Tests/TypeSize.cpp +++ b/Tests/TypeSize.cpp @@ -103,4 +103,4 @@ __constructor void TestTypeSize() debug("__UINTMAX_MAX__ = %#llx", __UINTMAX_MAX__); } -#endif +#endif // DEBUG diff --git a/Tests/t.h b/Tests/t.h new file mode 100644 index 0000000..96670db --- /dev/null +++ b/Tests/t.h @@ -0,0 +1,10 @@ +#ifndef __FENNIX_KERNEL_non_constructor_tests_H__ +#define __FENNIX_KERNEL_non_constructor_tests_H__ +#ifdef DEBUG + +#include + +void TestString(); + +#endif // DEBUG +#endif // !__FENNIX_KERNEL_non_constructor_tests_H__ diff --git a/include/string.hpp b/include/string.hpp new file mode 100644 index 0000000..b12d251 --- /dev/null +++ b/include/string.hpp @@ -0,0 +1,233 @@ +#ifndef __FENNIX_KERNEL_STRING_H__ +#define __FENNIX_KERNEL_STRING_H__ + +#include +#include +#include + +// show debug messages +// #define DEBUG_CPP_STRING 1 + +#ifdef DEBUG_CPP_STRING +#define strdbg(m, ...) debug(m, ##__VA_ARGS__) +#else +#define strdbg(m, ...) +#endif + +// TODO: Somewhere the delete is called twice, causing a double free error. + +/** + * @brief String class + * String class that can be used to store strings. + */ +class String +{ +private: + char *m_Data; + int m_Length; + int m_Capacity; + +public: + String(const char *Str = "") + { + this->m_Length = strlen(Str); + this->m_Capacity = this->m_Length + 1; + this->m_Data = new char[m_Capacity]; + strcpy(m_Data, Str); + strdbg("New string created: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + } + + ~String() + { + strdbg("String deleted: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + delete[] this->m_Data; + } + + int length() const + { + strdbg("String length: %d", this->m_Length); + return this->m_Length; + } + + int capacity() const + { + strdbg("String capacity: %d", this->m_Capacity); + return this->m_Capacity; + } + + const char *c_str() const + { + strdbg("String data: \"%s\"", this->m_Data); + return this->m_Data; + } + + void resize(int NewLength) + { + strdbg("String resize: %d", NewLength); + if (NewLength > this->m_Capacity) + { + int newCapacity = NewLength + 1; + char *newData = new char[newCapacity]; + + strcpy(newData, this->m_Data); + + strdbg("old: %#lx, new: %#lx", this->m_Data, newData); + delete[] this->m_Data; + this->m_Data = newData; + this->m_Capacity = newCapacity; + } + this->m_Length = NewLength; + this->m_Data[m_Length] = '\0'; + strdbg("String resized: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + } + + void concat(const String &Other) + { + int NewLength = this->m_Length + Other.m_Length; + this->resize(NewLength); + + strcat(m_Data, Other.m_Data); + strdbg("String concatenated: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + } + + String operator+(const String &Other) const + { + String result = *this; + result.concat(Other); + strdbg("String added: \"%s\" (data: %#lx, length: %d, capacity: %d)", result.m_Data, result.m_Data, result.m_Length, result.m_Capacity); + return result; + } + + String operator+(const char *Other) const + { + String result = *this; + result.concat(Other); + strdbg("String added: \"%s\" (data: %#lx, length: %d, capacity: %d)", result.m_Data, result.m_Data, result.m_Length, result.m_Capacity); + return result; + } + + /* 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->m_Data; + // this->m_Data = Other.m_Data; + // this->m_Length = Other.m_Length; + // this->m_Capacity = Other.m_Capacity; + // strdbg("String assigned: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + // } + // return *this; + // } + + String &operator=(const char *Other) + { + this->m_Length = strlen(Other); + this->m_Capacity = this->m_Length + 1; + delete[] this->m_Data; + this->m_Data = new char[m_Capacity]; + strcpy(m_Data, Other); + strdbg("String assigned: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + return *this; + } + + String &operator<<(const String &Other) + { + this->concat(Other); + strdbg("String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + return *this; + } + + String &operator<<(const char *Other) + { + this->concat(Other); + strdbg("String appended: \"%s\" (data: %#lx, length: %d, capacity: %d)", this->m_Data, this->m_Data, this->m_Length, this->m_Capacity); + return *this; + } + + char &operator[](int Index) + { + strdbg("String index: %d", Index); + return this->m_Data[Index]; + } + + const char &operator[](int Index) const + { + strdbg("String index: %d", Index); + return this->m_Data[Index]; + } + + bool operator==(const String &Other) const + { + strdbg("String compared: \"%s\" == \"%s\"", this->m_Data, Other.m_Data); + return strcmp(this->m_Data, Other.m_Data) == 0; + } + + bool operator!=(const String &Other) const + { + strdbg("String compared: \"%s\" != \"%s\"", this->m_Data, Other.m_Data); + return strcmp(this->m_Data, Other.m_Data) != 0; + } + + bool operator==(const char *Other) const + { + strdbg("String compared: \"%s\" == \"%s\"", this->m_Data, Other); + return strcmp(this->m_Data, Other) == 0; + } + + bool operator!=(const char *Other) const + { + strdbg("String compared: \"%s\" != \"%s\"", this->m_Data, Other); + return strcmp(this->m_Data, Other) != 0; + } + + class Iterator + { + private: + char *m_Pointer; + + public: + Iterator(char *Pointer) : m_Pointer(Pointer) {} + + Iterator &operator++() + { + ++this->m_Pointer; + strdbg("String iterator incremented: %#lx", this->m_Pointer); + return *this; + } + + char &operator*() + { + strdbg("String iterator dereferenced: %#lx", this->m_Pointer); + return *this->m_Pointer; + } + + bool operator!=(const Iterator &Other) const + { + strdbg("String iterator compared: %#lx != %#lx", this->m_Pointer, Other.m_Pointer); + return this->m_Pointer != Other.m_Pointer; + } + + bool operator==(const Iterator &Other) const + { + strdbg("String iterator compared: %#lx == %#lx", this->m_Pointer, Other.m_Pointer); + return this->m_Pointer == Other.m_Pointer; + } + }; + + Iterator begin() + { + strdbg("String iterator begin: %#lx", this->m_Data); + return Iterator(this->m_Data); + } + + Iterator end() + { + strdbg("String iterator end: %#lx", this->m_Data + this->m_Length); + return Iterator(this->m_Data + this->m_Length); + } +}; + +#endif // !__FENNIX_KERNEL_STRING_H__