130 lines
2.9 KiB
C++
130 lines
2.9 KiB
C++
export module bedrock.foundation:string;
|
|
|
|
import bedrock.numbers;
|
|
import bedrock.semantics;
|
|
import :byte;
|
|
import :buffer;
|
|
import :bytes_iterator;
|
|
import :iterators.enumerate;
|
|
import :iterators.reverse;
|
|
|
|
namespace br {
|
|
|
|
export class String final {
|
|
private:
|
|
BufferView m_data;
|
|
|
|
explicit String(BufferView&& view)
|
|
: m_data(view) {}
|
|
|
|
public:
|
|
friend class StringBuffer;
|
|
|
|
template <usize Size>
|
|
constexpr String(const char (&str)[Size])
|
|
: m_data(reinterpret_cast<const byte*>(&str), Size - 1) {}
|
|
|
|
[[nodiscard]]
|
|
auto byteSize() const noexcept -> usize {
|
|
return m_data.size();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
auto characterLength() const noexcept -> usize {
|
|
usize nCharacters = 0;
|
|
for (auto byte : m_data) {
|
|
if ((byte & 0xc0_b) != 0x80_b) {
|
|
++nCharacters;
|
|
}
|
|
}
|
|
return nCharacters;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
auto isEmpty() const noexcept -> bool {
|
|
return *this == "";
|
|
}
|
|
|
|
[[nodiscard]]
|
|
auto startsWith(const String& str) noexcept -> bool {
|
|
for (auto [byte, i] : str.bytes() | enumerate()) {
|
|
if (m_data[i] != byte) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
auto endsWith(const String& str) noexcept -> bool {
|
|
for (auto [byte, i] : str.bytes() | reverse() | enumerate()) {
|
|
if (m_data[i] != byte) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ====================================================================
|
|
// Implicit conversions
|
|
// ====================================================================
|
|
[[nodiscard]] operator BufferView() const noexcept {
|
|
return m_data;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
auto bytes() const noexcept -> BytesIterator {
|
|
return m_data.bytes();
|
|
}
|
|
|
|
// ====================================================================
|
|
// Moveable
|
|
// ====================================================================
|
|
String(String&& other) noexcept
|
|
: m_data(move(other.m_data)) {}
|
|
|
|
auto operator=(String&& other) noexcept -> String& {
|
|
if (this == &other) {
|
|
m_data = move(other.m_data);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
~String() = default;
|
|
|
|
// ====================================================================
|
|
// Copyable
|
|
// ====================================================================
|
|
String(const String& other) = default;
|
|
|
|
auto operator=(const String& other) noexcept -> String& {
|
|
if (&other != this) {
|
|
m_data = other.m_data;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// ====================================================================
|
|
// Equivalence
|
|
// ====================================================================
|
|
[[nodiscard]]
|
|
auto operator==(const String& other) const noexcept -> bool {
|
|
return m_data == other.m_data;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
auto operator!=(const String& other) const noexcept -> bool {
|
|
return !(*this == other);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct EquivalenceType<String> {
|
|
static constexpr bool is_valid = true;
|
|
};
|
|
|
|
static_assert(Moveable<String>);
|
|
static_assert(Copyable<String>);
|
|
static_assert(Equivalence<String>);
|
|
|
|
} // namespace br
|