update main #1

Merged
Sinipelto merged 240 commits from Bananymous/banan-os:main into main 2023-11-20 13:20:51 +02:00
2 changed files with 186 additions and 167 deletions
Showing only changes of commit 1af3ca19ab - Show all commits

View File

@ -1,102 +1,108 @@
#include <BAN/Errors.h>
#include <BAN/Math.h>
#include <BAN/Move.h>
#include <BAN/New.h>
#include <BAN/String.h> #include <BAN/String.h>
#include <BAN/StringView.h> #include <BAN/New.h>
#include <BAN/Variant.h>
#include <string.h>
namespace BAN namespace BAN
{ {
String::String() String::String()
{ {
MUST(copy_impl(""sv));
} }
String::String(const String& other) String::String(const String& other)
{ {
MUST(copy_impl(other.sv())); *this = other;
} }
String::String(String&& other) String::String(String&& other)
{ {
move_impl(move(other)); *this = move(other);
} }
String::String(StringView other) String::String(StringView other)
{ {
MUST(copy_impl(other)); *this = other;
} }
String::~String() String::~String()
{ {
BAN::deallocator(m_data); clear();
} }
String& String::operator=(const String& other) String& String::operator=(const String& other)
{ {
MUST(copy_impl(other.sv())); clear();
if (!other.fits_in_sso())
MUST(ensure_capacity(other.size()));
memcpy(data(), other.data(), other.size() + 1);
m_size = other.size();
return *this; return *this;
} }
String& String::operator=(String&& other) String& String::operator=(String&& other)
{ {
BAN::deallocator(m_data); clear();
move_impl(move(other));
if (other.fits_in_sso())
memcpy(data(), other.data(), other.size() + 1);
else
m_storage = other.m_storage.get<GeneralStorage>();
m_size = other.m_size;
other.m_size = 0;
other.m_storage = SSOStorage();
return *this; return *this;
} }
String& String::operator=(StringView other) String& String::operator=(StringView other)
{ {
MUST(copy_impl(other)); clear();
if (!fits_in_sso(other.size()))
MUST(ensure_capacity(other.size()));
memcpy(data(), other.data(), other.size());
m_size = other.size();
data()[m_size] = '\0';
return *this; return *this;
} }
ErrorOr<void> String::push_back(char ch) ErrorOr<void> String::push_back(char c)
{ {
TRY(ensure_capacity(m_size + 2)); TRY(ensure_capacity(m_size + 1));
m_data[m_size] = ch; data()[m_size] = c;
m_size++; m_size++;
m_data[m_size] = '\0'; data()[m_size] = '\0';
return {}; return {};
} }
ErrorOr<void> String::insert(char ch, size_type index) ErrorOr<void> String::insert(char c, size_type index)
{ {
ASSERT(index <= m_size); ASSERT(index <= m_size);
TRY(ensure_capacity(m_size + 1 + 1)); TRY(ensure_capacity(m_size + 1));
memmove(m_data + index + 1, m_data + index, m_size - index); memmove(data() + index + 1, data() + index, m_size - index);
m_data[index] = ch; data()[index] = c;
m_size += 1; m_size++;
m_data[m_size] = '\0'; data()[m_size] = '\0';
return {}; return {};
} }
ErrorOr<void> String::insert(StringView other, size_type index) ErrorOr<void> String::insert(StringView str, size_type index)
{ {
ASSERT(index <= m_size); ASSERT(index <= m_size);
TRY(ensure_capacity(m_size + other.size() + 1)); TRY(ensure_capacity(m_size + str.size()));
memmove(m_data + index + other.size(), m_data + index, m_size - index); memmove(data() + index + str.size(), data() + index, m_size - index);
memcpy(m_data + index, other.data(), other.size()); memcpy(data() + index, str.data(), str.size());
m_size += other.size(); m_size += str.size();
m_data[m_size] = '\0'; data()[m_size] = '\0';
return {}; return {};
} }
ErrorOr<void> String::append(StringView other) ErrorOr<void> String::append(StringView str)
{ {
TRY(ensure_capacity(m_size + other.size() + 1)); TRY(ensure_capacity(m_size + str.size()));
memcpy(m_data + m_size, other.data(), other.size()); memcpy(data() + m_size, str.data(), str.size());
m_size += other.size(); m_size += str.size();
m_data[m_size] = '\0'; data()[m_size] = '\0';
return {};
}
ErrorOr<void> String::append(const String& string)
{
TRY(append(string.sv()));
return {}; return {};
} }
@ -104,159 +110,161 @@ namespace BAN
{ {
ASSERT(m_size > 0); ASSERT(m_size > 0);
m_size--; m_size--;
m_data[m_size] = '\0'; data()[m_size] = '\0';
} }
void String::remove(size_type index) void String::remove(size_type index)
{ {
erase(index, 1); ASSERT(index < m_size);
} memcpy(data() + index, data() + index + 1, m_size - index);
m_size--;
void String::erase(size_type index, size_type count) data()[m_size] = '\0';
{
ASSERT(index + count <= m_size);
memmove(m_data + index, m_data + index + count, m_size - index - count);
m_size -= count;
m_data[m_size] = '\0';
} }
void String::clear() void String::clear()
{ {
if (!has_sso())
{
deallocator(m_storage.get<GeneralStorage>().data);
m_storage = SSOStorage();
}
m_size = 0; m_size = 0;
m_data[0] = '\0'; data()[m_size] = '\0';
} }
char String::operator[](size_type index) const bool String::operator==(StringView str) const
{ {
ASSERT(index < m_size); if (size() != str.size())
return m_data[index];
}
char& String::operator[](size_type index)
{
ASSERT(index < m_size);
return m_data[index];
}
bool String::operator==(const String& other) const
{
if (m_size != other.m_size)
return false; return false;
return memcmp(m_data, other.m_data, m_size) == 0; for (size_type i = 0; i < m_size; i++)
} if (data()[i] != str.data()[i])
bool String::operator==(StringView other) const
{
if (m_size != other.size())
return false;
return memcmp(m_data, other.data(), m_size) == 0;
}
bool String::operator==(const char* other) const
{
for (size_type i = 0; i <= m_size; i++)
if (m_data[i] != other[i])
return false; return false;
return true; return true;
} }
ErrorOr<void> String::resize(size_type size, char ch) bool String::operator==(const char* cstr) const
{ {
if (size < m_size) for (size_type i = 0; i < m_size; i++)
{ if (data()[i] != cstr[i])
m_data[size] = '\0'; return false;
m_size = size; if (cstr[size()] != '\0')
return false;
return true;
} }
else if (size > m_size)
ErrorOr<void> String::resize(size_type new_size, char init_c)
{ {
TRY(ensure_capacity(size + 1)); if (m_size == new_size)
for (size_type i = m_size; i < size; i++) return {};
m_data[i] = ch;
m_data[size] = '\0'; // expanding
m_size = size; if (m_size < new_size)
} {
m_size = size; TRY(ensure_capacity(new_size));
memset(data() + m_size, init_c, new_size - m_size);
m_size = new_size;
data()[m_size] = '\0';
return {}; return {};
} }
ErrorOr<void> String::reserve(size_type size) // shrink general -> sso
if (!has_sso() && fits_in_sso(new_size))
{ {
TRY(ensure_capacity(size)); char* data = m_storage.get<GeneralStorage>().data;
m_storage = SSOStorage();
memcpy(m_storage.get<SSOStorage>().storage, data, new_size);
deallocator(data);
}
m_size = new_size;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> String::reserve(size_type new_size)
{
TRY(ensure_capacity(new_size));
return {}; return {};
} }
ErrorOr<void> String::shrink_to_fit() ErrorOr<void> String::shrink_to_fit()
{ {
size_type temp = m_capacity; if (has_sso())
m_capacity = 0; return {};
auto error_or = ensure_capacity(m_size);
if (error_or.is_error()) if (fits_in_sso())
{ {
m_capacity = temp; char* data = m_storage.get<GeneralStorage>().data;
return error_or; m_storage = SSOStorage();
} memcpy(m_storage.get<SSOStorage>().storage, data, m_size + 1);
deallocator(data);
return {}; return {};
} }
StringView String::sv() const GeneralStorage& storage = m_storage.get<GeneralStorage>();
{ if (storage.capacity == m_size)
return StringView(*this); return {};
}
bool String::empty() const char* new_data = (char*)allocator(m_size + 1);
{ if (new_data == nullptr)
return m_size == 0; return BAN::Error::from_errno(ENOMEM);
}
String::size_type String::size() const memcpy(new_data, storage.data, m_size);
{ deallocator(storage.data);
return m_size;
storage.capacity = m_size;
storage.data = new_data;
return {};
} }
String::size_type String::capacity() const String::size_type String::capacity() const
{ {
return m_capacity; if (has_sso())
return sso_capacity;
return m_storage.get<GeneralStorage>().capacity;
}
char* String::data()
{
if (has_sso())
return m_storage.get<SSOStorage>().storage;
return m_storage.get<GeneralStorage>().data;
} }
const char* String::data() const const char* String::data() const
{ {
return m_data; if (has_sso())
return m_storage.get<SSOStorage>().storage;
return m_storage.get<GeneralStorage>().data;
} }
ErrorOr<void> String::ensure_capacity(size_type size) ErrorOr<void> String::ensure_capacity(size_type new_size)
{ {
if (m_capacity >= size) if (m_size >= new_size || fits_in_sso(new_size))
return {}; return {};
size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
void* new_data = BAN::allocator(new_cap); char* new_data = (char*)allocator(new_size + 1);
if (new_data == nullptr) if (new_data == nullptr)
return Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
if (m_data)
memcpy(new_data, m_data, m_size + 1); memcpy(new_data, data(), m_size + 1);
BAN::deallocator(m_data);
m_data = (char*)new_data; if (has_sso())
m_capacity = new_cap; m_storage = GeneralStorage();
else
deallocator(m_storage.get<GeneralStorage>().data);
auto& storage = m_storage.get<GeneralStorage>();
storage.capacity = new_size;
storage.data = new_data;
return {}; return {};
} }
ErrorOr<void> String::copy_impl(StringView other) bool String::has_sso() const
{ {
TRY(ensure_capacity(other.size() + 1)); return m_storage.has<SSOStorage>();
memcpy(m_data, other.data(), other.size());
m_size = other.size();
m_data[m_size] = '\0';
return {};
}
void String::move_impl(String&& other)
{
m_data = other.m_data;
m_size = other.m_size;
m_capacity = other.m_capacity;
other.m_data = nullptr;
other.m_size = 0;
other.m_capacity = 0;
} }
} }

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <BAN/Errors.h> #include <BAN/Errors.h>
#include <BAN/ForwardList.h>
#include <BAN/Formatter.h> #include <BAN/Formatter.h>
#include <BAN/ForwardList.h>
#include <BAN/Hash.h> #include <BAN/Hash.h>
#include <BAN/Iterators.h> #include <BAN/Iterators.h>
@ -15,6 +15,7 @@ namespace BAN
using size_type = size_t; using size_type = size_t;
using iterator = IteratorSimple<char, String>; using iterator = IteratorSimple<char, String>;
using const_iterator = ConstIteratorSimple<char, String>; using const_iterator = ConstIteratorSimple<char, String>;
static constexpr size_type sso_capacity = 15;
public: public:
String(); String();
@ -34,29 +35,26 @@ namespace BAN
ErrorOr<void> insert(char, size_type); ErrorOr<void> insert(char, size_type);
ErrorOr<void> insert(StringView, size_type); ErrorOr<void> insert(StringView, size_type);
ErrorOr<void> append(StringView); ErrorOr<void> append(StringView);
ErrorOr<void> append(const String&);
void pop_back(); void pop_back();
void remove(size_type); void remove(size_type);
void erase(size_type, size_type);
void clear(); void clear();
const_iterator begin() const { return const_iterator(m_data); } const_iterator begin() const { return const_iterator(data()); }
iterator begin() { return iterator(m_data); } iterator begin() { return iterator(data()); }
const_iterator end() const { return const_iterator(m_data + m_size); } const_iterator end() const { return const_iterator(data() + size()); }
iterator end() { return iterator(m_data + m_size); } iterator end() { return iterator(data() + size()); }
char front() const { ASSERT(!empty()); return m_data[0]; } char front() const { ASSERT(m_size > 0); return data()[0]; }
char& front() { ASSERT(!empty()); return m_data[0]; } char& front() { ASSERT(m_size > 0); return data()[0]; }
char back() const { ASSERT(!empty()); return m_data[m_size - 1]; } char back() const { ASSERT(m_size > 0); return data()[m_size - 1]; }
char& back() { ASSERT(!empty()); return m_data[m_size - 1]; } char& back() { ASSERT(m_size > 0); return data()[m_size - 1]; }
char operator[](size_type) const; char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
char& operator[](size_type); char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
bool operator==(const String&) const;
bool operator==(StringView) const; bool operator==(StringView) const;
bool operator==(const char*) const; bool operator==(const char*) const;
@ -64,24 +62,37 @@ namespace BAN
ErrorOr<void> reserve(size_type); ErrorOr<void> reserve(size_type);
ErrorOr<void> shrink_to_fit(); ErrorOr<void> shrink_to_fit();
StringView sv() const; StringView sv() const { return StringView(data(), size()); }
bool empty() const; bool empty() const { return m_size == 0; }
size_type size() const; size_type size() const { return m_size; }
size_type capacity() const; size_type capacity() const;
char* data();
const char* data() const; const char* data() const;
private: private:
ErrorOr<void> ensure_capacity(size_type); ErrorOr<void> ensure_capacity(size_type);
ErrorOr<void> copy_impl(StringView); bool has_sso() const;
void move_impl(String&&);
bool fits_in_sso() const { return fits_in_sso(m_size); }
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
private: private:
char* m_data = nullptr; struct SSOStorage
size_type m_capacity = 0; {
size_type m_size = 0; char storage[sso_capacity + 1] {};
};
struct GeneralStorage
{
size_type capacity { 0 };
char* data;
};
private:
Variant<SSOStorage, GeneralStorage> m_storage { SSOStorage() };
size_type m_size { 0 };
}; };
template<typename... Args> template<typename... Args>