Compare commits

..

No commits in common. "1af3ca19abd24272318ab942122648ced162fcc9" and "3940f532319de4642d83b7c2fded96f5b6c7ffb5" have entirely different histories.

3 changed files with 167 additions and 188 deletions

View File

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

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <BAN/Errors.h> #include <BAN/Errors.h>
#include <BAN/Formatter.h>
#include <BAN/ForwardList.h> #include <BAN/ForwardList.h>
#include <BAN/Formatter.h>
#include <BAN/Hash.h> #include <BAN/Hash.h>
#include <BAN/Iterators.h> #include <BAN/Iterators.h>
@ -15,7 +15,6 @@ 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();
@ -35,26 +34,29 @@ 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(data()); } const_iterator begin() const { return const_iterator(m_data); }
iterator begin() { return iterator(data()); } iterator begin() { return iterator(m_data); }
const_iterator end() const { return const_iterator(data() + size()); } const_iterator end() const { return const_iterator(m_data + m_size); }
iterator end() { return iterator(data() + size()); } iterator end() { return iterator(m_data + m_size); }
char front() const { ASSERT(m_size > 0); return data()[0]; } char front() const { ASSERT(!empty()); return m_data[0]; }
char& front() { ASSERT(m_size > 0); return data()[0]; } char& front() { ASSERT(!empty()); return m_data[0]; }
char back() const { ASSERT(m_size > 0); return data()[m_size - 1]; } char back() const { ASSERT(!empty()); return m_data[m_size - 1]; }
char& back() { ASSERT(m_size > 0); return data()[m_size - 1]; } char& back() { ASSERT(!empty()); return m_data[m_size - 1]; }
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; } char operator[](size_type) const;
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; } char& operator[](size_type);
bool operator==(const String&) const;
bool operator==(StringView) const; bool operator==(StringView) const;
bool operator==(const char*) const; bool operator==(const char*) const;
@ -62,37 +64,24 @@ 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 { return StringView(data(), size()); } StringView sv() const;
bool empty() const { return m_size == 0; } bool empty() const;
size_type size() const { return m_size; } size_type size() const;
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);
bool has_sso() const; ErrorOr<void> copy_impl(StringView);
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:
struct SSOStorage char* m_data = nullptr;
{ size_type m_capacity = 0;
char storage[sso_capacity + 1] {}; size_type m_size = 0;
};
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>