From b6a8c83e0bde8c3f6d931d13aee688264936a1dd Mon Sep 17 00:00:00 2001 From: rexy712 Date: Tue, 19 Jul 2022 16:44:34 -0700 Subject: [PATCH] Add list class --- CMakeLists.txt | 2 +- include/rexy/list.hpp | 211 ++++++++++++++ include/rexy/list.tpp | 657 ++++++++++++++++++++++++++++++++++++++++++ src/ensure.cpp | 2 + 4 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 include/rexy/list.hpp create mode 100644 include/rexy/list.tpp 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 + detail::node_base* list::get_next_then_move_node_(detail::node_base* dest, detail::node_base* n){ + auto* next = n->next; + remove_node_(n); + insert_node_(dest, n); + return next; + } + +} + +#endif diff --git a/src/ensure.cpp b/src/ensure.cpp index 369f314..6fde4be 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -22,6 +22,8 @@ #include "rexy/visitor.hpp" #include "rexy/string_view.hpp" #include "rexy/string_view.tpp" +#include "rexy/list.hpp" +#include "rexy/list.tpp" #ifndef LIBREXY_HEADER_ONLY #include "rexy/filerd.hpp"