diff --git a/CMakeLists.txt b/CMakeLists.txt
index 335fa85..34467a6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,7 +33,7 @@ endif()
set(CMAKE_CXX_STANDARD 20)
-set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/algorithm.tpp" "include/rexy/utility.hpp" "include/rexy/hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/expression.hpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/enum_traits.hpp" "include/rexy/storage_for.hpp" "include/rexy/storage_for.tpp" "include/rexy/visitor.hpp" "include/rexy/string_view.hpp" "include/rexy/string_view.tpp" "include/rexy/format.hpp" "include/rexy/format.tpp")
+set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/algorithm.tpp" "include/rexy/utility.hpp" "include/rexy/hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/expression.hpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/enum_traits.hpp" "include/rexy/storage_for.hpp" "include/rexy/storage_for.tpp" "include/rexy/visitor.hpp" "include/rexy/string_view.hpp" "include/rexy/string_view.tpp" "include/rexy/format.hpp" "include/rexy/format.tpp" "include/rexy/list.hpp" "include/rexy/list.tpp")
if(BUILD_HEADER_ONLY)
set(LIBREXY_BUILT_LIBRARY_HEADERS "")
diff --git a/include/rexy/list.hpp b/include/rexy/list.hpp
new file mode 100644
index 0000000..62fb2a0
--- /dev/null
+++ b/include/rexy/list.hpp
@@ -0,0 +1,211 @@
+/**
+ This file is a part of rexy's general purpose library
+ Copyright (C) 2022 rexy712
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef REXY_LLIST_HPP
+#define REXY_LLIST_HPP
+
+#include //size_t, ptrdiff_t
+#include "allocator.hpp" //TODO
+#include "detail/hasallocator.hpp"
+#include //bidirectional_iterator_tag, reverse_iterator
+#include //allocator_traits
+#include
+#include //pair
+
+namespace rexy{
+
+ template
+ class list;
+
+ namespace detail{
+ struct node_base{
+ node_base* next = nullptr;
+ node_base* prev = nullptr;
+ };
+
+ template
+ struct list_iterator;
+ template
+ struct const_list_iterator;
+ template
+ struct node;
+ }
+
+ template>
+ class list : protected detail::hasallocator::template rebind_alloc>>
+ {
+ private:
+ using node_allocator_type = detail::hasallocator::template rebind_alloc>>;
+
+ public:
+ using value_type = T;
+ using allocator_type = Alloc;
+ 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 = detail::list_iterator;
+ using const_iterator = detail::const_list_iterator;
+ using reverse_iterator = std::reverse_iterator;
+ using const_reverse_iterator = std::reverse_iterator;
+
+ public:
+ using node = detail::node;
+
+ private:
+ detail::node_base m_sentinel = {&m_sentinel, &m_sentinel};
+ size_type m_size = 0;
+
+ public:
+ constexpr list(void) = default;
+ constexpr explicit list(const allocator_type& alloc);
+ REXY_CPP20_CONSTEXPR list(size_type count, const_reference value = value_type(), const allocator_type& = allocator_type());
+ REXY_CPP20_CONSTEXPR explicit list(size_type count, const allocator_type& alloc = allocator_type());
+ template
+ REXY_CPP20_CONSTEXPR list(InputIt first, InputIt last, const allocator_type& alloc = allocator_type());
+ REXY_CPP20_CONSTEXPR list(const list& other, const allocator_type& alloc = allocator_type());
+ REXY_CPP20_CONSTEXPR list(list&& other, const allocator_type& alloc = allocator_type());
+ REXY_CPP20_CONSTEXPR list(std::initializer_list l, const allocator_type& alloc = allocator_type());
+
+ REXY_CPP20_CONSTEXPR ~list(void);
+
+ REXY_CPP20_CONSTEXPR list& operator=(const list& other);
+ REXY_CPP20_CONSTEXPR list& operator=(list&& other);
+ REXY_CPP20_CONSTEXPR list& operator=(std::initializer_list l);
+
+ constexpr bool operator==(const list& other)const noexcept;
+#if __cpp_impl_three_way_comparison
+ constexpr auto operator<=>(const list& other)const noexcept;
+#else
+ constexpr bool operator!=(const list& other)const noexcept;
+ constexpr bool operator<(const list& other)const noexcept;
+ constexpr bool operator<=(const list& other)const noexcept;
+ constexpr bool operator>(const list& other)const noexcept;
+ constexpr bool operator>=(const list& other)const noexcept;
+#endif
+
+ REXY_CPP20_CONSTEXPR void assign(size_type count, const_reference value);
+ template
+ REXY_CPP20_CONSTEXPR void assign(InputIt first, InputIt last);
+ REXY_CPP20_CONSTEXPR void assign(std::initializer_list l);
+
+ constexpr allocator_type get_allocator(void)const noexcept;
+
+ constexpr reference front(void);
+ constexpr const_reference front(void)const;
+ constexpr reference back(void);
+ constexpr const_reference back(void)const;
+
+ constexpr iterator begin(void)noexcept;
+ constexpr const_iterator begin(void)const noexcept;
+ constexpr const_iterator cbegin(void)const noexcept;
+ constexpr iterator end(void)noexcept;
+ constexpr const_iterator end(void)const noexcept;
+ constexpr const_iterator cend(void)const noexcept;
+
+ constexpr iterator next(iterator i)noexcept;
+ constexpr const_iterator next(const_iterator i)noexcept;
+
+ constexpr iterator prev(iterator i)noexcept;
+ constexpr const_iterator prev(const_iterator i)noexcept;
+
+ constexpr reverse_iterator rbegin(void)noexcept;
+ constexpr const_reverse_iterator rbegin(void)const noexcept;
+ constexpr const_reverse_iterator crbegin(void)const noexcept;
+ constexpr reverse_iterator rend(void)noexcept;
+ constexpr const_reverse_iterator rend(void)const noexcept;
+ constexpr const_reverse_iterator crend(void)const noexcept;
+
+ constexpr bool empty(void)const noexcept;
+ constexpr size_type size(void)const noexcept;
+ constexpr size_type max_size(void)const noexcept;
+
+ REXY_CPP20_CONSTEXPR void clear(void)noexcept;
+
+ REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, const_reference value);
+ REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, value_type&& value);
+ REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, size_type count, const_reference value);
+ template
+ REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, InputIt first, InputIt last);
+ REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, std::initializer_list l);
+
+ template
+ REXY_CPP20_CONSTEXPR iterator emplace(const_iterator pos, Args&&... args);
+
+ REXY_CPP20_CONSTEXPR iterator erase(const_iterator pos);
+ REXY_CPP20_CONSTEXPR iterator erase(const_iterator first, const_iterator last);
+
+ REXY_CPP20_CONSTEXPR reference push_back(const_reference value);
+ REXY_CPP20_CONSTEXPR reference push_back(value_type&& value);
+ template
+ REXY_CPP20_CONSTEXPR reference emplace_back(Args&&... args);
+
+ REXY_CPP20_CONSTEXPR void pop_back(void);
+
+ REXY_CPP20_CONSTEXPR reference push_front(const_reference value);
+ REXY_CPP20_CONSTEXPR reference push_front(value_type&& value);
+ template
+ REXY_CPP20_CONSTEXPR reference emplace_front(Args&&... args);
+
+ REXY_CPP20_CONSTEXPR void pop_front(void);
+
+ REXY_CPP20_CONSTEXPR void resize(size_type count);
+ REXY_CPP20_CONSTEXPR void resize(size_type count, value_type value);
+
+ REXY_CPP20_CONSTEXPR void swap(list& other);
+
+ REXY_CPP20_CONSTEXPR void merge(list&& other);
+ template
+ REXY_CPP20_CONSTEXPR void merge(list&& other, Comp comp);
+
+ REXY_CPP20_CONSTEXPR void splice(const_iterator pos, list&& other);
+ REXY_CPP20_CONSTEXPR void splice(const_iterator pos, list&& other, const_iterator it);
+ REXY_CPP20_CONSTEXPR void splice(const_iterator pos, list&& other, const_iterator first, const_iterator last);
+
+ REXY_CPP20_CONSTEXPR size_type remove(const_reference value);
+ template
+ REXY_CPP20_CONSTEXPR size_type remove_if(UnaryPred p);
+
+ REXY_CPP20_CONSTEXPR void reverse(void)noexcept;
+
+ REXY_CPP20_CONSTEXPR size_type unique(void);
+ template
+ REXY_CPP20_CONSTEXPR size_type unique(BinaryPred p);
+
+ REXY_CPP20_CONSTEXPR void sort(void);
+ template
+ REXY_CPP20_CONSTEXPR void sort(Comp comp);
+ private:
+ template
+ iterator mergesort(iterator first, size_type firstlen, Comp comp);
+ std::pair ms_split(iterator it, size_type len);
+
+ static void insert_node_(detail::node_base* prev, detail::node_base* n);
+ static void remove_node_(detail::node_base* rm);
+ static detail::node_base* get_next_then_move_node_(detail::node_base* dest, detail::node_base* n);
+ constexpr auto& sentinel(void){return this->m_sentinel;}
+ constexpr const auto& sentinel(void)const{return this->m_sentinel;}
+ };
+
+}
+
+#include "list.tpp"
+
+#endif
diff --git a/include/rexy/list.tpp b/include/rexy/list.tpp
new file mode 100644
index 0000000..f4ec3fd
--- /dev/null
+++ b/include/rexy/list.tpp
@@ -0,0 +1,657 @@
+/**
+ This file is a part of rexy's general purpose library
+ Copyright (C) 2022 rexy712
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef REXY_LLIST_TPP
+#define REXY_LLIST_TPP
+
+#include //move, swap, forward
+#include //numeric_limits
+#include //lexicographical_compare_three_way, equal
+#include //construct_at, destroy_at
+
+#include "utility.hpp" //sized_constant_iterator
+
+namespace rexy{
+
+ namespace detail{
+ template
+ struct node : public node_base{
+ T data;
+
+ node* next(void)const{return static_cast(node_base::next);}
+ node* prev(void)const{return static_cast(node_base::prev);}
+ };
+
+ template
+ struct list_iterator{
+
+ using value_type = T;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+
+ using node_t = node;
+
+ node_base* current = nullptr;
+
+ constexpr bool operator==(const list_iterator& other)const noexcept{return current == other.current;}
+ constexpr bool operator!=(const list_iterator& other)const noexcept{return current != other.current;}
+ constexpr bool operator==(const const_list_iterator& other)const noexcept{return current == other.nod();}
+ constexpr bool operator!=(const const_list_iterator& other)const noexcept{return current != other.nod();}
+
+ constexpr reference operator*(void){return static_cast(current)->data;}
+ constexpr const_reference operator*(void)const{return static_cast(current)->data;}
+ constexpr pointer operator->(void){return &(static_cast(current)->data);}
+ constexpr const_pointer operator->(void)const{return &(static_cast(current)->data);}
+ constexpr list_iterator& operator++(void){
+ current = current->next;
+ return *this;
+ }
+ constexpr list_iterator operator++(int){
+ list_iterator copy(*this);
+ ++(*this);
+ return copy;
+ }
+ constexpr list_iterator& operator--(void){
+ current = current->prev;
+ return *this;
+ }
+ constexpr list_iterator operator--(int){
+ list_iterator copy(*this);
+ --(*this);
+ return copy;
+ }
+
+ constexpr operator const_list_iterator(void)const{
+ return const_list_iterator{current};
+ }
+
+ list_iterator next(void)const{
+ return list_iterator{current->next};
+ }
+ list_iterator prev(void)const{
+ return list_iterator{current->prev};
+ }
+
+ node_base* nod(void){return current;}
+ node_base* nod(void)const{return current;}
+ };
+ template
+ struct const_list_iterator{
+ template
+ friend class rexy::list;
+
+ using value_type = T;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+
+ using node_t = node;
+
+ const node_base* current = nullptr;
+
+ constexpr bool operator==(const const_list_iterator& other)const noexcept{return current == other.current;}
+ constexpr bool operator!=(const const_list_iterator& other)const noexcept{return current != other.current;}
+ constexpr bool operator==(const list_iterator& other)const noexcept{return current == other.nod();}
+ constexpr bool operator!=(const list_iterator& other)const noexcept{return current != other.nod();}
+
+ constexpr const_reference operator*(void){return static_cast(current)->data;}
+ constexpr const_reference operator*(void)const{return static_cast(current)->data;}
+ constexpr const_pointer operator->(void){return &(static_cast(current)->data);}
+ constexpr const_pointer operator->(void)const{return &(static_cast(current)->data);}
+ constexpr const_list_iterator& operator++(void){
+ current = current->next;
+ return *this;
+ }
+ constexpr const_list_iterator operator++(int){
+ const_list_iterator copy(*this);
+ ++(*this);
+ return copy;
+ }
+ constexpr const_list_iterator& operator--(void){
+ current = current->prev;
+ return *this;
+ }
+ constexpr const_list_iterator operator--(int){
+ const_list_iterator copy(*this);
+ --(*this);
+ return copy;
+ }
+
+ const_list_iterator next(void)const{
+ return const_list_iterator{current->next};
+ }
+ const_list_iterator prev(void)const{
+ return const_list_iterator{current->prev};
+ }
+
+ const node_base* nod(void)const{return current;}
+
+ protected:
+ list_iterator unconst(void){
+ return list_iterator{const_cast(current)};
+ }
+ };
+
+
+ }
+ namespace detail{
+ }
+
+ template
+ constexpr list::list(const allocator_type& alloc):
+ node_allocator_type(alloc){}
+ template
+ REXY_CPP20_CONSTEXPR list::list(size_type count, const_reference value, const allocator_type& alloc):
+ node_allocator_type(alloc)
+ {
+ assign(count, value);
+ }
+ template
+ REXY_CPP20_CONSTEXPR list::list(size_type count, const allocator_type& alloc):
+ node_allocator_type(alloc)
+ {
+ assign(count, value_type());
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR list::list(InputIt first, InputIt last, const allocator_type& alloc):
+ node_allocator_type(alloc)
+ {
+ assign(first, last);
+ }
+ template
+ REXY_CPP20_CONSTEXPR list::list(const list& other, const allocator_type& alloc):
+ node_allocator_type(alloc)
+ {
+ assign(other.begin(), other.end());
+ }
+ template
+ REXY_CPP20_CONSTEXPR list::list(list&& other, const allocator_type& alloc):
+ node_allocator_type(alloc)
+ {
+ swap(other);
+ }
+ template
+ REXY_CPP20_CONSTEXPR list::list(std::initializer_list l, const allocator_type& alloc):
+ node_allocator_type(alloc)
+ {
+ assign(l);
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR list::~list(void){
+ clear();
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::operator=(const list& other) -> list&{
+ return (*this = list(other));
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::operator=(list&& other) -> list&{
+ swap(other);
+ return *this;
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::operator=(std::initializer_list l) -> list&{
+ return (*this = list(l));
+ }
+
+ template
+ constexpr bool list::operator==(const list& other)const noexcept{
+ if(m_size != other.m_size)
+ return false;
+ return std::equal(cbegin(), cend(), other.cbegin());
+ }
+#if __cpp_impl_three_way_comparison
+ template
+ constexpr auto list::operator<=>(const list& other)const noexcept{
+ return std::lexicographical_compare_three_way(cbegin(), cend(), other.cbegin(), other.cend());
+ }
+#else
+ template
+ constexpr bool list::operator!=(const list& other)const noexcept{
+ return !(*this == other);
+ }
+ template
+ constexpr bool list::operator<(const list& other)const noexcept{
+ return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend());
+ }
+ template
+ constexpr bool list::operator<=(const list& other)const noexcept{
+ return !(other < *this);
+ }
+ template
+ constexpr bool list::operator>(const list& other)const noexcept{
+ return other < *this;
+ }
+ template
+ constexpr bool list::operator>=(const list& other)const noexcept{
+ return !(*this < other);
+ }
+#endif
+
+ template
+ REXY_CPP20_CONSTEXPR void list::assign(size_type count, const_reference value){
+ assign(sized_constant_iterator{value, count}, sized_constant_iterator{{}, 0});
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR void list::assign(InputIt first, InputIt last){
+ auto current = begin();
+ size_type i = 0;
+ for(;i < m_size && first != last;++i){
+ *current++ = *first++;
+ }
+ if(first != last){
+ m_size = i;
+ while(first != last){
+ current = ++(insert(current, *first++));
+ }
+ }else{
+ erase(current, end());
+ }
+ }
+ template
+ REXY_CPP20_CONSTEXPR void list::assign(std::initializer_list l){
+ assign(l.begin(), l.end());
+ }
+
+ template
+ constexpr auto list::get_allocator(void)const noexcept -> allocator_type{return {*this};}
+
+ //Direct accessors
+ template
+ constexpr auto list::front(void) -> reference{return *begin();}
+ template
+ constexpr auto list::front(void)const -> const_reference{return *begin();}
+ template
+ constexpr auto list::back(void) -> reference{return *(--end());}
+ template
+ constexpr auto list::back(void)const -> const_reference{return *(--end());}
+
+ //Iterators
+ template
+ constexpr auto list::begin(void)noexcept -> iterator{return iterator{m_sentinel.next};}
+ template
+ constexpr auto list::begin(void)const noexcept -> const_iterator{return const_iterator{m_sentinel.next};}
+ template
+ constexpr auto list::cbegin(void)const noexcept -> const_iterator{return const_iterator{m_sentinel.next};}
+ template
+ constexpr auto list::end(void)noexcept -> iterator{return iterator{&m_sentinel};}
+ template
+ constexpr auto list::end(void)const noexcept -> const_iterator{return const_iterator{&m_sentinel};}
+ template
+ constexpr auto list::cend(void)const noexcept -> const_iterator{return const_iterator{&m_sentinel};}
+ template
+ constexpr auto list::next(iterator i)noexcept -> iterator{
+ return i.next();
+ }
+ template
+ constexpr auto list::next(const_iterator i)noexcept -> const_iterator{return i.next();}
+ template
+ constexpr auto list::prev(iterator i)noexcept -> iterator{return i.prev();}
+ template
+ constexpr auto list::prev(const_iterator i)noexcept -> const_iterator{return i.prev();}
+ template
+ constexpr auto list::rbegin(void)noexcept -> reverse_iterator{return reverse_iterator{end()};}
+ template
+ constexpr auto list::rbegin(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{end()};}
+ template
+ constexpr auto list::crbegin(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{end()};}
+ template
+ constexpr auto list::rend(void)noexcept -> reverse_iterator{return reverse_iterator{begin()};}
+ template
+ constexpr auto list::rend(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{begin()};}
+ template
+ constexpr auto list::crend(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{begin()};}
+
+ //Queries
+ template
+ constexpr bool list::empty(void)const noexcept{return m_sentinel.next == nullptr;}
+ template
+ constexpr auto list::size(void)const noexcept -> size_type{return m_size;}
+ template
+ constexpr auto list::max_size(void)const noexcept -> size_type{return std::numeric_limits::max();}
+
+ template
+ REXY_CPP20_CONSTEXPR void list::clear(void)noexcept{
+ erase(begin(), end());
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::insert(const_iterator pos, const_reference value) -> iterator{
+ return insert(pos, value_type{value});
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::insert(const_iterator pos, value_type&& value) -> iterator{
+ auto* prev = (--pos).unconst().nod();
+ auto* next = prev->next;
+ prev->next = this->allocate(1);
+ next->prev = prev->next;
+#ifdef __clang__
+ //clang won't let construct at emplace without creating a temporary here...
+ std::construct_at(static_cast(prev->next), node{{next, prev}, std::move(value)});
+#else
+ std::construct_at(static_cast(prev->next), detail::node_base{next, prev}, std::move(value));
+#endif
+ ++m_size;
+ return iterator{prev->next};
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::insert(const_iterator pos, size_type count, const_reference value) -> iterator{
+ auto start = pos.unconst();
+ for(auto i = count;i > 0;--i){
+ pos = ++(insert(pos, value_type{value}));
+ }
+ return start;
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR auto list::insert(const_iterator pos, InputIt first, InputIt last) -> iterator{
+ auto start = pos.unconst();
+ while(first != last){
+ pos = ++(insert(pos, *first++));
+ }
+ return start;
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::insert(const_iterator pos, std::initializer_list l) -> iterator{
+ return insert(pos, l.begin(), l.end());
+ }
+
+ template
+ template
+ REXY_CPP20_CONSTEXPR auto list::emplace(const_iterator pos, Args&&... args) -> iterator{
+ auto* prev = (--pos).unconst().nod();
+ auto* next = prev->next;
+ prev->next = this->allocate(1);
+ next->prev = prev->next;
+#ifdef __clang__
+ std::construct_at(static_cast(prev->next), node{{next, prev}, value_type{std::forward(args)...}});
+#else
+ std::construct_at(static_cast(prev->next), detail::node_base{next, prev}, value_type{std::forward(args)...});
+#endif
+ ++m_size;
+ return iterator{prev->next};
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::erase(const_iterator pos) -> iterator{
+ auto* n = pos.unconst().nod();
+ auto* next = n->next;
+
+ remove_node_(n);
+ std::destroy_at(static_cast(n));
+ this->deallocate(static_cast(n), 1);
+ --m_size;
+ return iterator{next};
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::erase(const_iterator first, const_iterator last) -> iterator{
+ while(first != last){
+ first = erase(first);
+ }
+ return last.unconst();
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::push_back(const_reference value) -> reference{
+ return insert(cend(), value);
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::push_back(value_type&& value) -> reference{
+ return insert(cend(), std::move(value));
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR auto list::emplace_back(Args&&... args) -> reference{
+ return emplace(cend(), std::forward(args)...);
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::pop_back(void){
+ erase(--cend());
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::push_front(const_reference value) -> reference{
+ return insert(cbegin(), value);
+ }
+ template
+ REXY_CPP20_CONSTEXPR auto list::push_front(value_type&& value) -> reference{
+ return insert(cbegin(), std::move(value));
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR auto list::emplace_front(Args&&... args) -> reference{
+ return emplace(cbegin(), std::forward(args)...);
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::pop_front(void){
+ erase(cbegin());
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::resize(size_type count){
+ resize(count, value_type{});
+ }
+ template
+ REXY_CPP20_CONSTEXPR void list::resize(size_type count, value_type value){
+ while(count > m_size){
+ insert(cend(), value);
+ }
+ while(m_size > count){
+ erase(--cend());
+ }
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::swap(list& other){
+ std::swap(m_sentinel, other.m_sentinel);
+ std::swap(m_size, other.m_size);
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::merge(list&& other){
+ merge(std::move(other), [](const_reference a, const_reference b){return a < b;});
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR void list::merge(list&& other, Comp comp){
+ if(&other == this){
+ return;
+ }
+ auto it = begin();
+ auto oit = other.begin();
+
+ while(it != end() && oit != other.end()){
+ if(comp(*oit, *it)){
+ oit = iterator{get_next_then_move_node_(it.prev().nod(), oit.nod())};
+ ++m_size;
+ }else{
+ ++it;
+ }
+ }
+ splice(it, std::move(other));
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::splice(const_iterator pos, list&& other){
+ splice(pos, std::move(other), other.begin(), other.end());
+ }
+ template
+ REXY_CPP20_CONSTEXPR void list::splice(const_iterator pos, list&& other, const_iterator it){
+ auto oit = it.unconst();
+ auto prev = (--pos).unconst();
+ remove_node_(oit.nod());
+ insert_node_(prev.nod(), oit.nod());
+
+ ++m_size;
+ --other.m_size;
+ }
+ template
+ REXY_CPP20_CONSTEXPR void list::splice(const_iterator pos, list&& other, const_iterator first, const_iterator last){
+ for(auto oit = first;oit != last;){
+ auto onext = oit.next();
+ splice(pos, std::move(other), oit);
+ oit = onext;
+ }
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::remove(const_reference value) -> size_type{
+ return remove_if(
+ [&value](const_reference r) -> bool{
+ return r == value;
+ }
+ );
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR auto list::remove_if(UnaryPred pred) -> size_type{
+ size_type count = 0;
+ for(auto it = begin();it != end();){
+ if(pred(*it)){
+ it = erase(it);
+ ++count;
+ }else{
+ ++it;
+ }
+ }
+ return count;
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::reverse(void)noexcept{
+ auto* it = begin().nod();
+ std::swap(m_sentinel.next, m_sentinel.prev);
+
+ for(;it != &m_sentinel;it = it->prev){
+ std::swap(it->next, it->prev);
+ }
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR auto list::unique(void) -> size_type{
+ return unique(
+ [](const_reference first, const_reference second) -> bool{
+ return first == second;
+ }
+ );
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR auto list::unique(BinaryPred pred) -> size_type{
+ size_type count = 0;
+ for(auto it = begin();it != end();++it){
+ auto next = it.next();
+ while(next != end() && pred(*it, *next)){
+ next = erase(next);
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ template
+ REXY_CPP20_CONSTEXPR void list::sort(void){
+ mergesort(begin(), m_size, [](const_reference first, const_reference second)->bool{
+ return first < second;
+ });
+ }
+ template
+ template
+ REXY_CPP20_CONSTEXPR void list::sort(Comp comp){
+ mergesort(begin(), m_size, comp);
+ }
+
+ template
+ template
+ auto list::mergesort(iterator first, size_type firstlen, Comp comp) -> iterator{
+ if(firstlen == 1)
+ return first;
+ auto [second, secondlen] = ms_split(first, firstlen);
+ firstlen -= secondlen;
+
+ first = mergesort(first, firstlen, comp);
+ second = mergesort(second, secondlen, comp);
+
+ iterator result = first;
+
+ //do this outside the loop to save return value
+ if(comp(*second, *first)){
+ result = second;
+ second = iterator{get_next_then_move_node_(first.prev().nod(), second.nod())};
+ --secondlen;
+ }
+
+ while(firstlen > 0 && secondlen > 0){
+ if(comp(*second, *first)){
+ second = iterator{get_next_then_move_node_(first.prev().nod(), second.nod())};
+ --secondlen;
+ }else{
+ ++first;
+ --firstlen;
+ }
+ }
+ //finish off the second list if it isn't already done
+ while(secondlen > 0){
+ second = iterator{get_next_then_move_node_(first.prev().nod(), second.nod())};
+ --secondlen;
+ }
+ return result;
+ }
+
+ template
+ auto list::ms_split(iterator it, size_type len) -> std::pair{
+ size_type second_half_len = len / 2;
+ size_type dist = len - second_half_len;
+ for(auto i = dist;i > 0;--i){
+ ++it;
+ }
+ return {it, second_half_len};
+ }
+
+ template
+ void list::insert_node_(detail::node_base* prev, detail::node_base* n){
+ n->next = prev->next;
+ n->prev = prev;
+ prev->next->prev = n;
+ prev->next = n;
+ }
+ template
+ void list::remove_node_(detail::node_base* rm){
+ rm->prev->next = rm->next;
+ rm->next->prev = rm->prev;
+ }
+ template