Files
OpenVulkano/openVulkanoCpp/Data/Containers/String.hpp
2025-10-14 15:47:48 +02:00

333 lines
9.8 KiB
C++

/*
* 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 <string>
#include <string_view>
#include <vector>
#include <c4/substr.hpp>
#include <c4/substr_fwd.hpp>
#include <c4/format.hpp>
#include <c4/charconv.hpp>
#include <type_traits>
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(std::string&& other) noexcept : m_string(std::move(other)) {}
~String() = default;
template<typename T> String& operator=(const T& other)
{
m_string = other;
return *this;
}
template<typename T> String& operator=(T&& other)
{
m_string = std::move(other);
return *this;
}
String& operator=(const String& other)
{
m_string = other.m_string;
return *this;
}
String& operator=(String&& other) noexcept
{
m_string = std::move(other.m_string);
return *this;
}
template<typename T> String& operator+=(const T& other)
{
m_string += other;
return *this;
}
String& operator+=(const String& other)
{
m_string += other.m_string;
return *this;
}
template<typename T> String operator+(const T& other) const { return m_string + other; }
String operator+(const String& other) const { return m_string + other.m_string; }
template<typename T> 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 const std::string&() const { return m_string; }
explicit operator std::string_view() const { return m_string; }
char& operator[](const size_t index) noexcept { return m_string[index]; }
const char& operator[](const size_t index) const noexcept { return m_string[index]; }
char& At(const size_t index) { return m_string.at(index); }
const char& At(const size_t index) const { return m_string.at(index); }
const char* CharString() const { return m_string.c_str(); }
const char* c_str() const { return m_string.c_str(); }
const char* Data() const { return m_string.data(); }
const char* data() const { return m_string.data(); }
char* Data() { return m_string.data(); }
char* data() { return m_string.data(); }
size_t Length() const { return m_string.length(); }
size_t Size() const { return m_string.size(); }
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;
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 substr(size_t start, size_t elementCount) const { return m_string.substr(start, elementCount); }
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 { return TrimBack().TrimFront(); }
[[nodiscard]] String Trim() const
{
size_t start = m_string.find_first_not_of(" \t\n\r");
if (start == std::string::npos) start = 0;
size_t end = m_string.find_last_not_of(" \t\n\r");
if (end == std::string::npos) end = m_string.size();
return { m_string.substr(start, end - start + 1) };
}
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<String> Split(const std::string_view& delimiter) const
{
std::vector<String> 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<String, String> 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<String, String> 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<std::string_view> SplitAsStringViews(const std::string_view& delimiter) const
{
std::vector<std::string_view> 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<std::string_view, std::string_view>
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<std::string_view, std::string_view>
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 constexpr int64_t OctToInt(const std::string_view& string)
{
int64_t result = 0;
for (size_t i = 0; i < 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;
}
int64_t OctToInt() const { return OctToInt(m_string); }
static constexpr int64_t HexToInt(const std::string_view& 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;
}
int64_t HexToInt() const { return HexToInt(m_string); }
static constexpr bool IsUrl(const std::string_view& str)
{
return str.find("http://") == 0 || str.find("https://") == 0 || str.find("ftp://") == 0;
}
bool IsUrl() const { return IsUrl(m_string); }
template<typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
static constexpr std::string_view GetOrdinal(T number)
{
if (number <= 0) return "";
else if (number == 1) return "st";
else if (number == 2) return "nd";
else if (number == 3) return "rd";
return "th";
}
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<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> 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<std::string::const_iterator> crbegin() const { return m_string.crbegin(); }
std::reverse_iterator<std::string::const_iterator> crend() const { return m_string.crend(); }
private:
std::string m_string;
};
template<typename T> String operator+(const T& lhs, const String& rhs) noexcept { return String(lhs) + rhs; }
}