184 lines
5.4 KiB
C++
184 lines
5.4 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 <c4/substr.hpp>
|
|
#include <c4/substr_fwd.hpp>
|
|
#include <c4/format.hpp>
|
|
#include <c4/charconv.hpp>
|
|
#include <utf8.h>
|
|
#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() = 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;
|
|
}
|
|
|
|
template<typename T> String& operator=(const String& other)
|
|
{
|
|
m_string = other.m_string;
|
|
return *this;
|
|
}
|
|
|
|
template<typename T> String& operator+=(const T& other)
|
|
{
|
|
m_string += other;
|
|
return *this;
|
|
}
|
|
|
|
template<typename T> 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> int operator<=>(const T& other) const { return m_string <=> other; }
|
|
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
|
|
{
|
|
size_t start = m_string.find_first_not_of(" \t\n\r");
|
|
if (start == std::string::npos)
|
|
{
|
|
m_string.clear();
|
|
return *this;
|
|
}
|
|
|
|
size_t end = m_string.find_last_not_of(" \t\n\r");
|
|
|
|
m_string.erase(0, start);
|
|
m_string.resize(end - start + 1);
|
|
|
|
return *this;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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; }
|
|
}
|