282 lines
7.2 KiB
C++
282 lines
7.2 KiB
C++
/*
|
|
* Copyright 2015 - 2022 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
|
|
|
|
#include "memops.hpp"
|
|
#include "stringview.hpp"
|
|
#include "strops.hpp"
|
|
#include "typetraits.hpp"
|
|
|
|
namespace ox {
|
|
|
|
// Bounded String
|
|
template<std::size_t buffLen>
|
|
class BString {
|
|
private:
|
|
char m_buff[buffLen + 1];
|
|
|
|
public:
|
|
constexpr BString() noexcept;
|
|
|
|
constexpr BString(StringView str) noexcept;
|
|
|
|
constexpr BString(const char *str) noexcept;
|
|
|
|
constexpr BString &operator=(CRStringView str) noexcept;
|
|
|
|
constexpr BString &operator=(const char *str) noexcept;
|
|
|
|
constexpr BString &operator=(char *str) noexcept;
|
|
|
|
constexpr BString &operator=(Integer_c auto i) noexcept;
|
|
|
|
constexpr BString &operator+=(const char *str) noexcept;
|
|
|
|
constexpr BString &operator+=(char *str) noexcept;
|
|
|
|
constexpr BString &operator+=(Integer_c auto i) noexcept;
|
|
|
|
constexpr BString &operator+=(StringView s) noexcept;
|
|
|
|
constexpr BString operator+(const char *str) const noexcept;
|
|
|
|
constexpr BString operator+(char *str) const noexcept;
|
|
|
|
constexpr BString operator+(Integer_c auto i) const noexcept;
|
|
|
|
constexpr bool operator==(const char *other) const noexcept;
|
|
|
|
constexpr bool operator==(const OxString_c auto &other) const noexcept;
|
|
|
|
constexpr bool operator!=(const char *other) const noexcept;
|
|
|
|
constexpr bool operator!=(const OxString_c auto &other) 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;
|
|
|
|
[[nodiscard]]
|
|
constexpr const char *data() const noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr char *data() noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr const char *c_str() const noexcept;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* Returns the capacity of bytes for this string.
|
|
*/
|
|
[[nodiscard]]
|
|
constexpr std::size_t cap() const noexcept;
|
|
};
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size>::BString() noexcept: m_buff{{0}} {
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size>::BString(StringView str) noexcept: m_buff{{0}} {
|
|
operator=(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size>::BString(const char *str) noexcept: m_buff{{0}} {
|
|
operator=(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator=(Integer_c auto i) noexcept {
|
|
char str[65] = {};
|
|
ox_itoa(i, str);
|
|
return this->operator=(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator=(ox::CRStringView str) noexcept {
|
|
std::size_t strLen = str.bytes() + 1;
|
|
if (cap() < strLen) {
|
|
strLen = cap();
|
|
}
|
|
ox_memcpy(m_buff, str.data(), strLen);
|
|
// make sure last element is a null terminator
|
|
m_buff[strLen] = 0;
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator=(const char *str) noexcept {
|
|
std::size_t strLen = ox_strlen(str) + 1;
|
|
if (cap() < strLen) {
|
|
strLen = cap();
|
|
}
|
|
ox_memcpy(m_buff, str, strLen);
|
|
// make sure last element is a null terminator
|
|
m_buff[cap()] = 0;
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator=(char *str) noexcept {
|
|
return *this = static_cast<const char*>(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator+=(const char *str) noexcept {
|
|
std::size_t strLen = ox_strlen(str) + 1;
|
|
oxIgnoreError(append(str, strLen));
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator+=(char *str) noexcept {
|
|
return *this += static_cast<const char*>(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator+=(Integer_c auto i) noexcept {
|
|
char str[65] = {};
|
|
ox_itoa(i, str);
|
|
return this->operator+=(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
|
|
std::size_t strLen = s.bytes();
|
|
oxIgnoreError(append(s.data(), strLen));
|
|
return *this;
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> BString<size>::operator+(const char *str) const noexcept {
|
|
auto out = *this;
|
|
std::size_t strLen = ox_strlen(str) + 1;
|
|
oxIgnoreError(out.append(str, strLen));
|
|
return out;
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> BString<size>::operator+(char *str) const noexcept {
|
|
return *this + static_cast<const char*>(str);
|
|
}
|
|
|
|
template<std::size_t size>
|
|
constexpr BString<size> BString<size>::operator+(Integer_c auto i) const noexcept {
|
|
char str[65] = {};
|
|
ox_itoa(i, str);
|
|
return this->operator+(str);
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr bool BString<buffLen>::operator==(const char *other) const noexcept {
|
|
return ox::StringView(*this) == other;
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr bool BString<buffLen>::operator==(const OxString_c auto &other) const noexcept {
|
|
return ox::StringView(*this) == ox::StringView(other);
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr bool BString<buffLen>::operator!=(const char *other) const noexcept {
|
|
return !operator==(other);
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr bool BString<buffLen>::operator!=(const OxString_c auto &other) noexcept {
|
|
return !operator==(other);
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr char BString<buffLen>::operator[](std::size_t i) const noexcept {
|
|
return m_buff[i];
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
|
|
return m_buff[i];
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr Error BString<buffLen>::append(const char *str, std::size_t strLen) noexcept {
|
|
Error err;
|
|
auto currentLen = len();
|
|
if (cap() < currentLen + strLen + 1) {
|
|
strLen = cap() - currentLen;
|
|
err = OxError(1, "Insufficient space for full string");
|
|
}
|
|
ox_strncpy(m_buff + currentLen, str, strLen);
|
|
// make sure last element is a null terminator
|
|
m_buff[currentLen + strLen] = 0;
|
|
return err;
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr const char *BString<buffLen>::data() const noexcept {
|
|
return static_cast<const char*>(m_buff);
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr char *BString<buffLen>::data() noexcept {
|
|
return static_cast<char*>(m_buff);
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr const char *BString<buffLen>::c_str() const noexcept {
|
|
return static_cast<const char*>(m_buff);
|
|
}
|
|
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr std::size_t BString<buffLen>::len() const noexcept {
|
|
std::size_t length = 0;
|
|
for (std::size_t i = 0; i < buffLen; i++) {
|
|
uint8_t b = static_cast<uint8_t>(m_buff[i]);
|
|
if (b) {
|
|
const auto asciiChar = (b & 128) == 0;
|
|
const auto utf8Char = (b & (256 << 6)) == (256 << 6);
|
|
if (asciiChar || utf8Char) {
|
|
length++;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return length;
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr std::size_t BString<buffLen>::bytes() const noexcept {
|
|
std::size_t i = 0;
|
|
for (i = 0; i < buffLen && m_buff[i]; i++);
|
|
return i + 1; // add one for null terminator
|
|
}
|
|
|
|
template<std::size_t buffLen>
|
|
constexpr std::size_t BString<buffLen>::cap() const noexcept {
|
|
return buffLen;
|
|
}
|
|
|
|
}
|