// // Created by Patrick Maschek on 19.01.2024. // #ifndef UDIFF_CONST_LIST_H_ #define UDIFF_CONST_LIST_H_ #include #include #include #include namespace cc { template class const_list_node; template class _const_list_iterator_base { protected: 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 { return *_curr; } constexpr virtual const N* operator->() const noexcept { return _curr; } constexpr virtual _const_list_iterator_base &operator++() noexcept = 0; constexpr virtual _const_list_iterator_base &operator--() noexcept = 0; constexpr virtual _const_list_iterator_base &operator++(int) & noexcept = 0; constexpr virtual _const_list_iterator_base &operator--(int) & noexcept = 0; constexpr bool operator==(const _const_list_iterator_base &other) { return _curr == other._curr; } }; template class _const_list_iterator : public _const_list_iterator_base { using _Base = _const_list_iterator_base; 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 override { return *_Base::_curr; } constexpr N* operator->() const override { return _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 override { auto tmp = *this; _Base::_curr == _Base::_curr->_next; return tmp; } constexpr _const_list_iterator operator--(int) & noexcept override { auto tmp = *this; _Base::_curr == _Base::_curr->_prev; return tmp; } }; template class _const_const_list_iterator : public _const_list_iterator_base { using _Base = _const_list_iterator_base; 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_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 override { auto tmp = *this; _Base::_curr == _Base::_curr->_next; return tmp; } constexpr _const_const_list_iterator operator--(int) & noexcept override { auto tmp = *this; _Base::_curr == _Base::_curr->_prev; return tmp; } }; template class const_list { private: static consteval void asserts() { static_assert(std::is_base_of_v, 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; using const_iterator = _const_const_list_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; private: Node *_start = nullptr; Node *_end = nullptr; 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> 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> init) noexcept; constexpr void assign(size_type count, const value_type& value) noexcept; template constexpr void assign(InputIt first, InputIt last); constexpr void assign(std::initializer_list values); [[nodiscard]] constexpr reference front() noexcept{ return *_start; } [[nodiscard]] constexpr const_reference front() const noexcept { return *_start; } [[nodiscard]] constexpr reference back() noexcept { return _end; } [[nodiscard]] constexpr const_reference back() const noexcept { return _end; } [[nodiscard]] constexpr iterator begin() noexcept { return iterator(_start); }; [[nodiscard]] constexpr const_iterator begin() const noexcept { return const_iterator(_start); }; [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return const_iterator(_start); }; [[nodiscard]] constexpr iterator end() noexcept { return iterator(); }; [[nodiscard]] constexpr const_iterator end() const noexcept { return const_iterator(); }; [[nodiscard]] constexpr const_iterator cend() const noexcept { return const_iterator(); }; [[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); }; [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return std::reverse_iterator(end()); }; [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return std::reverse_iterator(end()); }; [[nodiscard]] constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); }; [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return std::reverse_iterator(begin()); }; [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return std::reverse_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, const value_type& value); constexpr iterator insert(const_iterator pos, value_type&& value); constexpr iterator insert(const_iterator pos, size_type count, const value_type& value); template constexpr iterator insert(const_iterator pos, InputIt first, InputIt last); constexpr iterator insert(const_iterator pos, std::initializer_list values); template 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 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 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 constexpr void merge(const_list& other, Compare comp); template 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 size_type remove_if(UnaryPredicate p); void reverse() noexcept; size_type unique(); template constexpr size_type unique(BinaryPredicate p); constexpr void sort(); template void sort(Compare comp); }; template class const_list_node { private: static consteval void asserts() { static_assert(std::is_base_of_v, D>, "Template parameter has to be a subclass of const_list_node<*self*>"); } private: const_list_node *_prev = nullptr; const_list_node *_next = nullptr; const_list *_owner = nullptr; void (*_delete_cb)() = nullptr; public: constexpr const_list_node() noexcept { asserts(); } virtual constexpr ~const_list_node(); constexpr void on_delete(void (*cb)()); private: void notify_delete(); friend class const_list; friend class _const_list_iterator_base; }; template constexpr bool operator==(const const_list& lhs, const const_list& rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template constexpr auto operator<=>(const const_list& lhs, const const_list& rhs) { return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template constexpr void swap(const const_list& lhs, const const_list& rhs) { lhs.swap(rhs); } template constexpr const_list::size_type erase(const_list& c, const N& value) { c.remove(value); } template constexpr const_list::size_type erase(const_list& c, Pred pred) { c.remove_if(pred); } template constexpr const_list::const_list(const_list &&other) noexcept : _start(other._start), _end(other._end), _size(other._size) { asserts(); for (auto node : other) { node._owner = this; } other._size = 0; other._start = nullptr; other._end = nullptr; } template constexpr const_list::const_list(std::initializer_list> init) noexcept : _start(std::addressof(init.begin()->get())), _end(std::addressof(std::prev(init.end())->get())), _size(init.size()) { asserts(); auto prev = init.begin(); prev->get()._owner = this; for (auto it = std::next(init.begin()); it != init.end(); ++it) { prev->get()._next = std::addressof(it->get()); it->get()._prev = std::addressof(prev->get()); it->get()._owner = this; prev = it; } } template constexpr const_list::~const_list() { clear(); } template constexpr const_list &const_list::operator=(const_list &&other) noexcept { for (auto node : other) { node._owner = this; } other._size = 0; other._start = nullptr; other._end = nullptr; return *this; } template constexpr const_list &const_list::operator=(std::initializer_list> init) noexcept { *this = const_list(init); return *this; } template constexpr const_list_node::~const_list_node() { if (_delete_cb) (*_delete_cb)(); _owner->remove(*this); } template constexpr void const_list_node::on_delete(void (*cb)()) { _delete_cb = cb; } template void const_list_node::notify_delete() { if (_delete_cb) (*_delete_cb)(); } } // cc #endif //UDIFF_CONST_LIST_H_