banan-os/BAN/include/BAN/String.h

143 lines
3.4 KiB
C++

#pragma once
#include <BAN/Errors.h>
#include <BAN/Formatter.h>
#include <BAN/ForwardList.h>
#include <BAN/Hash.h>
#include <BAN/Iterators.h>
namespace BAN
{
class String
{
public:
using size_type = size_t;
using iterator = IteratorSimple<char, String>;
using const_iterator = ConstIteratorSimple<char, String>;
static constexpr size_type sso_capacity = 15;
public:
String();
String(const String&);
String(String&&);
String(StringView);
~String();
template<typename... Args>
static String formatted(const char* format, const Args&... args);
String& operator=(const String&);
String& operator=(String&&);
String& operator=(StringView);
ErrorOr<void> push_back(char);
ErrorOr<void> insert(char, size_type);
ErrorOr<void> insert(StringView, size_type);
ErrorOr<void> append(StringView);
void pop_back();
void remove(size_type);
void clear();
const_iterator begin() const { return const_iterator(data()); }
iterator begin() { return iterator(data()); }
const_iterator end() const { return const_iterator(data() + size()); }
iterator end() { return iterator(data() + size()); }
char front() const { ASSERT(m_size > 0); return data()[0]; }
char& front() { ASSERT(m_size > 0); return data()[0]; }
char back() const { ASSERT(m_size > 0); return data()[m_size - 1]; }
char& back() { ASSERT(m_size > 0); return data()[m_size - 1]; }
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
bool operator==(const String&) const;
bool operator==(StringView) const;
bool operator==(const char*) const;
ErrorOr<void> resize(size_type, char = '\0');
ErrorOr<void> reserve(size_type);
ErrorOr<void> shrink_to_fit();
StringView sv() const { return StringView(data(), size()); }
bool empty() const { return m_size == 0; }
size_type size() const { return m_size; }
size_type capacity() const;
char* data();
const char* data() const;
private:
ErrorOr<void> ensure_capacity(size_type);
bool has_sso() const;
bool fits_in_sso() const { return fits_in_sso(m_size); }
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
private:
struct SSOStorage
{
char data[sso_capacity + 1] {};
};
struct GeneralStorage
{
size_type capacity { 0 };
char* data { nullptr };
};
private:
union {
SSOStorage sso_storage;
GeneralStorage general_storage;
} m_storage { .sso_storage = SSOStorage() };
size_type m_size : sizeof(size_type) * 8 - 1 { 0 };
size_type m_has_sso : 1 { true };
};
template<typename... Args>
String String::formatted(const char* format, const Args&... args)
{
String result;
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
return result;
}
template<>
struct hash<String>
{
hash_t operator()(const String& string) const
{
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
constexpr hash_t FNV_prime = 0x01000193;
hash_t hash = FNV_offset_basis;
for (String::size_type i = 0; i < string.size(); i++)
{
hash *= FNV_prime;
hash ^= (uint8_t)string[i];
}
return hash;
}
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const String& string, const ValueFormat&)
{
for (String::size_type i = 0; i < string.size(); i++)
putc(string[i]);
}
}