[ox/std] Add support for custom allocators in Vector
This commit is contained in:
parent
bc98c42be6
commit
c6c18c18d3
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user