Files
banan-os/BAN/include/BAN/String.h
Bananymous f72fdeeb59 BAN: String now uses union for its sso storage
This allows String to shrink by 8 bytes since Variant's 8 index is
no longer stored in here.

This required me to make Strings max size one bit less, but that
should still be fine. There should never be strings with size of
over half of the computer's address space.
2023-10-30 11:13:16 +02:00

142 lines
3.3 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==(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]);
}
}