const_container/include/const_list.h

427 lines
14 KiB
C++

//
// Created by Patrick Maschek on 19.01.2024.
//
#ifndef UDIFF_CONST_LIST_H_
#define UDIFF_CONST_LIST_H_
#include <concepts>
#include <functional>
#include <initializer_list>
#include <iterator>
namespace cc {
template<typename D>
class const_list_node;
template<typename Node>
class const_list;
template<typename N>
class _const_list_iterator_base {
protected:
const_list_node<N> *_curr = nullptr;
public:
constexpr _const_list_iterator_base() noexcept = default;
constexpr explicit _const_list_iterator_base(N *curr) noexcept : _curr(curr) {}
constexpr _const_list_iterator_base(const _const_list_iterator_base& other) noexcept : _curr(other._curr) {}
constexpr virtual const N& operator*() const noexcept { return *dynamic_cast<N*>(_curr); }
constexpr virtual const N* operator->() const noexcept { return dynamic_cast<N*>(_curr); }
constexpr virtual const_list_node<N>* node() const { return _curr; }
constexpr virtual _const_list_iterator_base &operator++() noexcept { return *this; };
constexpr virtual _const_list_iterator_base &operator--() noexcept { return *this; };
constexpr bool operator==(const _const_list_iterator_base &other) const { return _curr == other._curr; }
protected:
constexpr _const_list_iterator_base(const_list_node<N> *tail) : _curr(tail) {}
friend class const_list<N>;
};
template<typename N>
class _const_list_iterator : public _const_list_iterator_base<N> {
using _Base = _const_list_iterator_base<N>;
public:
constexpr _const_list_iterator() noexcept : _Base() {}
constexpr explicit _const_list_iterator(N *curr) noexcept : _Base(curr) {}
constexpr _const_list_iterator(const _Base& other) noexcept : _Base(other) {}
constexpr N& operator*() const noexcept override { return *dynamic_cast<N*>(_Base::_curr); }
constexpr N* operator->() const noexcept override { return dynamic_cast<N*>(_Base::_curr); }
constexpr _const_list_iterator &operator++() noexcept override { _Base::_curr = _Base::_curr->_next; return *this; }
constexpr _const_list_iterator &operator--() noexcept override { _Base::_curr = _Base::_curr->_prev; return *this; }
constexpr _const_list_iterator operator++(int) noexcept { auto tmp = *this; _Base::_curr = _Base::_curr->_next; return tmp; }
constexpr _const_list_iterator operator--(int) noexcept { auto tmp = *this; _Base::_curr = _Base::_curr->_prev; return tmp; }
};
template<typename N>
class _const_const_list_iterator : public _const_list_iterator_base<N> {
using _Base = _const_list_iterator_base<N>;
public:
constexpr _const_const_list_iterator() : _Base() {}
constexpr explicit _const_const_list_iterator(N *curr) : _Base(curr) {}
constexpr _const_const_list_iterator(const _Base& other) noexcept : _Base(other) {}
constexpr const N* node() noexcept override { return _Base::node(); }
constexpr _const_const_list_iterator &operator++() noexcept override { _Base::_curr = _Base::_curr->_next; return *this; }
constexpr _const_const_list_iterator &operator--() noexcept override { _Base::_curr = _Base::_curr->_prev; return *this; }
constexpr _const_const_list_iterator operator++(int) noexcept { auto tmp = *this; _Base::_curr = _Base::_curr->_next; return tmp; }
constexpr _const_const_list_iterator operator--(int) noexcept { auto tmp = *this; _Base::_curr = _Base::_curr->_prev; return tmp; }
};
template<typename Node>
class const_list {
private:
static consteval void asserts() {
static_assert(std::is_base_of_v<const_list_node<Node>, Node>, "Can only create const_list with elements derived from const_list_node");
}
public:
using value_type = Node;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type *;
using const_pointer = const value_type *;
using iterator = _const_list_iterator<Node>;
using const_iterator = _const_const_list_iterator<Node>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
const_list_node<Node> _tail;
std::size_t _size = 0;
public:
constexpr const_list() noexcept { asserts(); };
constexpr const_list(const const_list&) = delete;
constexpr const_list(const_list&& other) noexcept;
constexpr const_list(std::initializer_list<std::reference_wrapper<value_type>> init) noexcept;
constexpr ~const_list();
constexpr const_list& operator=(const const_list&) = delete;
constexpr const_list& operator=(const_list&& other) noexcept;
constexpr const_list& operator=(std::initializer_list<std::reference_wrapper<value_type>> init) noexcept;
constexpr void assign(std::initializer_list<std::reference_wrapper<value_type>> init) noexcept;
[[nodiscard]] constexpr reference front() noexcept{ return dynamic_cast<Node&>(_tail._next); }
[[nodiscard]] constexpr const_reference front() const noexcept { return dynamic_cast<Node&>(_tail._next); }
[[nodiscard]] constexpr reference back() noexcept { return dynamic_cast<Node&>(_tail._prev); }
[[nodiscard]] constexpr const_reference back() const noexcept { return dynamic_cast<Node&>(_tail._prev); }
[[nodiscard]] constexpr iterator begin() noexcept { return iterator(_tail._next); };
[[nodiscard]] constexpr const_iterator begin() const noexcept { return const_iterator(_tail._next); };
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return const_iterator(_tail._next); };
[[nodiscard]] constexpr iterator end() noexcept { return iterator(&_tail); };
[[nodiscard]] constexpr const_iterator end() const noexcept { return const_iterator(&_tail); };
[[nodiscard]] constexpr const_iterator cend() const noexcept { return const_iterator(&_tail); };
[[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator<iterator>(end()); };
[[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return std::reverse_iterator<const_iterator>(end()); };
[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return std::reverse_iterator<const_iterator>(end()); };
[[nodiscard]] constexpr reverse_iterator rend() noexcept { return std::reverse_iterator<iterator>(begin()); };
[[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return std::reverse_iterator<const_iterator>(begin()); };
[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return std::reverse_iterator<const_iterator>(begin()); };
[[nodiscard]] constexpr bool empty() const noexcept { return _size == 0; }
[[nodiscard]] constexpr size_type max_size() const noexcept { return SIZE_MAX; }
void clear() noexcept;
constexpr iterator insert(const_iterator pos, value_type& value);
constexpr iterator insert(const_iterator pos, std::initializer_list<std::reference_wrapper<value_type>> values);
template<typename ...Args>
constexpr iterator emplace(const_iterator pos, Args&&... args);
constexpr iterator erase(const_iterator pos);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void push_back(const value_type& value);
constexpr void push_back(value_type&& value);
template<typename ...Args>
constexpr reference emplace_back(Args&&... args);
constexpr void pop_back();
constexpr void push_front(const value_type& value);
constexpr void push_front(value_type&& value);
template<typename ...Args>
constexpr reference emplace_front(Args&&... args);
constexpr void pop_front();
constexpr void resize(size_type count);
constexpr void resize(size_type count, const value_type& value);
constexpr void swap(const_list& other) noexcept;
constexpr void merge(const_list& other);
constexpr void merge(const_list&& other);
template<typename Compare>
constexpr void merge(const_list& other, Compare comp);
template<typename Compare>
constexpr void merge(const_list&& other, Compare comp);
constexpr void splice(const_iterator pos, const_list& other);
constexpr void splice(const_iterator pos, const_list&& other);
constexpr void splice(const_iterator pos, const_list& other, const_iterator it);
constexpr void splice(const_iterator pos, const_list&& other, const_iterator it);
constexpr void splice(const_iterator pos, const_list& other, const_iterator first, const_iterator last);
constexpr void splice(const_iterator pos, const_list&& other, const_iterator first, const_iterator last);
constexpr size_type remove(const value_type& value);
template<typename UnaryPredicate>
size_type remove_if(UnaryPredicate p);
void reverse() noexcept;
size_type unique();
template<typename BinaryPredicate>
constexpr size_type unique(BinaryPredicate p);
constexpr void sort();
template<typename Compare>
void sort(Compare comp);
};
template<typename D>
class const_list_node {
private:
static consteval void asserts() {
static_assert(std::is_base_of_v<const_list_node<D>, D>, "Template parameter has to be a subclass of const_list_node<*self*>");
}
private:
const_list_node *_prev = this;
const_list_node *_next = this;
const_list<D> *_owner = nullptr;
void (*_delete_cb)() = nullptr;
public:
constexpr const_list_node() noexcept { asserts(); }
constexpr const_list_node(const const_list_node& other) noexcept;
constexpr const_list_node(const_list_node&& other) noexcept;
virtual constexpr ~const_list_node();
protected:
constexpr void on_delete(void (*cb)()) noexcept;
private:
constexpr void push_before(const_list_node *node) noexcept;
constexpr void unlink() noexcept;
friend class const_list<D>;
friend class _const_list_iterator_base<D>;
friend class _const_list_iterator<D>;
friend class _const_const_list_iterator<D>;
};
template<typename N1, typename N2>
constexpr bool operator==(const const_list<N1>& lhs,
const const_list<N2>& rhs)
{
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<typename N1, typename N2>
constexpr auto operator<=>(const const_list<N1>& lhs,
const const_list<N2>& rhs)
{
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<typename N>
constexpr void swap(const const_list<N>& lhs,
const const_list<N>& rhs)
{
lhs.swap(rhs);
}
template<typename N>
constexpr const_list<N>::size_type erase(const_list<N>& c, const N& value)
{
c.remove(value);
}
template<typename N, typename Pred>
constexpr const_list<N>::size_type erase(const_list<N>& c, Pred pred)
{
c.remove_if(pred);
}
template<typename Node>
constexpr const_list<Node>::const_list(const_list &&other) noexcept
: _tail(std::move(other._tail)),
_size(other._size)
{
asserts();
for (auto node : other) {
node._owner = this;
}
}
template<typename Node>
constexpr const_list<Node>::const_list(std::initializer_list<std::reference_wrapper<value_type>> init) noexcept
: _tail(),
_size(init.size())
{
asserts();
assign(init);
}
template<typename Node>
constexpr const_list<Node>::~const_list()
{
clear();
}
template<typename Node>
constexpr const_list<Node> &const_list<Node>::operator=(const_list &&other) noexcept
{
for (auto& node : other) {
node._owner = this;
}
_tail = std::move(other._tail);
_size = other._size;
return *this;
}
template<typename Node>
constexpr const_list<Node> &const_list<Node>::operator=(std::initializer_list<std::reference_wrapper<value_type>> init) noexcept
{
assign(init);
return *this;
}
template<typename Node>
constexpr void const_list<Node>::assign(std::initializer_list<std::reference_wrapper<value_type>> init) noexcept
{
clear();
for (auto& value : init) {
_tail.push_before(std::addressof(value.get()));
}
_size += init.size();
}
template<typename Node>
void const_list<Node>::clear() noexcept
{
for (auto node = _tail._next; _tail._next != std::addressof(_tail); ) {
auto next = node->_next;
node->unlink();
node = next;
}
_size = 0;
}
template<typename Node>
constexpr const_list<Node>::iterator const_list<Node>::insert(const_iterator pos, value_type &value)
{
pos->push_before(value);
++_size;
return --pos;
}
template<typename Node>
constexpr const_list<Node>::iterator const_list<Node>::insert(const_list::const_iterator pos,
std::initializer_list<std::reference_wrapper<value_type>> values)
{
auto prev = pos.node();
for (auto& it = values.rbegin(); it != values.rend(); ++it) {
prev->push_before(it->get());
prev = it->get();
}
_size += values.size();
return iterator(prev);
}
template<typename D>
constexpr const_list_node<D>::const_list_node(const const_list_node &other) noexcept
: _delete_cb(other._delete_cb)
{}
template<typename D>
constexpr const_list_node<D>::const_list_node(const_list_node &&other) noexcept
: _prev(other._prev),
_next(other._next),
_delete_cb(other._delete_cb)
{
_prev->_next = this;
_next->_prev = this;
}
template<typename D>
constexpr const_list_node<D>::~const_list_node()
{
if (_delete_cb)
_delete_cb();
unlink();
}
template<typename D>
constexpr void const_list_node<D>::on_delete(void (*cb)()) noexcept
{
_delete_cb = cb;
}
template<typename D>
constexpr void const_list_node<D>::unlink() noexcept
{
if (_delete_cb)
_delete_cb();
_prev->_next = _next;
_next->_prev = _prev;
_next = this;
_prev = this;
_owner = nullptr;
}
template<typename D>
constexpr void const_list_node<D>::push_before(const_list_node *node) noexcept
{
node->_prev = _prev;
node->_next = this;
_prev->_next = node;
_prev = node;
}
} // cc
#endif //UDIFF_CONST_LIST_H_