/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include #include #include #include #include #include #include #include #include namespace OpenVulkano { class String final { public: String() = default; String(const char* str) : m_string(str) {} String(const std::string& str) : m_string(str) {} String(const std::string_view& str) : m_string(str) {} String(const String& other) : m_string(other.m_string) {} String(String&& other) noexcept : m_string(std::move(other.m_string)) {} ~String() = default; template String& operator=(const T& other) { m_string = other; return *this; } template String& operator=(T&& other) { m_string = std::move(other); return *this; } template String& operator=(const String& other) { m_string = other.m_string; return *this; } template String& operator+=(const T& other) { m_string += other; return *this; } template String& operator+=(const String& other) { m_string += other.m_string; return *this; } template String operator+(const T& other) const { return m_string + other; } String operator+(const String& other) const { return m_string + other.m_string; } template auto operator<=>(const T& other) const { return m_string <=> other; } auto operator<=>(const String& other) const = default; explicit operator bool() const { return !m_string.empty(); } operator std::string() const { return m_string; } explicit operator std::string_view() const { return m_string; } char& operator[](size_t index) noexcept { return m_string[index]; } const char& operator[](size_t index) const noexcept { return m_string[index]; } char& At(size_t index) { return m_string.at(index); } const char& At(size_t index) const { return m_string.at(index); } const char* CharString() const { return m_string.c_str(); } const char* Data() { return m_string.data(); } size_t Length() const { return m_string.length(); } size_t Size() const { return m_string.size(); } bool Empty() const { return m_string.empty(); } size_t Capacity() const { return m_string.capacity(); } size_t CharCount() const { return utf8::distance(m_string.begin(), m_string.end()); } char& Front() { return m_string.front(); } char& Back() { return m_string.back(); } void PopBack() { m_string.pop_back(); } void Clear() { m_string.clear(); } void ShrinkToFit() { m_string.shrink_to_fit(); } String SubString(size_t start, size_t elementCount) const { return m_string.substr(start, elementCount); } bool StartsWith(const std::string_view& str) const { return m_string.find(str) == 0; } bool EndsWith(const std::string_view& str) const { return m_string.rfind(str) == m_string.size() - str.size(); } bool Contains(const std::string_view& str) const { return m_string.find(str) != std::string::npos; } size_t FindStartIndexOf(const std::string_view& str) const { return m_string.find(str); } size_t FindEndIndexOf(const std::string_view& str) const { return m_string.rfind(str); } String Trim() noexcept { String trimmed = TrimBack(); return trimmed.TrimFront(); } String& TrimFront() noexcept { size_t start = m_string.find_first_not_of(" \t\n\r"); if (start == std::string::npos) { m_string.clear(); } else { m_string.erase(0, start); } return *this; } String& TrimBack() noexcept { size_t end = m_string.find_last_not_of(" \t\n\r"); if (end == std::string::npos) { m_string.clear(); } else { m_string.resize(end + 1); } return *this; } std::vector Split(const std::string_view& delimiter) const { std::vector result; size_t start = 0; size_t end = m_string.find(delimiter); while (end != std::string::npos) { result.push_back(m_string.substr(start, end - start)); start = end + delimiter.size(); end = m_string.find(delimiter, start); } result.push_back(m_string.substr(start, end)); return result; } std::pair SplitAtLastOccurrence(const std::string_view& delimiter) const { size_t end = m_string.rfind(delimiter); if (end == std::string::npos) { return { m_string, "" }; } return { m_string.substr(0, end), m_string.substr(end + delimiter.size()) }; } std::pair SplitAtFirstOccurrence(const std::string_view& delimiter) const { size_t end = m_string.find(delimiter); if (end == std::string::npos) { return { m_string, "" }; } return { m_string.substr(0, end), m_string.substr(end + delimiter.size()) }; } std::vector SplitAsStringViews(const std::string_view& delimiter) const { std::vector result; size_t start = 0; size_t end = m_string.find(delimiter); while (end != std::string::npos) { result.push_back(std::string_view(m_string.c_str() + start, end - start)); start = end + delimiter.size(); end = m_string.find(delimiter, start); } result.push_back( std::string_view(m_string.c_str() + start, m_string.size() - (start + end + delimiter.size()))); return result; } std::pair SplitAtLastOccurenceAsStringViews(const std::string_view& delimiter) const { size_t end = m_string.rfind(delimiter); if (end == std::string::npos) { return { m_string, "" }; } return { std::string_view(m_string.c_str(), end), std::string_view(m_string.c_str() + end + delimiter.size(), m_string.size() - end - delimiter.size()) }; } std::pair SplitAtFirstOccurenceAsStringViews(const std::string_view& delimiter) const { size_t end = m_string.find(delimiter); if (end == std::string::npos) { return { m_string, "" }; } return { std::string_view(m_string.c_str(), end), std::string_view(m_string.c_str() + end + delimiter.size(), m_string.size() - end - delimiter.size()) }; } static inline constexpr int64_t OctToInt(std::string_view string) { int64_t result = 0; for (int i = 0; i < static_cast(string.length()); i++) { char c = string[i]; if (c == 0) { break; } if (c == ' ') { continue; } if (c < '0' || c > '7') { return -1; } result = result * 8 + c - '0'; } return result; } constexpr int64_t OctToInt() { return OctToInt(m_string); } static inline constexpr int64_t HexToInt(std::string string) { int64_t result = 0; for (char c: string) { if (c == 0) { break; } if (c == ' ') { continue; } if (c >= '0' && c <= '9') { result = result * 16 + c - '0'; } else if (c >= 'A' && c <= 'F') { result = result * 16 + c - 'A' + 10; } else if (c >= 'a' && c <= 'f') { result = result * 16 + c - 'a' + 10; } else { return -1; } } return result; } constexpr int64_t HexToInt() { return HexToInt(m_string); } void ToUpper() noexcept { std::transform(m_string.begin(), m_string.end(), m_string.begin(), [](unsigned char c) { return std::toupper(c); }); } void ToLower() noexcept { std::transform(m_string.begin(), m_string.end(), m_string.begin(), [](unsigned char c) { return std::tolower(c); }); } void Capitalize() noexcept { if (!m_string.empty()) { m_string[0] = std::toupper(m_string[0]); } } template>> T FromString() const { T value; c4::csubstr str = c4::to_csubstr(m_string.c_str()); c4::from_chars(str, &value); return value; } // iterators std::string::iterator begin() { return m_string.begin(); } std::string::iterator end() { return m_string.end(); } std::string::const_iterator cbegin() const { return m_string.cbegin(); } std::string::const_iterator cend() const { return m_string.cend(); } std::string::reverse_iterator rbegin() { return m_string.rbegin(); } std::string::reverse_iterator rend() { return m_string.rend(); } std::reverse_iterator crbegin() const { return m_string.crbegin(); } std::reverse_iterator crend() const { return m_string.crend(); } private: std::string m_string; }; template String operator+(const T& lhs, const String& rhs) noexcept { return String(lhs) + rhs; } }