[ox/std] Add support for custom allocators in Vector
This commit is contained in:
		
							
								
								
									
										225
									
								
								deps/ox/src/ox/std/vector.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										225
									
								
								deps/ox/src/ox/std/vector.hpp
									
									
									
									
										vendored
									
									
								
							| @@ -8,6 +8,8 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include "array.hpp" | ||||||
|  | #include "concepts.hpp" | ||||||
| #include "bit.hpp" | #include "bit.hpp" | ||||||
| #include "error.hpp" | #include "error.hpp" | ||||||
| #include "initializerlist.hpp" | #include "initializerlist.hpp" | ||||||
| @@ -20,71 +22,103 @@ | |||||||
|  |  | ||||||
| namespace ox { | namespace ox { | ||||||
|  |  | ||||||
|  | template<typename PlatSpec> | ||||||
|  | struct VectorMemMap { | ||||||
|  | 	typename PlatSpec::size_t size = 0; | ||||||
|  | 	typename PlatSpec::size_t cap = 0; | ||||||
|  | 	typename PlatSpec::PtrType items = 0; | ||||||
|  | 	uint8_t allocator = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename PlatSpec> | ||||||
|  | [[nodiscard]] | ||||||
|  | constexpr auto sizeOf(const VectorMemMap<PlatSpec> &t) noexcept { | ||||||
|  | 	constexpr auto padding = [](std::size_t size, std::size_t al) { | ||||||
|  | 		return size - size % al; | ||||||
|  | 	}; | ||||||
|  | 	std::size_t size = 0; | ||||||
|  | 	size += sizeof(t.size); | ||||||
|  | 	size += padding(size, PlatSpec::alignOf(t.cap)); | ||||||
|  | 	size += sizeof(t.cap); | ||||||
|  | 	size += padding(size, PlatSpec::alignOf(t.items)); | ||||||
|  | 	size += sizeof(t.items); | ||||||
|  | 	size += padding(size, PlatSpec::alignOf(t.allocator)); | ||||||
|  | 	size += sizeof(t.allocator); | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename PlatSpec> | ||||||
|  | [[nodiscard]] | ||||||
|  | constexpr auto alignOf(const VectorMemMap<PlatSpec>&) noexcept { | ||||||
|  | 	const typename PlatSpec::size_t i = 0; | ||||||
|  | 	return PlatSpec::alignOf(i); | ||||||
|  | } | ||||||
|  |  | ||||||
| namespace detail { | namespace detail { | ||||||
|  |  | ||||||
| template<typename T, std::size_t Size> | template<typename T, typename Allocator, std::size_t Size = 1> | ||||||
| struct VectorAllocator { | struct VectorAllocator { | ||||||
| 	private: | 	private: | ||||||
| 		std::allocator<T> m_allocator; | 		ox::Array<AllocAlias<T>, Size> m_data = {}; | ||||||
| 		AllocAlias<T> m_data[Size] = {}; | 		Allocator m_allocator; | ||||||
| 	public: | 	public: | ||||||
| 		constexpr VectorAllocator() noexcept = default; | 		constexpr VectorAllocator() noexcept = default; | ||||||
| 		constexpr VectorAllocator(const VectorAllocator&) noexcept = default; | 		constexpr VectorAllocator(const VectorAllocator&) noexcept = default; | ||||||
| 		constexpr VectorAllocator(VectorAllocator&&) noexcept = default; | 		constexpr VectorAllocator(VectorAllocator&&) noexcept = default; | ||||||
| 	protected: |  | ||||||
| 		constexpr void allocate(T **items, std::size_t cap) noexcept { | 		constexpr void allocate(T **items, std::size_t cap) noexcept { | ||||||
| 			// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr | 			// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr | ||||||
| 			if (std::is_constant_evaluated() || cap > Size) { | 			if (std::is_constant_evaluated() || cap > Size) { | ||||||
| 				*items = m_allocator.allocate(cap); | 				*items = m_allocator.allocate(cap); | ||||||
| 			} else { | 			} else { | ||||||
| 				*items = reinterpret_cast<T*>(m_data); | 				*items = reinterpret_cast<T*>(m_data.data()); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		constexpr void moveConstructItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept { | 		constexpr void moveConstructItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept { | ||||||
| 			// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, | 			// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, | ||||||
| 			// try removing it later | 			// try removing it later | ||||||
| 			if (!std::is_constant_evaluated() && cap <= Size && count <= Size) { | 			if (cap <= Size && count <= Size) { | ||||||
| 				const auto dstItems = reinterpret_cast<T*>(m_data); | 				const auto dstItems = reinterpret_cast<T*>(m_data.data()); | ||||||
| 				const auto srcItems = reinterpret_cast<T*>(src.m_data); | 				const auto srcItems = reinterpret_cast<T*>(src.m_data.data()); | ||||||
| 				for (auto i = 0u; i < count; ++i) { | 				for (auto i = 0u; i < count; ++i) { | ||||||
| 					std::construct_at<T>(&dstItems[i], std::move(srcItems[i])); | 					std::construct_at<T>(&dstItems[i], std::move(srcItems[i])); | ||||||
| 				} | 				} | ||||||
| 				*items = reinterpret_cast<T*>(m_data); | 				*items = reinterpret_cast<T*>(m_data.data()); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		constexpr void moveItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept { | 		constexpr void moveItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept { | ||||||
| 			// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, | 			// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, | ||||||
| 			// try removing it later | 			// try removing it later | ||||||
| 			if (!std::is_constant_evaluated() && cap <= Size && count <= Size) { | 			if (cap <= Size && count <= Size) { | ||||||
| 				const auto dstItems = reinterpret_cast<T*>(m_data); | 				const auto dstItems = reinterpret_cast<T*>(m_data.data()); | ||||||
| 				const auto srcItems = reinterpret_cast<T*>(src.m_data); | 				const auto srcItems = reinterpret_cast<T*>(src.m_data.data()); | ||||||
| 				for (std::size_t i = 0; i < count; ++i) { | 				for (std::size_t i = 0; i < count; ++i) { | ||||||
| 					dstItems[i] = std::move(srcItems[i]); | 					dstItems[i] = std::move(srcItems[i]); | ||||||
| 				} | 				} | ||||||
| 				*items = reinterpret_cast<T*>(m_data); | 				*items = reinterpret_cast<T*>(m_data.data()); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		constexpr void deallocate(T *items, std::size_t cap) noexcept { | 		constexpr void deallocate(T *items, std::size_t cap) noexcept { | ||||||
| 			// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr | 			// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr | ||||||
| 			if (std::is_constant_evaluated() || (items && static_cast<void*>(items) != static_cast<void*>(m_data))) { | 			if (std::is_constant_evaluated() || (items && static_cast<void*>(items) != static_cast<void*>(m_data.data()))) { | ||||||
| 				m_allocator.deallocate(items, cap); | 				m_allocator.deallocate(items, cap); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template<typename T> | template<typename T, typename Allocator> | ||||||
| struct VectorAllocator<T, 0> { | struct VectorAllocator<T, Allocator, 0> { | ||||||
| 	private: | 	private: | ||||||
| 		std::allocator<T> m_allocator; | 		Allocator m_allocator; | ||||||
| 	public: | 	public: | ||||||
| 		constexpr VectorAllocator() noexcept = default; | 		constexpr VectorAllocator() noexcept = default; | ||||||
| 		constexpr VectorAllocator(const VectorAllocator&) noexcept = default; | 		constexpr VectorAllocator(const VectorAllocator&) noexcept = default; | ||||||
| 		constexpr VectorAllocator(VectorAllocator&&) noexcept = default; | 		constexpr VectorAllocator(VectorAllocator&&) noexcept = default; | ||||||
| 	protected: |  | ||||||
| 		constexpr void allocate(T **items, std::size_t cap) noexcept { | 		constexpr void allocate(T **items, std::size_t cap) noexcept { | ||||||
| 			*items = m_allocator.allocate(cap); | 			*items = m_allocator.allocate(cap); | ||||||
| 		} | 		} | ||||||
| @@ -107,8 +141,8 @@ struct VectorAllocator<T, 0> { | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize = 0> | template<typename T, std::size_t SmallVectorSize = 0, typename Allocator = std::allocator<T>> | ||||||
| class Vector: detail::VectorAllocator<T, SmallVectorSize> { | class Vector { | ||||||
|  |  | ||||||
| 	public: | 	public: | ||||||
| 		using value_type = T; | 		using value_type = T; | ||||||
| @@ -223,6 +257,7 @@ class Vector: detail::VectorAllocator<T, SmallVectorSize> { | |||||||
| 		std::size_t m_size = 0; | 		std::size_t m_size = 0; | ||||||
| 		std::size_t m_cap = 0; | 		std::size_t m_cap = 0; | ||||||
| 		T *m_items = nullptr; | 		T *m_items = nullptr; | ||||||
|  | 		detail::VectorAllocator<T, Allocator, SmallVectorSize> m_allocator; | ||||||
|  |  | ||||||
| 	public: | 	public: | ||||||
| 		constexpr Vector() noexcept = default; | 		constexpr Vector() noexcept = default; | ||||||
| @@ -378,61 +413,61 @@ class Vector: detail::VectorAllocator<T, SmallVectorSize> { | |||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize, typename RefType, bool reverse> | template<typename T, std::size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse> | ||||||
| using VectorIt = typename Vector<T, SmallVectorSize>::template iterator<RefType, reverse>; | using VectorIt = typename Vector<T, SmallVectorSize, Allocator>::template iterator<RefType, reverse>; | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize, typename RefType, bool reverse> | template<typename T, std::size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse> | ||||||
| constexpr VectorIt<T, SmallVectorSize, RefType, reverse> operator+(std::size_t n, const VectorIt<T, SmallVectorSize, RefType, reverse> &a) { | constexpr VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> operator+(std::size_t n, const VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> &a) { | ||||||
| 	return a + n; | 	return a + n; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize>::Vector(std::size_t size) noexcept { | constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexcept { | ||||||
| 	m_size = size; | 	m_size = size; | ||||||
| 	m_cap = m_size; | 	m_cap = m_size; | ||||||
| 	this->allocate(&m_items, m_cap); | 	m_allocator.allocate(&m_items, m_cap); | ||||||
| 	for (std::size_t i = 0; i < size; ++i) { | 	for (std::size_t i = 0; i < size; ++i) { | ||||||
| 		std::construct_at(&m_items[i]); | 		std::construct_at(&m_items[i]); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize>::Vector(std::initializer_list<T> list) noexcept { | constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept { | ||||||
| 	for (auto &item : list) { | 	for (auto &item : list) { | ||||||
| 		emplace_back(item); | 		emplace_back(item); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize>::Vector(const Vector &other) { | constexpr Vector<T, SmallVectorSize, Allocator>::Vector(const Vector &other) { | ||||||
| 	m_size = other.m_size; | 	m_size = other.m_size; | ||||||
| 	m_cap = other.m_cap; | 	m_cap = other.m_cap; | ||||||
| 	this->allocate(&m_items, other.m_cap); | 	m_allocator.allocate(&m_items, other.m_cap); | ||||||
| 	for (std::size_t i = 0; i < m_size; ++i) { | 	for (std::size_t i = 0; i < m_size; ++i) { | ||||||
| 		std::construct_at(&m_items[i], other.m_items[i]); | 		std::construct_at(&m_items[i], other.m_items[i]); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize>::Vector(Vector &&other) noexcept { | constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept { | ||||||
| 	m_size = other.m_size; | 	m_size = other.m_size; | ||||||
| 	m_cap = other.m_cap; | 	m_cap = other.m_cap; | ||||||
| 	m_items = other.m_items; | 	m_items = other.m_items; | ||||||
| 	this->moveConstructItemsFrom(&m_items, other, m_size, m_cap); | 	m_allocator.moveConstructItemsFrom(&m_items, other.m_allocator, m_size, m_cap); | ||||||
| 	other.m_size = 0; | 	other.m_size = 0; | ||||||
| 	other.m_cap = 0; | 	other.m_cap = 0; | ||||||
| 	other.m_items = nullptr; | 	other.m_items = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize>::~Vector() { | constexpr Vector<T, SmallVectorSize, Allocator>::~Vector() { | ||||||
| 	clear(); | 	clear(); | ||||||
| 	this->deallocate(m_items, m_cap); | 	m_allocator.deallocate(m_items, m_cap); | ||||||
| 	m_items = nullptr; | 	m_items = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr bool Vector<T, SmallVectorSize>::operator==(const Vector &other) const { | constexpr bool Vector<T, SmallVectorSize, Allocator>::operator==(const Vector &other) const { | ||||||
| 	if (m_size != other.m_size) { | 	if (m_size != other.m_size) { | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -444,15 +479,15 @@ constexpr bool Vector<T, SmallVectorSize>::operator==(const Vector &other) const | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize> &Vector<T, SmallVectorSize>::operator=(const Vector &other) { | constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(const Vector &other) { | ||||||
| 	if (this != &other) { | 	if (this != &other) { | ||||||
| 		clear(); | 		clear(); | ||||||
| 		this->deallocate(m_items, m_cap); | 		m_allocator.deallocate(m_items, m_cap); | ||||||
| 		m_items = nullptr; | 		m_items = nullptr; | ||||||
| 		m_size = other.m_size; | 		m_size = other.m_size; | ||||||
| 		m_cap = other.m_cap; | 		m_cap = other.m_cap; | ||||||
| 		this->allocate(&m_items, other.m_cap); | 		m_allocator.allocate(&m_items, other.m_cap); | ||||||
| 		for (std::size_t i = 0; i < m_size; i++) { | 		for (std::size_t i = 0; i < m_size; i++) { | ||||||
| 			std::construct_at(&m_items[i], other.m_items[i]); | 			std::construct_at(&m_items[i], other.m_items[i]); | ||||||
| 		} | 		} | ||||||
| @@ -460,15 +495,15 @@ constexpr Vector<T, SmallVectorSize> &Vector<T, SmallVectorSize>::operator=(cons | |||||||
| 	return *this; | 	return *this; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Vector<T, SmallVectorSize> &Vector<T, SmallVectorSize>::operator=(Vector &&other) noexcept { | constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(Vector &&other) noexcept { | ||||||
| 	if (this != &other) { | 	if (this != &other) { | ||||||
| 		clear(); | 		clear(); | ||||||
| 		this->deallocate(m_items, m_cap); | 		m_allocator.deallocate(m_items, m_cap); | ||||||
| 		m_size = other.m_size; | 		m_size = other.m_size; | ||||||
| 		m_cap = other.m_cap; | 		m_cap = other.m_cap; | ||||||
| 		m_items = other.m_items; | 		m_items = other.m_items; | ||||||
| 		this->moveItemsFrom(&m_items, other, m_size, m_cap); | 		m_allocator.moveItemsFrom(&m_items, other.m_allocator, m_size, m_cap); | ||||||
| 		other.m_size = 0; | 		other.m_size = 0; | ||||||
| 		other.m_cap = 0; | 		other.m_cap = 0; | ||||||
| 		other.m_items = nullptr; | 		other.m_items = nullptr; | ||||||
| @@ -476,18 +511,18 @@ constexpr Vector<T, SmallVectorSize> &Vector<T, SmallVectorSize>::operator=(Vect | |||||||
| 	return *this; | 	return *this; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr T &Vector<T, SmallVectorSize>::operator[](std::size_t i) noexcept { | constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept { | ||||||
| 	return m_items[i]; | 	return m_items[i]; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr const T &Vector<T, SmallVectorSize>::operator[](std::size_t i) const noexcept { | constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept { | ||||||
| 	return m_items[i]; | 	return m_items[i]; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| Result<T&> Vector<T, SmallVectorSize>::front() noexcept { | Result<T&> Vector<T, SmallVectorSize, Allocator>::front() noexcept { | ||||||
| 	if (!m_size) { | 	if (!m_size) { | ||||||
| 		AllocAlias<T> v; | 		AllocAlias<T> v; | ||||||
| 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | ||||||
| @@ -495,8 +530,8 @@ Result<T&> Vector<T, SmallVectorSize>::front() noexcept { | |||||||
| 	return m_items[0]; | 	return m_items[0]; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| Result<const T&> Vector<T, SmallVectorSize>::front() const noexcept { | Result<const T&> Vector<T, SmallVectorSize, Allocator>::front() const noexcept { | ||||||
| 	if (!m_size) { | 	if (!m_size) { | ||||||
| 		AllocAlias<T> v; | 		AllocAlias<T> v; | ||||||
| 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | ||||||
| @@ -504,8 +539,8 @@ Result<const T&> Vector<T, SmallVectorSize>::front() const noexcept { | |||||||
| 	return m_items[0]; | 	return m_items[0]; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Result<T&> Vector<T, SmallVectorSize>::back() noexcept { | constexpr Result<T&> Vector<T, SmallVectorSize, Allocator>::back() noexcept { | ||||||
| 	if (!m_size) { | 	if (!m_size) { | ||||||
| 		AllocAlias<T> v; | 		AllocAlias<T> v; | ||||||
| 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | ||||||
| @@ -513,8 +548,8 @@ constexpr Result<T&> Vector<T, SmallVectorSize>::back() noexcept { | |||||||
| 	return m_items[m_size - 1]; | 	return m_items[m_size - 1]; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Result<const T&> Vector<T, SmallVectorSize>::back() const noexcept { | constexpr Result<const T&> Vector<T, SmallVectorSize, Allocator>::back() const noexcept { | ||||||
| 	if (!m_size) { | 	if (!m_size) { | ||||||
| 		AllocAlias<T> v; | 		AllocAlias<T> v; | ||||||
| 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | 		return {*reinterpret_cast<T*>(&v), OxError(1)}; | ||||||
| @@ -522,18 +557,18 @@ constexpr Result<const T&> Vector<T, SmallVectorSize>::back() const noexcept { | |||||||
| 	return m_items[m_size - 1]; | 	return m_items[m_size - 1]; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr std::size_t Vector<T, SmallVectorSize>::size() const noexcept { | constexpr std::size_t Vector<T, SmallVectorSize, Allocator>::size() const noexcept { | ||||||
| 	return m_size; | 	return m_size; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr bool Vector<T, SmallVectorSize>::empty() const noexcept { | constexpr bool Vector<T, SmallVectorSize, Allocator>::empty() const noexcept { | ||||||
| 	return !m_size; | 	return !m_size; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::clear() { | constexpr void Vector<T, SmallVectorSize, Allocator>::clear() { | ||||||
| 	if constexpr(is_class<T>()) { | 	if constexpr(is_class<T>()) { | ||||||
| 		for (std::size_t i = 0; i < m_size; ++i) { | 		for (std::size_t i = 0; i < m_size; ++i) { | ||||||
| 			m_items[i].~T(); | 			m_items[i].~T(); | ||||||
| @@ -542,8 +577,8 @@ constexpr void Vector<T, SmallVectorSize>::clear() { | |||||||
| 	m_size = 0; | 	m_size = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::resize(std::size_t size) { | constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) { | ||||||
| 	if (m_cap < size) { | 	if (m_cap < size) { | ||||||
| 		expandCap(size); | 		expandCap(size); | ||||||
| 	} | 	} | ||||||
| @@ -559,8 +594,8 @@ constexpr void Vector<T, SmallVectorSize>::resize(std::size_t size) { | |||||||
| 	m_size = size; | 	m_size = size; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr bool Vector<T, SmallVectorSize>::contains(const T &v) const { | constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(const T &v) const { | ||||||
| 	for (std::size_t i = 0; i < m_size; i++) { | 	for (std::size_t i = 0; i < m_size; i++) { | ||||||
| 		if (m_items[i] == v) { | 		if (m_items[i] == v) { | ||||||
| 			return true; | 			return true; | ||||||
| @@ -569,8 +604,8 @@ constexpr bool Vector<T, SmallVectorSize>::contains(const T &v) const { | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::insert(std::size_t pos, std::size_t cnt, const T &val) { | constexpr void Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, std::size_t cnt, const T &val) { | ||||||
| 	// TODO: insert should ideally have its own expandCap | 	// TODO: insert should ideally have its own expandCap | ||||||
| 	if (m_size + cnt > m_cap) { | 	if (m_size + cnt > m_cap) { | ||||||
| 		expandCap(m_cap ? m_size + cnt : initialSize); | 		expandCap(m_cap ? m_size + cnt : initialSize); | ||||||
| @@ -588,8 +623,8 @@ constexpr void Vector<T, SmallVectorSize>::insert(std::size_t pos, std::size_t c | |||||||
| 	++m_size; | 	++m_size; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::insert(std::size_t pos, const T &val) { | constexpr void Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, const T &val) { | ||||||
| 	// TODO: insert should ideally have its own expandCap | 	// TODO: insert should ideally have its own expandCap | ||||||
| 	if (m_size == m_cap) { | 	if (m_size == m_cap) { | ||||||
| 		expandCap(m_cap ? m_cap * 2 : initialSize); | 		expandCap(m_cap ? m_cap * 2 : initialSize); | ||||||
| @@ -605,19 +640,19 @@ constexpr void Vector<T, SmallVectorSize>::insert(std::size_t pos, const T &val) | |||||||
| 	++m_size; | 	++m_size; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| template<typename... Args> | template<typename... Args> | ||||||
| constexpr T &Vector<T, SmallVectorSize>::emplace_back(Args&&... args) { | constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args) { | ||||||
| 	if (m_size == m_cap) { | 	if (m_size == m_cap) { | ||||||
| 		expandCap(m_cap ? m_cap * 2 : initialSize); | 		expandCap(m_cap ? m_cap * 2 : initialSize); | ||||||
| 	} | 	} | ||||||
| 	auto out = std::construct_at(&m_items[m_size], forward<Args>(args)...); | 	auto out = std::construct_at(&m_items[m_size], ox::forward<Args>(args)...); | ||||||
| 	++m_size; | 	++m_size; | ||||||
| 	return *out; | 	return *out; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::push_back(const T &item) { | constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(const T &item) { | ||||||
| 	if (m_size == m_cap) { | 	if (m_size == m_cap) { | ||||||
| 		expandCap(m_cap ? m_cap * 2 : initialSize); | 		expandCap(m_cap ? m_cap * 2 : initialSize); | ||||||
| 	} | 	} | ||||||
| @@ -625,19 +660,19 @@ constexpr void Vector<T, SmallVectorSize>::push_back(const T &item) { | |||||||
| 	++m_size; | 	++m_size; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::pop_back() { | constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() { | ||||||
| 	--m_size; | 	--m_size; | ||||||
| 	m_items[m_size].~T(); | 	m_items[m_size].~T(); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Result<typename Vector<T, SmallVectorSize>::template iterator<T&, T*, false>> Vector<T, SmallVectorSize>::erase(const iterator<> &pos) { | constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>> Vector<T, SmallVectorSize, Allocator>::erase(const iterator<> &pos) { | ||||||
| 	return erase(pos.offset()); | 	return erase(pos.offset()); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Result<typename Vector<T, SmallVectorSize>::template iterator<T&, T*, false>> Vector<T, SmallVectorSize>::erase(std::size_t pos) { | constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>> Vector<T, SmallVectorSize, Allocator>::erase(std::size_t pos) { | ||||||
| 	if (pos >= m_size) { | 	if (pos >= m_size) { | ||||||
| 		return OxError(1, "Vector::erase failed: pos is greater than Vector size"); | 		return OxError(1, "Vector::erase failed: pos is greater than Vector size"); | ||||||
| 	} | 	} | ||||||
| @@ -649,8 +684,8 @@ constexpr Result<typename Vector<T, SmallVectorSize>::template iterator<T&, T*, | |||||||
| 	return begin() + pos; | 	return begin() + pos; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr Error Vector<T, SmallVectorSize>::unordered_erase(std::size_t pos) { | constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size_t pos) { | ||||||
| 	if (pos >= m_size) { | 	if (pos >= m_size) { | ||||||
| 		return OxError(1); | 		return OxError(1); | ||||||
| 	} | 	} | ||||||
| @@ -660,20 +695,28 @@ constexpr Error Vector<T, SmallVectorSize>::unordered_erase(std::size_t pos) { | |||||||
| 	return OxError(0); | 	return OxError(0); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, std::size_t SmallVectorSize> | template<typename T, std::size_t SmallVectorSize, typename Allocator> | ||||||
| constexpr void Vector<T, SmallVectorSize>::expandCap(std::size_t cap) { | constexpr void Vector<T, SmallVectorSize, Allocator>::expandCap(std::size_t cap) { | ||||||
| 	const auto oldItems = m_items; | 	const auto oldItems = m_items; | ||||||
| 	const auto oldCap = m_cap; | 	const auto oldCap = m_cap; | ||||||
| 	m_cap = cap; | 	m_cap = cap; | ||||||
| 	this->allocate(&m_items, cap); | 	m_allocator.allocate(&m_items, cap); | ||||||
| 	if (oldItems) { // move over old items | 	if (oldItems) { // move over old items | ||||||
| 		const auto itRange = ox::min(cap, m_size); | 		const auto itRange = ox::min(cap, m_size); | ||||||
| 		for (std::size_t i = 0; i < itRange; ++i) { | 		for (std::size_t i = 0; i < itRange; ++i) { | ||||||
| 			std::construct_at(&m_items[i], std::move(oldItems[i])); | 			std::construct_at(&m_items[i], std::move(oldItems[i])); | ||||||
| 			oldItems[i].~T(); | 			oldItems[i].~T(); | ||||||
| 		} | 		} | ||||||
| 		this->deallocate(oldItems, oldCap); | 		m_allocator.deallocate(oldItems, oldCap); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | template<typename PlatSpec, typename T> | ||||||
|  | [[nodiscard]] | ||||||
|  | constexpr auto alignOf(const Vector<T>&) noexcept { | ||||||
|  | 	const typename PlatSpec::size_t i = 0; | ||||||
|  | 	return PlatSpec::alignOf(i); | ||||||
|  | } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user