Files
nostalgia/deps/ox/src/ox/std/string.hpp
Gary Talent 95a69b72b5
All checks were successful
Build / build (push) Successful in 2m36s
[ox/std] Fix String::c_str to always retrun a valid C str
2024-05-29 20:51:15 -05:00

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;
};
}