From 621036d591a6f7a28b91dcb4bc5f972130dd6e77 Mon Sep 17 00:00:00 2001 From: ChUrl Date: Thu, 8 Dec 2022 22:42:26 +0100 Subject: [PATCH] Cleanup string classes --- src/device/graphics/CGA.cc | 2 +- src/device/graphics/CGA.h | 2 +- src/device/port/SerialOut.cc | 2 +- src/device/port/SerialOut.h | 2 +- src/lib/demo/StringDemo.cc | 14 +- src/lib/memory/Memory.cc | 2 +- src/lib/memory/Memory.h | 2 +- src/lib/stream/Logger.cc | 10 +- src/lib/stream/Logger.h | 12 +- src/lib/stream/OutStream.h | 2 +- src/lib/string/String.h | 297 +++++++++++++++++++---------------- src/lib/string/StringView.cc | 4 +- src/lib/string/StringView.h | 55 ++++--- 13 files changed, 218 insertions(+), 188 deletions(-) diff --git a/src/device/graphics/CGA.cc b/src/device/graphics/CGA.cc index 0c29c0b..29ac552 100755 --- a/src/device/graphics/CGA.cc +++ b/src/device/graphics/CGA.cc @@ -106,7 +106,7 @@ void CGA::show(uint8_t x, uint8_t y, char character, uint8_t attrib) { * n Laenger der Zeichenkette * * attrib Attributbyte fuer alle Zeichen der Zeichenkette * *****************************************************************************/ -void CGA::print(const String::string_view string, uint8_t attrib) const { +void CGA::print(const String::StringView string, uint8_t attrib) const { /* Hier muess Code eingefuegt werden */ diff --git a/src/device/graphics/CGA.h b/src/device/graphics/CGA.h index ee0ac1a..7495938 100755 --- a/src/device/graphics/CGA.h +++ b/src/device/graphics/CGA.h @@ -99,7 +99,7 @@ public: static void show(uint8_t x, uint8_t y, char character, uint8_t attrib = STD_ATTR); // Anzeige mehrerer Zeichen ab der aktuellen Cursorposition - void print(String::string_view substring, uint8_t attrib = STD_ATTR) const; + void print(String::StringView substring, uint8_t attrib = STD_ATTR) const; // Verschiebt den Bildschirminhalt um eine Zeile nach oben. // Neue Zeile am unteren Bildrand mit Leerzeichen fuellen diff --git a/src/device/port/SerialOut.cc b/src/device/port/SerialOut.cc index 3cebfb4..ecb0c04 100644 --- a/src/device/port/SerialOut.cc +++ b/src/device/port/SerialOut.cc @@ -42,7 +42,7 @@ void SerialOut::write(const char a) { com1.outb(a); } -void SerialOut::write(const String::string_view a) { +void SerialOut::write(const String::StringView a) { for (char current: a) { write(current); } diff --git a/src/device/port/SerialOut.h b/src/device/port/SerialOut.h index ca2e04a..497efa8 100644 --- a/src/device/port/SerialOut.h +++ b/src/device/port/SerialOut.h @@ -24,7 +24,7 @@ public: static void write(char a); - static void write(String::string_view a); + static void write(String::StringView a); private: static const IOport com1; diff --git a/src/lib/demo/StringDemo.cc b/src/lib/demo/StringDemo.cc index f8fa0c2..b762ddd 100644 --- a/src/lib/demo/StringDemo.cc +++ b/src/lib/demo/StringDemo.cc @@ -10,7 +10,7 @@ void StringDemo::run() { Util::System::out.clear(); log.info() << "Allocating new string" << endl; - String::string str1 = "This is a dynamically allocated string!"; + String::String str1 = "This is a dynamically allocated string!"; Util::System::out << str1 << endl; log.info() << "Reassign string" << endl; @@ -25,7 +25,7 @@ void StringDemo::run() { Util::System::out << "Hello += World" << endl; log.info() << "Hello += World" << endl; - String::string str3 = "Hello"; + String::String str3 = "Hello"; str3 += " World"; Util::System::out << str3 << endl; @@ -40,7 +40,7 @@ void StringDemo::run() { Util::System::out << endl; log.info() << "Allocating new string" << endl; - String::string str2 = "Hello World"; + String::String str2 = "Hello World"; Util::System::out << "str1 == str2: " << static_cast(str1 == str2) << endl; Util::System::out << "strcmp(Hello, Hello): " << String::strcmp("Hello", "Hello") << endl; @@ -53,10 +53,10 @@ void StringDemo::run() { arr[2] = 'l'; arr[3] = 'l'; arr[4] = 'o'; - Util::System::out << "bse::array to bse::string: " << static_cast(arr) << ", size: " - << (String::string(arr)).size() << endl; - Util::System::out << "(bse::string)arr (" << static_cast(arr) << ") == str2 (" << str2 << "): " - << static_cast(String::string(arr) == str2) << endl; + Util::System::out << "bse::array to bse::string: " << static_cast(arr) << ", size: " + << (String::String(arr)).size() << endl; + Util::System::out << "(bse::string)arr (" << static_cast(arr) << ") == str2 (" << str2 << "): " + << static_cast(String::String(arr) == str2) << endl; Util::System::out.unlock(); auto &schedulerService = Kernel::System::getService(); diff --git a/src/lib/memory/Memory.cc b/src/lib/memory/Memory.cc index 63038cd..c097636 100755 --- a/src/lib/memory/Memory.cc +++ b/src/lib/memory/Memory.cc @@ -2,7 +2,7 @@ namespace Memory { -void memset(char *destination, const char value, std::size_t bytes) { +void memset(uint8_t *destination, const uint8_t value, std::size_t bytes) { for (std::size_t byte = 0; byte < bytes; ++byte) { *(destination + byte) = value; } diff --git a/src/lib/memory/Memory.h b/src/lib/memory/Memory.h index 92cccf7..4f9f432 100755 --- a/src/lib/memory/Memory.h +++ b/src/lib/memory/Memory.h @@ -17,7 +17,7 @@ void memset(uint8_t *destination, uint8_t value, std::size_t bytes); template void zero(T *destination) { - memset(reinterpret_cast(destination), '\0', sizeof(T)); + memset(reinterpret_cast(destination), 0, sizeof(T)); } } // namespace bse diff --git a/src/lib/stream/Logger.cc b/src/lib/stream/Logger.cc index 6e7b24d..6dd3e36 100644 --- a/src/lib/stream/Logger.cc +++ b/src/lib/stream/Logger.cc @@ -14,7 +14,7 @@ constexpr const char *ansi_cyan = "\033[1;36m"; constexpr const char *ansi_white = "\033[1;37m"; constexpr const char *ansi_default = "\033[0;39m "; -void Logger::log(const String::string_view message, Device::CGA::color col) const { +void Logger::log(const String::StringView message, Device::CGA::color col) const { if (!Logger::serial_enabled) { return; } @@ -66,25 +66,25 @@ void Logger::flush() { Logger::unlock(); } -void Logger::trace(const String::string_view message) const { +void Logger::trace(const String::StringView message) const { if (Logger::level <= Logger::TRACE) { log(message, Device::CGA::WHITE); } } -void Logger::debug(const String::string_view message) const { +void Logger::debug(const String::StringView message) const { if (Logger::level <= Logger::DEBUG) { log(message, Device::CGA::LIGHT_MAGENTA); } } -void Logger::error(const String::string_view message) const { +void Logger::error(const String::StringView message) const { if (Logger::level <= Logger::ERROR) { log(message, Device::CGA::LIGHT_RED); } } -void Logger::info(const String::string_view message) const { +void Logger::info(const String::StringView message) const { if (Logger::level <= Logger::INFO) { log(message, Device::CGA::LIGHT_BLUE); } diff --git a/src/lib/stream/Logger.h b/src/lib/stream/Logger.h index 60cdfd2..ad160a8 100644 --- a/src/lib/stream/Logger.h +++ b/src/lib/stream/Logger.h @@ -21,7 +21,7 @@ private: static bool serial_enabled; - void log(String::string_view message, Device::CGA::color col) const; + void log(String::StringView message, Device::CGA::color col) const; Async::SpinLock sem; // Semaphore would be a cyclic include, also there is just one logger... static void lock() { Logger::instance().sem.acquire(); } @@ -46,20 +46,20 @@ public: void flush() override; - void trace(String::string_view message) const; + void trace(String::StringView message) const; - void debug(String::string_view message) const; + void debug(String::StringView message) const; - void error(String::string_view message) const; + void error(String::StringView message) const; - void info(String::string_view message) const; + void info(String::StringView message) const; // TODO: Make lvl change accessible over menu static void set_level(LogLevel lvl) { Logger::level = lvl; } - static String::string_view level_to_string(LogLevel lvl) { + static String::StringView level_to_string(LogLevel lvl) { switch (lvl) { case Logger::TRACE: return "TRC"; diff --git a/src/lib/stream/OutStream.h b/src/lib/stream/OutStream.h index dea4fb6..828b9b8 100755 --- a/src/lib/stream/OutStream.h +++ b/src/lib/stream/OutStream.h @@ -88,7 +88,7 @@ public: // Darstellung einer nullterminierten Zeichenkette template - friend T &operator<<(T &os, const String::string_view string) { + friend T &operator<<(T &os, const String::StringView string) { for (char current: string) { os.put(current); } diff --git a/src/lib/string/String.h b/src/lib/string/String.h index a1d0f35..624bb08 100644 --- a/src/lib/string/String.h +++ b/src/lib/string/String.h @@ -6,172 +6,191 @@ namespace String { -// A heap dynamically heap-allocated string (mutable) +// Utility functions +unsigned int strlen(const char *str); - unsigned int strlen(const char* str); - void strncpy(char* destination, unsigned int n, const char* source); - int strcmp(const char* a, const char* b); +void strncpy(char *destination, unsigned int n, const char *source); - class string { - private: - std::size_t len = 0; - char* buf = nullptr; +int strcmp(const char *a, const char *b); - public: - using iterator = Container::ContinuousIterator; +/** + * This class implements a simple heap allocated string. + */ +class String { + using iterator = Container::ContinuousIterator; - string() = default; +public: + String() = default; - string(const char* str) : len(strlen(str)), buf(new char[len + 1]) { - strncpy(buf, len + 1, str); + /** + * Constructor. Implicitly convert string literal to dynamic string. + * + * @param str The string literal to convert + */ + String(const char *str) : len(strlen(str)), buf(new char[len + 1]) { // NOLINT(google-explicit-constructor) + strncpy(buf, len + 1, str); + } + + /** + * Constructor. Convert a char array to a dynamic string. + * + * @tparam N The size of the char array + * @param arr The char array + */ + template + explicit String(const Container::Array &arr) : len(N), buf(new char[len + 1]) { + for (std::size_t i = 0; i < N; ++i) { + buf[i] = arr[i]; } + buf[N] = '\0'; + } - // Convert char array to string - template - explicit string(const Container::Array& arr) : len(N), buf(new char[len + 1]) { - for (std::size_t i = 0; i < N; ++i) { - buf[i] = arr[i]; - } - buf[N] = '\0'; - } + String(const String ©) : len(copy.len), buf(new char[len + 1]) { + strncpy(buf, len + 1, copy.buf); + } - string(const string& copy) : len(copy.len), buf(new char[len + 1]) { + String &operator=(const String ©) { + if (© != this) { + len = copy.len; + buf = new char[len + 1]; strncpy(buf, len + 1, copy.buf); } - string& operator=(const string& copy) { - if (© != this) { - len = copy.len; - buf = new char[len + 1]; - strncpy(buf, len + 1, copy.buf); - } + return *this; + } - return *this; - } + String(String &&move) noexcept: len(move.len), buf(move.buf) { + move.len = 0; + move.buf = nullptr; + } + + String &operator=(String &&move) noexcept { + if (&move != this) { + len = move.len; + buf = move.buf; - string(string&& move) noexcept : len(move.len), buf(move.buf) { move.len = 0; move.buf = nullptr; } - string& operator=(string&& move) noexcept { - if (&move != this) { - len = move.len; - buf = move.buf; + return *this; + } - move.len = 0; - move.buf = nullptr; - } + ~String() { + delete[] buf; + } - return *this; + iterator begin() { return {buf}; } + + [[nodiscard]] iterator begin() const { return {buf}; } + + iterator end() { return {&buf[len]}; } + + [[nodiscard]] iterator end() const { return {&buf[len]}; } + + explicit operator char *() { return buf; } + + explicit operator char *() const { return buf; } + + char operator[](std::size_t pos) { return buf[pos]; } + + char operator[](std::size_t pos) const { return buf[pos]; } + + String operator+(const String &other) const { + String new_str; + new_str.len = len + other.len; + new_str.buf = new char[new_str.len + 1]; + + strncpy(new_str.buf, len, buf); // Copy this content + strncpy(&new_str.buf[len], other.len + 1, other.buf); // Copy other content + + return new_str; + } + + String operator+(const char *other) const { + std::size_t other_len = strlen(other); + + String new_str; + new_str.len = len + other_len; + new_str.buf = new char[new_str.len + 1]; + + strncpy(new_str.buf, len, buf); + strncpy(&new_str.buf[len], other_len + 1, other); + + return new_str; + } + + String &operator+=(const String &other) { + unsigned int new_len = len + other.size(); + char *new_buf = new char[new_len + 1]; + + strncpy(new_buf, len, buf); + strncpy(&new_buf[len], other.size() + 1, other.buf); + + delete[] buf; + buf = new_buf; + len = new_len; + + return *this; + } + + String &operator+=(const char *other) { + unsigned int other_len = strlen(other); + unsigned int new_len = len + other_len; + char *new_buf = new char[new_len + 1]; + + strncpy(new_buf, len, buf); + strncpy(&new_buf[len], other_len + 1, other); + + delete[] buf; + buf = new_buf; + len = new_len; + + return *this; + } + + String operator*(unsigned int n) const { + String new_str; + new_str.len = len * n; + new_str.buf = new char[new_str.len]; + + for (unsigned int i = 0; i < n; ++i) { + strncpy(&new_str.buf[i * len], len, buf); } - ~string() { - delete[] buf; + return new_str; + } + + String &operator*=(unsigned int n) { + unsigned int new_len = len * n; + char *new_buf = new char[new_len]; + + for (unsigned int i = 0; i < n; ++i) { + strncpy(&new_buf[i * len], len, buf); } - iterator begin() { return iterator(buf); } - iterator begin() const { return iterator(buf); } - iterator end() { return iterator(&buf[len]); } - iterator end() const { return iterator(&buf[len]); } + delete[] buf; + buf = new_buf; + len = new_len; + return *this; + } - explicit operator char*() { return buf; } - explicit operator char*() const { return buf; } + bool operator==(const String &other) const { + return strcmp(buf, other.buf) == 0; + } - char operator[](std::size_t pos) { return buf[pos]; } - char operator[](std::size_t pos) const { return buf[pos]; } + bool operator!=(const String &other) const { + return strcmp(buf, other.buf) != 0; + } - string operator+(const string& other) const { - string new_str; - new_str.len = len + other.len; - new_str.buf = new char[new_str.len + 1]; + [[nodiscard]] std::size_t size() const { + return len; + } - strncpy(new_str.buf, len, buf); // Copy this content - strncpy(&new_str.buf[len], other.len + 1, other.buf); // Copy other content - - return new_str; - } - - string operator+(const char* other) const { - std::size_t other_len = strlen(other); - - string new_str; - new_str.len = len + other_len; - new_str.buf = new char[new_str.len + 1]; - - strncpy(new_str.buf, len, buf); - strncpy(&new_str.buf[len], other_len + 1, other); - - return new_str; - } - - string& operator+=(const string& other) { - unsigned int new_len = len + other.size(); - char* new_buf = new char[new_len + 1]; - - strncpy(new_buf, len, buf); - strncpy(&new_buf[len], other.size() + 1, other.buf); - - delete[] buf; - buf = new_buf; - len = new_len; - - return *this; - } - - string& operator+=(const char* other) { - unsigned int other_len = strlen(other); - unsigned int new_len = len + other_len; - char* new_buf = new char[new_len + 1]; - - strncpy(new_buf, len, buf); - strncpy(&new_buf[len], other_len + 1, other); - - delete[] buf; - buf = new_buf; - len = new_len; - - return *this; - } - - string operator*(unsigned int n) const { - string new_str; - new_str.len = len * n; - new_str.buf = new char[new_str.len]; - - for (unsigned int i = 0; i < n; ++i) { - strncpy(&new_str.buf[i * len], len, buf); - } - - return new_str; - } - - string& operator*=(unsigned int n) { - unsigned int new_len = len * n; - char* new_buf = new char[new_len]; - - for (unsigned int i = 0; i < n; ++i) { - strncpy(&new_buf[i * len], len, buf); - } - - delete[] buf; - buf = new_buf; - len = new_len; - return *this; - } - - bool operator==(const string& other) const { - return strcmp(buf, other.buf) == 0; - } - - bool operator!=(const string& other) const { - return strcmp(buf, other.buf) != 0; - } - - std::size_t size() const { - return len; - } - }; +private: + std::size_t len = 0; + char *buf = nullptr; +}; } // namespace bse diff --git a/src/lib/string/StringView.cc b/src/lib/string/StringView.cc index 9adfe5d..f382f98 100644 --- a/src/lib/string/StringView.cc +++ b/src/lib/string/StringView.cc @@ -2,12 +2,12 @@ namespace String { -string_view string_view::substring(std::size_t first, std::size_t last) const { +StringView StringView::substring(std::size_t first, std::size_t last) const { if (first < 0 || first > len || last <= first || last > len) { return nullptr; } - string_view new_view; + StringView new_view; new_view.len = last - first; new_view.buf = &buf[first]; return new_view; diff --git a/src/lib/string/StringView.h b/src/lib/string/StringView.h index c0c436a..e6bd591 100644 --- a/src/lib/string/StringView.h +++ b/src/lib/string/StringView.h @@ -7,34 +7,45 @@ namespace String { - class string_view { - private: - std::size_t len = 0; - const char* buf = nullptr; +// TODO: Investigate this class - public: - using iterator = Container::ContinuousIterator; +/** + * This class implements a simple wrapper for usual string literals. + */ +class StringView { + using iterator = Container::ContinuousIterator; - string_view() = default; +public: + StringView() = default; - // Important that char* and string& can be implicitly converted: Only have to provide one - // implementation using stringview for everything (OutStream only uses string_view for example) - string_view(const char* str) : len(strlen(str)), buf(str) {} - string_view(const string& str) : len(str.size()), buf(static_cast(str)) {} + // Important that char* and string& can be implicitly converted: Only have to provide one + // implementation using stringview for everything (OutStream only uses StringView for example) + StringView(const char *str) : len(strlen(str)), buf(str) {} // NOLINT(google-explicit-constructor) - iterator begin() const { return iterator(buf); } - iterator end() const { return iterator(&buf[len]); } + StringView(const String &str) : len(str.size()), // NOLINT(google-explicit-constructor) + buf(static_cast(str)) {} - explicit operator const char*() const { return buf; } - char operator[](std::size_t pos) const { return buf[pos]; } - bool operator==(const string_view& other) const { return buf == other.buf; } - bool operator!=(const string_view& other) const { return buf != other.buf; } + [[nodiscard]] iterator begin() const { return {buf}; } - std::size_t size() const { return len; } + [[nodiscard]] iterator end() const { return {&buf[len]}; } - string_view substring(std::size_t first, std::size_t last) const; - }; + explicit operator const char *() const { return buf; } -} // namespace bse + char operator[](std::size_t pos) const { return buf[pos]; } -#endif //C_OS_STRINGVIEW_H + bool operator==(const StringView &other) const { return buf == other.buf; } + + bool operator!=(const StringView &other) const { return buf != other.buf; } + + [[nodiscard]] std::size_t size() const { return len; } + + [[nodiscard]] StringView substring(std::size_t first, std::size_t last) const; + +private: + std::size_t len = 0; + const char *buf = nullptr; +}; + +} // namespace bse + +#endif //C_OS_STRINGVIEW_H