Files
Seele/src/Engine/Containers/List.h
T

493 lines
12 KiB
C++
Raw Normal View History

2020-03-13 12:44:33 +01:00
#pragma once
2021-11-01 20:25:16 +01:00
#include <memory_resource>
2024-01-16 19:24:49 +01:00
#include <assert.h>
2021-10-23 00:22:35 +02:00
2020-03-13 12:44:33 +01:00
namespace Seele
{
2021-10-23 00:22:35 +02:00
template <typename T, typename Allocator = std::pmr::polymorphic_allocator<T>>
2020-04-12 15:47:19 +02:00
class List
{
private:
2021-10-23 00:22:35 +02:00
struct Node
{
2024-01-16 19:24:49 +01:00
Node(Node* prev, Node* next, const T& data)
: prev(prev)
, next(next)
, data(std::move(data))
{}
Node(Node* prev, Node* next, T&& data)
: prev(prev)
, next(next)
, data(std::move(data))
{}
2021-10-23 00:22:35 +02:00
Node *prev;
Node *next;
T data;
};
using NodeAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Node>;
2020-04-12 15:47:19 +02:00
public:
2021-10-23 00:22:35 +02:00
template <typename X>
class IteratorBase
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = X;
using difference_type = std::ptrdiff_t;
using reference = X&;
using pointer = X*;
2020-03-13 12:44:33 +01:00
2021-10-23 00:22:35 +02:00
IteratorBase(Node *x = nullptr)
: node(x)
{
}
IteratorBase(const IteratorBase &i)
: node(i.node)
{
}
2023-02-13 14:56:13 +01:00
IteratorBase(IteratorBase&& i) noexcept
2021-10-23 00:22:35 +02:00
: node(std::move(i.node))
{
}
~IteratorBase()
{
}
IteratorBase& operator=(const IteratorBase& other)
{
if(this != &other)
{
node = other.node;
}
return *this;
}
2023-02-13 14:56:13 +01:00
IteratorBase& operator=(IteratorBase&& other) noexcept
2021-10-23 00:22:35 +02:00
{
if(this != &other)
{
node = std::move(other.node);
}
return *this;
}
2024-01-16 19:24:49 +01:00
constexpr reference operator*() const
2021-10-23 00:22:35 +02:00
{
return node->data;
}
2024-01-16 19:24:49 +01:00
constexpr pointer operator->() const
2021-10-23 00:22:35 +02:00
{
return &node->data;
}
2024-01-16 19:24:49 +01:00
constexpr bool operator!=(const IteratorBase &other)
2021-10-23 00:22:35 +02:00
{
return node != other.node;
}
2024-01-16 19:24:49 +01:00
constexpr bool operator==(const IteratorBase &other)
2021-10-23 00:22:35 +02:00
{
return node == other.node;
}
2024-01-16 19:24:49 +01:00
constexpr std::strong_ordering operator<=>(const IteratorBase& other)
{
return node <=> other.node;
}
constexpr IteratorBase &operator--()
2021-10-23 00:22:35 +02:00
{
node = node->prev;
return *this;
}
2024-01-16 19:24:49 +01:00
constexpr IteratorBase operator--(int)
2021-10-23 00:22:35 +02:00
{
IteratorBase tmp(*this);
--*this;
return tmp;
}
2024-01-16 19:24:49 +01:00
constexpr IteratorBase &operator++()
2021-10-23 00:22:35 +02:00
{
node = node->next;
return *this;
}
2024-01-16 19:24:49 +01:00
constexpr IteratorBase operator++(int)
2021-10-23 00:22:35 +02:00
{
IteratorBase tmp(*this);
++*this;
return tmp;
}
2020-03-13 12:44:33 +01:00
2021-10-23 00:22:35 +02:00
private:
Node *node;
friend class List<T>;
};
using Iterator = IteratorBase<T>;
using ConstIterator = IteratorBase<const T>;
using value_type = T;
using allocator_type = Allocator;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = T*;
using const_pointer = const T*;
2020-04-12 15:47:19 +02:00
2021-10-23 00:22:35 +02:00
using iterator = Iterator;
using const_iterator = ConstIterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
List()
: root(nullptr)
, tail(nullptr)
, beginIt(Iterator(root))
, endIt(Iterator(tail))
, _size(0)
2023-01-21 18:43:21 +01:00
, allocator(Allocator())
2021-10-23 00:22:35 +02:00
{
}
2023-01-21 18:43:21 +01:00
explicit List(const Allocator& alloc)
: root(nullptr)
, tail(nullptr)
, beginIt(Iterator(root))
, endIt(Iterator(tail))
, _size(0)
, allocator(alloc)
{
}
List(size_type count, const T& value = T(), const Allocator& alloc = Allocator())
: List(alloc)
{
for(size_type i = 0; i < count; ++i)
{
add(value);
}
}
List(size_type count, const Allocator& alloc = Allocator())
: List(alloc)
{
for(size_type i = 0; i < count; ++i)
{
add(T());
}
}
2021-10-23 00:22:35 +02:00
List(const List& other)
2023-01-21 18:43:21 +01:00
: List(std::allocator_traits<allocator_type>::select_on_container_copy_construction(other.allocator))
{
//TODO: improve
for(const auto& it : other)
{
add(it);
}
}
List(const List& other, const Allocator& alloc)
: List(alloc)
2021-10-23 00:22:35 +02:00
{
//TODO: improve
for(const auto& it : other)
{
add(it);
}
}
List(List&& other)
: root(std::move(other.root))
, tail(std::move(other.tail))
, beginIt(std::move(other.beginIt))
, endIt(std::move(other.endIt))
, _size(std::move(other._size))
2023-01-21 18:43:21 +01:00
, allocator(std::move(other.allocator))
2021-10-23 00:22:35 +02:00
{
2023-12-17 16:16:46 +01:00
other._size = 0;
2023-01-21 18:43:21 +01:00
}
List(List&& other, const Allocator& alloc)
: root(std::move(other.root))
, tail(std::move(other.tail))
, beginIt(std::move(other.beginIt))
, endIt(std::move(other.endIt))
, _size(std::move(other._size))
2024-01-16 19:24:49 +01:00
, allocator(alloc)
2023-01-21 18:43:21 +01:00
{
2023-12-17 16:16:46 +01:00
other._size = 0;
2021-10-23 00:22:35 +02:00
}
~List()
{
clear();
}
List& operator=(const List& other)
{
if(this != &other)
{
2022-01-12 14:40:26 +01:00
clear();
2023-01-21 18:43:21 +01:00
if constexpr (std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value )
{
if (!std::allocator_traits<allocator_type>::is_always_equal::value
&& allocator != other.allocator)
{
clear();
}
allocator = other.allocator;
}
2021-10-23 00:22:35 +02:00
for(const auto& it : other)
{
add(it);
}
2021-11-13 19:28:18 +01:00
markIteratorDirty();
2021-10-23 00:22:35 +02:00
}
return *this;
}
List& operator=(List&& other)
{
if(this != &other)
{
2022-01-12 14:40:26 +01:00
clear();
2023-01-21 18:43:21 +01:00
if constexpr (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
{
allocator = std::move(other.allocator);
}
2021-10-23 00:22:35 +02:00
root = other.root;
tail = other.tail;
beginIt = other.beginIt;
endIt = other.endIt;
_size = other._size;
other._size = 0;
2021-11-13 19:28:18 +01:00
markIteratorDirty();
2021-10-23 00:22:35 +02:00
}
return *this;
}
2021-11-01 20:25:16 +01:00
reference front()
2021-10-23 00:22:35 +02:00
{
return root->data;
}
2021-11-01 20:25:16 +01:00
reference back()
2021-10-23 00:22:35 +02:00
{
return tail->prev->data;
}
void clear()
{
if (empty())
{
return;
}
for (Node *tmp = root; tmp != tail;)
{
tmp = tmp->next;
2022-01-12 14:40:26 +01:00
destroyNode(tmp->prev);
2021-10-23 00:22:35 +02:00
deallocateNode(tmp->prev);
}
deallocateNode(tail);
tail = nullptr;
root = nullptr;
2021-11-24 12:10:23 +01:00
markIteratorDirty();
_size = 0;
2021-10-23 00:22:35 +02:00
}
//Insert at the end
iterator add(const T &value)
{
2022-01-12 14:40:26 +01:00
return addInternal(value);
2021-10-23 00:22:35 +02:00
}
iterator add(T&& value)
{
2022-01-12 14:40:26 +01:00
return addInternal(std::move(value));
2021-10-23 00:22:35 +02:00
}
2021-11-11 20:12:50 +01:00
// takes all elements from other and move-inserts them into
// this, clearing other in the process
2023-01-21 18:43:21 +01:00
void moveElements(List&& other)
2022-01-12 14:40:26 +01:00
{
2021-11-11 20:12:50 +01:00
tail->prev->next = other.root;
other.root->prev = tail->prev;
_size += other._size;
deallocateNode(tail);
tail = other.tail;
other._size = 0;
other.root = nullptr;
other.tail = nullptr;
markIteratorDirty();
other.markIteratorDirty();
}
2021-11-05 00:01:12 +01:00
template<typename... args>
constexpr reference emplace(args... arguments)
{
if (root == nullptr)
{
root = allocateNode();
tail = root;
}
std::allocator_traits<NodeAllocator>::construct(allocator,
tail,
tail->prev,
tail->next,
arguments...);
Node *newTail = allocateNode();
newTail->prev = tail;
newTail->next = nullptr;
tail->next = newTail;
Iterator insertedElement(tail);
tail = newTail;
markIteratorDirty();
_size++;
return insertedElement;
}
2021-11-01 20:25:16 +01:00
// front + popFront
2021-11-19 15:08:56 +01:00
value_type retrieve()
2021-11-01 20:25:16 +01:00
{
2021-11-19 15:08:56 +01:00
value_type temp = std::move(root->data);
2021-11-01 20:25:16 +01:00
popFront();
2021-11-24 12:10:23 +01:00
return temp;
2021-11-01 20:25:16 +01:00
}
2021-10-23 00:22:35 +02:00
iterator remove(iterator pos)
{
_size--;
Node *prev = pos.node->prev;
Node *next = pos.node->next;
if (prev == nullptr)
{
root = next;
}
else
{
prev->next = next;
}
if(next == nullptr)
{
2022-01-12 14:40:26 +01:00
tail = prev;
2021-10-23 00:22:35 +02:00
}
else
{
next->prev = prev;
}
2022-01-12 14:40:26 +01:00
destroyNode(pos.node);
2021-11-05 00:01:12 +01:00
deallocateNode(pos.node);
2021-10-23 00:22:35 +02:00
markIteratorDirty();
return Iterator(next);
}
void popBack()
{
assert(_size > 0);
remove(Iterator(tail->prev));
}
void popFront()
{
assert(_size > 0);
remove(Iterator(root));
}
iterator insert(iterator pos, const T &value)
{
_size++;
if (root == nullptr)
{
root = allocateNode();
root->data = value;
tail = allocateNode();
root->next = tail;
root->prev = nullptr;
tail->prev = root;
tail->next = nullptr;
markIteratorDirty();
return beginIt;
}
Node *tmp = pos.node->prev;
Node *newNode = allocateNode();
2021-11-01 20:25:16 +01:00
initializeNode(newNode, value);
2021-10-23 00:22:35 +02:00
tmp->next = newNode;
newNode->prev = tmp;
newNode->next = pos.node;
pos.node->prev = newNode;
2021-11-13 19:28:18 +01:00
markIteratorDirty();
2021-10-23 00:22:35 +02:00
return Iterator(newNode);
}
iterator find(const T &value)
{
for (Node *i = root; i != tail; i = i->next)
{
if (!(i->data < value) && !(value < i->data))
{
return iterator(i);
}
}
return endIt;
}
2021-11-13 19:28:18 +01:00
bool empty() const
2021-10-23 00:22:35 +02:00
{
return _size == 0;
}
2021-11-13 19:28:18 +01:00
size_type size() const
2021-10-23 00:22:35 +02:00
{
return _size;
}
iterator begin()
{
return beginIt;
}
const_iterator begin() const
{
return cbeginIt;
}
iterator end()
{
return endIt;
}
const_iterator end() const
{
return cendIt;
}
2020-03-13 12:44:33 +01:00
2020-04-12 15:47:19 +02:00
private:
2021-10-23 00:22:35 +02:00
Node* allocateNode()
{
Node* node = allocator.allocate(1);
assert(node != nullptr);
2021-11-01 20:25:16 +01:00
node->prev = nullptr;
node->next = nullptr;
2021-10-23 00:22:35 +02:00
return node;
}
2021-11-01 20:25:16 +01:00
template<typename Type>
void initializeNode(Node* node, Type&& data)
{
std::allocator_traits<NodeAllocator>::construct(allocator,
node,
node->prev,
node->next,
std::forward<Type>(data));
}
2022-01-12 14:40:26 +01:00
void destroyNode(Node* node)
{
std::allocator_traits<NodeAllocator>::destroy(allocator, node);
}
2021-10-23 00:22:35 +02:00
void deallocateNode(Node* node)
{
allocator.deallocate(node, 1);
}
2022-01-12 14:40:26 +01:00
template<typename ValueType>
iterator addInternal(ValueType&& value)
{
if (root == nullptr)
{
root = allocateNode();
tail = root;
}
initializeNode(tail, std::forward<ValueType>(value));
Node* newTail = allocateNode();
newTail->prev = tail;
newTail->next = nullptr;
tail->next = newTail;
Iterator insertedElement(tail);
tail = newTail;
markIteratorDirty();
_size++;
return insertedElement;
}
2021-10-23 00:22:35 +02:00
void markIteratorDirty()
{
beginIt = Iterator(root);
endIt = Iterator(tail);
cbeginIt = ConstIterator(root);
cendIt = ConstIterator(tail);
}
Node *root;
Node *tail;
2022-01-12 14:40:26 +01:00
iterator beginIt;
iterator endIt;
const_iterator cbeginIt;
const_iterator cendIt;
2021-11-05 00:01:12 +01:00
size_type _size;
2021-10-23 00:22:35 +02:00
NodeAllocator allocator;
2020-04-12 15:47:19 +02:00
};
} // namespace Seele