Compare commits
	
		
			2 Commits
		
	
	
		
			3940f53231
			...
			1af3ca19ab
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						1af3ca19ab | |
| 
							
							
								
								 | 
						09fcc613c7 | 
| 
						 | 
					@ -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])
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
							if (cstr[size()] != '\0')
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ErrorOr<void> String::resize(size_type new_size, char init_c)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (m_size == new_size)
 | 
				
			||||||
 | 
								return {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// expanding
 | 
				
			||||||
 | 
							if (m_size < new_size)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			m_data[size] = '\0';
 | 
								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 {};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (size > m_size)
 | 
							
 | 
				
			||||||
 | 
							// shrink general -> sso
 | 
				
			||||||
 | 
							if (!has_sso() && fits_in_sso(new_size))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			TRY(ensure_capacity(size + 1));
 | 
								char* data = m_storage.get<GeneralStorage>().data;
 | 
				
			||||||
			for (size_type i = m_size; i < size; i++)
 | 
								m_storage = SSOStorage();
 | 
				
			||||||
				m_data[i] = ch;
 | 
								memcpy(m_storage.get<SSOStorage>().storage, data, new_size);
 | 
				
			||||||
			m_data[size] = '\0';
 | 
								deallocator(data);
 | 
				
			||||||
			m_size = size;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		m_size = size;
 | 
					
 | 
				
			||||||
 | 
							m_size = new_size;
 | 
				
			||||||
 | 
							data()[m_size] = '\0';
 | 
				
			||||||
		return {};
 | 
							return {};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ErrorOr<void> String::reserve(size_type size)
 | 
						ErrorOr<void> String::reserve(size_type new_size)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		TRY(ensure_capacity(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 {};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							GeneralStorage& storage = m_storage.get<GeneralStorage>();
 | 
				
			||||||
 | 
							if (storage.capacity == m_size)
 | 
				
			||||||
 | 
								return {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							char* new_data = (char*)allocator(m_size + 1);
 | 
				
			||||||
 | 
							if (new_data == nullptr)
 | 
				
			||||||
 | 
								return BAN::Error::from_errno(ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(new_data, storage.data, m_size);
 | 
				
			||||||
 | 
							deallocator(storage.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							storage.capacity = m_size;
 | 
				
			||||||
 | 
							storage.data = new_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return {};
 | 
							return {};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StringView String::sv() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return StringView(*this);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool String::empty() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_size == 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	String::size_type String::size() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_size;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <BAN/Traits.h>
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace BAN
 | 
					namespace BAN
 | 
				
			||||||
| 
						 | 
					@ -14,5 +15,6 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue