571 lines
16 KiB
C++
571 lines
16 KiB
C++
/*
|
|
* Copyright 2015 - 2024 gary@drinkingtea.net
|
|
*
|
|
* 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
|
|
|
|
#if __has_include(<string>)
|
|
#include <string>
|
|
#endif
|
|
|
|
#include "algorithm.hpp"
|
|
#include "ignore.hpp"
|
|
#include "memops.hpp"
|
|
#include "serialize.hpp"
|
|
#include "strconv.hpp"
|
|
#include "stringliteral.hpp"
|
|
#include "stringview.hpp"
|
|
#include "strops.hpp"
|
|
#include "vector.hpp"
|
|
|
|
namespace ox {
|
|
|
|
template<typename Integer>
|
|
constexpr ox::IString<21> itoa(Integer v) noexcept;
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
class BasicString {
|
|
private:
|
|
Vector<char, SmallStringSize_v> m_buff;
|
|
|
|
public:
|
|
static constexpr auto SmallStringSize = SmallStringSize_v;
|
|
constexpr BasicString() noexcept;
|
|
|
|
constexpr explicit BasicString(std::size_t cap) noexcept;
|
|
|
|
constexpr explicit BasicString(const char *str) noexcept;
|
|
|
|
constexpr explicit BasicString(const char8_t *str) noexcept;
|
|
|
|
constexpr BasicString(const char *str, std::size_t size) noexcept;
|
|
|
|
constexpr explicit BasicString(StringLiteral const&str) noexcept;
|
|
|
|
constexpr explicit BasicString(CRStringView str) noexcept;
|
|
|
|
constexpr explicit BasicString(BasicString const&) noexcept;
|
|
|
|
constexpr BasicString(BasicString&&) noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr auto begin() noexcept {
|
|
return m_buff.begin();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto end() noexcept {
|
|
return m_buff.end();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto begin() const noexcept {
|
|
return m_buff.begin();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto end() const noexcept {
|
|
return m_buff.end();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto cbegin() const noexcept {
|
|
return m_buff.begin();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto cend() const noexcept {
|
|
return m_buff.end();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto rbegin() noexcept {
|
|
return m_buff.rbegin();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto rend() noexcept {
|
|
return m_buff.rend();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto rbegin() const noexcept {
|
|
return m_buff.rbegin();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto rend() const noexcept {
|
|
return m_buff.rend();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto crbegin() const noexcept {
|
|
return m_buff.rbegin();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto crend() const noexcept {
|
|
return m_buff.rend();
|
|
}
|
|
|
|
constexpr BasicString &operator=(const char *str) noexcept;
|
|
|
|
constexpr BasicString &operator=(char c) noexcept;
|
|
|
|
constexpr BasicString &operator=(int i) noexcept;
|
|
|
|
constexpr BasicString &operator=(int64_t i) noexcept;
|
|
|
|
constexpr BasicString &operator=(uint64_t i) noexcept;
|
|
|
|
constexpr BasicString &operator=(const BasicString &src) noexcept;
|
|
|
|
constexpr BasicString &operator=(BasicString &&src) noexcept;
|
|
|
|
constexpr BasicString &operator=(CRStringView src) noexcept;
|
|
|
|
constexpr BasicString &operator+=(const char *str) noexcept;
|
|
|
|
constexpr BasicString &operator+=(char *str) noexcept;
|
|
|
|
constexpr BasicString &operator+=(char c) noexcept;
|
|
|
|
constexpr BasicString &operator+=(Integer_c auto i) noexcept;
|
|
|
|
constexpr BasicString &operator+=(StringView src) noexcept;
|
|
|
|
constexpr BasicString &operator+=(BasicString const&src) noexcept;
|
|
|
|
constexpr BasicString operator+(const char *str) const noexcept;
|
|
|
|
constexpr BasicString operator+(char *str) const noexcept;
|
|
|
|
constexpr BasicString operator+(char c) const noexcept;
|
|
|
|
constexpr BasicString operator+(Integer_c auto i) const noexcept;
|
|
|
|
constexpr BasicString operator+(CRStringView src) const noexcept;
|
|
|
|
constexpr BasicString operator+(BasicString const&src) const noexcept;
|
|
|
|
constexpr bool operator==(const char *other) const noexcept;
|
|
|
|
constexpr bool operator==(OxString_c auto const&other) const noexcept;
|
|
|
|
constexpr bool operator!=(const char *other) const noexcept;
|
|
|
|
constexpr bool operator!=(OxString_c auto const&other) const noexcept;
|
|
|
|
constexpr bool operator<(BasicString const&other) const noexcept;
|
|
|
|
constexpr bool operator>(BasicString const&other) const noexcept;
|
|
|
|
constexpr bool operator<=(BasicString const&other) const noexcept;
|
|
|
|
constexpr bool operator>=(BasicString const&other) const noexcept;
|
|
|
|
constexpr char operator[](std::size_t i) const noexcept;
|
|
|
|
constexpr char &operator[](std::size_t i) noexcept;
|
|
|
|
constexpr Error append(const char *str, std::size_t strLen) noexcept {
|
|
auto currentLen = len();
|
|
m_buff.resize(m_buff.size() + strLen);
|
|
ox::listcpy(&m_buff[currentLen], str, strLen);
|
|
// make sure last element is a null terminator
|
|
m_buff[currentLen + strLen] = 0;
|
|
// this can't fail, but it returns an Error to match BString::append
|
|
return OxError(0);
|
|
}
|
|
|
|
constexpr Error append(ox::StringView sv) noexcept {
|
|
return append(sv.data(), sv.len());
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr BasicString substr(std::size_t pos) const noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr BasicString substr(std::size_t begin, std::size_t end) const noexcept;
|
|
|
|
constexpr void resize(size_t sz) noexcept {
|
|
++sz;
|
|
m_buff.resize(sz);
|
|
m_buff[sz - 1] = 0;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr const char *data() const noexcept {
|
|
return m_buff.data();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr char *data() noexcept {
|
|
return m_buff.data();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr const char *c_str() const noexcept {
|
|
return static_cast<const char*>(m_buff.data());
|
|
}
|
|
|
|
[[nodiscard]]
|
|
inline explicit operator const char*() const {
|
|
return c_str();
|
|
}
|
|
|
|
#if __has_include(<string>)
|
|
[[nodiscard]]
|
|
inline std::string toStdString() const {
|
|
return c_str();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
inline explicit operator std::string() const {
|
|
return c_str();
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Returns the number of characters in this string.
|
|
*/
|
|
[[nodiscard]]
|
|
constexpr std::size_t len() const noexcept;
|
|
|
|
/**
|
|
* Returns the number of bytes used for this string.
|
|
*/
|
|
[[nodiscard]]
|
|
constexpr std::size_t bytes() const noexcept;
|
|
|
|
private:
|
|
constexpr void set(CRStringView str) noexcept;
|
|
|
|
constexpr void set(const char8_t *str) noexcept;
|
|
};
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString() noexcept {
|
|
m_buff.resize(1);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) {}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str) noexcept {
|
|
set(str);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(const char8_t *str) noexcept {
|
|
set(str);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size_t size) noexcept {
|
|
m_buff.resize(size + 1);
|
|
ox::listcpy(m_buff.data(), str, size);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept:
|
|
BasicString(StringView{str.data(), str.len()}) {
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(CRStringView str) noexcept {
|
|
set(str);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(const BasicString &other) noexcept {
|
|
m_buff = other.m_buff;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v>::BasicString(BasicString &&other) noexcept: m_buff(std::move(other.m_buff)) {
|
|
other.m_buff.resize(1);
|
|
other.m_buff[0] = 0;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(const char *str) noexcept {
|
|
set(str);
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(char c) noexcept {
|
|
ox::Array<char, 2> str{c, 0};
|
|
set(str.data());
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int i) noexcept {
|
|
this->operator=(static_cast<int64_t>(i));
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
|
|
set(ox::itoa(i));
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
|
|
set(ox::itoa(i));
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(const BasicString &src) noexcept {
|
|
if (this != &src) {
|
|
set(src);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(BasicString &&src) noexcept {
|
|
if (this != &src) {
|
|
m_buff = std::move(src.m_buff);
|
|
src.m_buff.resize(1);
|
|
src.m_buff[0] = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(CRStringView src) noexcept {
|
|
set(src);
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(const char *str) noexcept {
|
|
std::size_t strLen = ox::strlen(str);
|
|
std::ignore = append(str, strLen);
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(char *str) noexcept {
|
|
return *this += static_cast<const char*>(str);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(char c) noexcept {
|
|
const char str[] = {c, 0};
|
|
return this->operator+=(str);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
|
|
auto const str = ox::itoa(i);
|
|
return this->operator+=(str.c_str());
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
|
|
std::size_t strLen = s.bytes();
|
|
std::ignore = append(s.data(), strLen);
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
|
|
std::ignore = append(src.c_str(), src.len());
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
|
|
const std::size_t strLen = ox::strlen(str);
|
|
const auto currentLen = len();
|
|
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
|
|
cpy.m_buff.resize(m_buff.size() + strLen);
|
|
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
|
|
ox::listcpy(&cpy.m_buff[currentLen], str, strLen);
|
|
// make sure last element is a null terminator
|
|
cpy.m_buff[currentLen + strLen] = 0;
|
|
return cpy;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(char *str) const noexcept {
|
|
return *this + static_cast<const char*>(str);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(char c) const noexcept {
|
|
const char str[] = {c, 0};
|
|
return *this + str;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
|
|
auto const str = ox::itoa(i);
|
|
return *this + str;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(CRStringView src) const noexcept {
|
|
const std::size_t strLen = src.len();
|
|
const auto currentLen = len();
|
|
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
|
|
cpy.m_buff.resize(m_buff.size() + strLen);
|
|
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
|
|
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
|
|
return cpy;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
|
|
const std::size_t strLen = src.len();
|
|
const auto currentLen = len();
|
|
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
|
|
cpy.m_buff.resize(m_buff.size() + strLen);
|
|
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
|
|
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
|
|
return cpy;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) const noexcept {
|
|
bool retval = true;
|
|
for (auto i = 0u; i < m_buff.size() && (m_buff[i] || other[i]); ++i) {
|
|
if (m_buff[i] != other[i]) {
|
|
retval = false;
|
|
break;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
|
|
return ox::StringView(*this) == ox::StringView(other);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator!=(const char *other) const noexcept {
|
|
return !operator==(other);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator!=(OxString_c auto const&other) const noexcept {
|
|
return !operator==(other);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator<(BasicString const&other) const noexcept {
|
|
return ox::strcmp(c_str(), other.c_str()) < 0;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator>(BasicString const&other) const noexcept {
|
|
return ox::strcmp(c_str(), other.c_str()) > 0;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator<=(BasicString const&other) const noexcept {
|
|
return ox::strcmp(c_str(), other.c_str()) < 1;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr bool BasicString<SmallStringSize_v>::operator>=(BasicString const&other) const noexcept {
|
|
return ox::strcmp(c_str(), other.c_str()) > -1;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr char BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
|
|
return m_buff[i];
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr char &BasicString<SmallStringSize_v>::operator[](std::size_t i) noexcept {
|
|
return m_buff[i];
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t pos) const noexcept {
|
|
return BasicString(m_buff.data() + pos, m_buff.size() - pos - 1);
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t begin, std::size_t end) const noexcept {
|
|
const auto src = m_buff.data() + begin;
|
|
const auto size = end - begin;
|
|
BasicString<SmallStringSize_v> out(size);
|
|
const auto buff = out.data();
|
|
ox::listcpy(buff, src, size);
|
|
buff[size] = 0;
|
|
return out;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
|
|
return m_buff.size();
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
|
|
return m_buff.size() - 1;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr void BasicString<SmallStringSize_v>::set(CRStringView str) noexcept {
|
|
std::size_t const strBytes = str.bytes();
|
|
m_buff.resize(strBytes + 1);
|
|
copy_n(str.data(), strBytes, m_buff.data());
|
|
*m_buff.back().value = 0;
|
|
}
|
|
|
|
template<std::size_t SmallStringSize_v>
|
|
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
|
|
std::size_t strBytes = ox::strlen(str) + 1;
|
|
m_buff.resize(strBytes);
|
|
ox::listcpy(m_buff.data(), str, strBytes);
|
|
*m_buff.back().value = 0;
|
|
}
|
|
|
|
extern template class BasicString<8>;
|
|
|
|
using String = BasicString<8>;
|
|
using CRString = String const&;
|
|
|
|
|
|
[[nodiscard]]
|
|
constexpr ox::String toString(ox::CRStringView sv) noexcept {
|
|
return ox::String(sv);
|
|
}
|
|
|
|
|
|
template<typename PlatSpec, std::size_t SmallStringSize_v>
|
|
[[nodiscard]]
|
|
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
|
|
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
|
|
return sizeOf<PlatSpec>(&v);
|
|
}
|
|
|
|
template<typename PlatSpec, std::size_t SmallStringSize_v>
|
|
[[nodiscard]]
|
|
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
|
|
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
|
|
return alignOf<PlatSpec>(&v);
|
|
}
|
|
|
|
template<size_t sz>
|
|
struct MaybeView<ox::BasicString<sz>> {
|
|
using type = ox::StringView;
|
|
};
|
|
|
|
}
|