Add list class
This commit is contained in:
parent
c4d83b0310
commit
b6a8c83e0b
@ -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 "")
|
||||
|
||||
211
include/rexy/list.hpp
Normal file
211
include/rexy/list.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_LLIST_HPP
|
||||
#define REXY_LLIST_HPP
|
||||
|
||||
#include <cstddef> //size_t, ptrdiff_t
|
||||
#include "allocator.hpp" //TODO
|
||||
#include "detail/hasallocator.hpp"
|
||||
#include <iterator> //bidirectional_iterator_tag, reverse_iterator
|
||||
#include <memory> //allocator_traits
|
||||
#include <initializer_list>
|
||||
#include <utility> //pair
|
||||
|
||||
namespace rexy{
|
||||
|
||||
template<class T, class Alloc>
|
||||
class list;
|
||||
|
||||
namespace detail{
|
||||
struct node_base{
|
||||
node_base* next = nullptr;
|
||||
node_base* prev = nullptr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct list_iterator;
|
||||
template<class T>
|
||||
struct const_list_iterator;
|
||||
template<class T>
|
||||
struct node;
|
||||
}
|
||||
|
||||
template<class T, class Alloc = rexy::allocator<T>>
|
||||
class list : protected detail::hasallocator<typename std::allocator_traits<Alloc>::template rebind_alloc<detail::node<T>>>
|
||||
{
|
||||
private:
|
||||
using node_allocator_type = detail::hasallocator<typename std::allocator_traits<Alloc>::template rebind_alloc<detail::node<T>>>;
|
||||
|
||||
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<T>;
|
||||
using const_iterator = detail::const_list_iterator<T>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
public:
|
||||
using node = detail::node<T>;
|
||||
|
||||
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<class InputIt>
|
||||
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<value_type> 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<value_type> 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<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR void assign(InputIt first, InputIt last);
|
||||
REXY_CPP20_CONSTEXPR void assign(std::initializer_list<value_type> 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<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, InputIt first, InputIt last);
|
||||
REXY_CPP20_CONSTEXPR iterator insert(const_iterator pos, std::initializer_list<value_type> l);
|
||||
|
||||
template<class... Args>
|
||||
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<class... Args>
|
||||
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<class... Args>
|
||||
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<class Comp>
|
||||
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<class UnaryPred>
|
||||
REXY_CPP20_CONSTEXPR size_type remove_if(UnaryPred p);
|
||||
|
||||
REXY_CPP20_CONSTEXPR void reverse(void)noexcept;
|
||||
|
||||
REXY_CPP20_CONSTEXPR size_type unique(void);
|
||||
template<class BinaryPred>
|
||||
REXY_CPP20_CONSTEXPR size_type unique(BinaryPred p);
|
||||
|
||||
REXY_CPP20_CONSTEXPR void sort(void);
|
||||
template<class Comp>
|
||||
REXY_CPP20_CONSTEXPR void sort(Comp comp);
|
||||
private:
|
||||
template<class Comp>
|
||||
iterator mergesort(iterator first, size_type firstlen, Comp comp);
|
||||
std::pair<iterator,size_type> 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
|
||||
657
include/rexy/list.tpp
Normal file
657
include/rexy/list.tpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_LLIST_TPP
|
||||
#define REXY_LLIST_TPP
|
||||
|
||||
#include <utility> //move, swap, forward
|
||||
#include <limits> //numeric_limits
|
||||
#include <algorithm> //lexicographical_compare_three_way, equal
|
||||
#include <memory> //construct_at, destroy_at
|
||||
|
||||
#include "utility.hpp" //sized_constant_iterator
|
||||
|
||||
namespace rexy{
|
||||
|
||||
namespace detail{
|
||||
template<class T>
|
||||
struct node : public node_base{
|
||||
T data;
|
||||
|
||||
node* next(void)const{return static_cast<node*>(node_base::next);}
|
||||
node* prev(void)const{return static_cast<node*>(node_base::prev);}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
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<T>;
|
||||
|
||||
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<T>& other)const noexcept{return current == other.nod();}
|
||||
constexpr bool operator!=(const const_list_iterator<T>& other)const noexcept{return current != other.nod();}
|
||||
|
||||
constexpr reference operator*(void){return static_cast<node_t*>(current)->data;}
|
||||
constexpr const_reference operator*(void)const{return static_cast<const node_t*>(current)->data;}
|
||||
constexpr pointer operator->(void){return &(static_cast<node_t*>(current)->data);}
|
||||
constexpr const_pointer operator->(void)const{return &(static_cast<const node_t*>(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<T>(void)const{
|
||||
return const_list_iterator<T>{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<class T>
|
||||
struct const_list_iterator{
|
||||
template<class U, class Alloc>
|
||||
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<T>;
|
||||
|
||||
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<T>& other)const noexcept{return current == other.nod();}
|
||||
constexpr bool operator!=(const list_iterator<T>& other)const noexcept{return current != other.nod();}
|
||||
|
||||
constexpr const_reference operator*(void){return static_cast<const node_t*>(current)->data;}
|
||||
constexpr const_reference operator*(void)const{return static_cast<const node_t*>(current)->data;}
|
||||
constexpr const_pointer operator->(void){return &(static_cast<const node_t*>(current)->data);}
|
||||
constexpr const_pointer operator->(void)const{return &(static_cast<const node_t*>(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<T> unconst(void){
|
||||
return list_iterator<T>{const_cast<node_base*>(current)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
namespace detail{
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
constexpr list<T,Alloc>::list(const allocator_type& alloc):
|
||||
node_allocator_type(alloc){}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::list(size_type count, const_reference value, const allocator_type& alloc):
|
||||
node_allocator_type(alloc)
|
||||
{
|
||||
assign(count, value);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::list(size_type count, const allocator_type& alloc):
|
||||
node_allocator_type(alloc)
|
||||
{
|
||||
assign(count, value_type());
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::list(InputIt first, InputIt last, const allocator_type& alloc):
|
||||
node_allocator_type(alloc)
|
||||
{
|
||||
assign(first, last);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::list(const list& other, const allocator_type& alloc):
|
||||
node_allocator_type(alloc)
|
||||
{
|
||||
assign(other.begin(), other.end());
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::list(list&& other, const allocator_type& alloc):
|
||||
node_allocator_type(alloc)
|
||||
{
|
||||
swap(other);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::list(std::initializer_list<value_type> l, const allocator_type& alloc):
|
||||
node_allocator_type(alloc)
|
||||
{
|
||||
assign(l);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR list<T,Alloc>::~list(void){
|
||||
clear();
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::operator=(const list& other) -> list&{
|
||||
return (*this = list(other));
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::operator=(list&& other) -> list&{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::operator=(std::initializer_list<value_type> l) -> list&{
|
||||
return (*this = list(l));
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::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<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::operator<=>(const list& other)const noexcept{
|
||||
return std::lexicographical_compare_three_way(cbegin(), cend(), other.cbegin(), other.cend());
|
||||
}
|
||||
#else
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::operator!=(const list& other)const noexcept{
|
||||
return !(*this == other);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::operator<(const list& other)const noexcept{
|
||||
return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend());
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::operator<=(const list& other)const noexcept{
|
||||
return !(other < *this);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::operator>(const list& other)const noexcept{
|
||||
return other < *this;
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::operator>=(const list& other)const noexcept{
|
||||
return !(*this < other);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::assign(size_type count, const_reference value){
|
||||
assign(sized_constant_iterator{value, count}, sized_constant_iterator<value_type>{{}, 0});
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::assign(std::initializer_list<value_type> l){
|
||||
assign(l.begin(), l.end());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::get_allocator(void)const noexcept -> allocator_type{return {*this};}
|
||||
|
||||
//Direct accessors
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::front(void) -> reference{return *begin();}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::front(void)const -> const_reference{return *begin();}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::back(void) -> reference{return *(--end());}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::back(void)const -> const_reference{return *(--end());}
|
||||
|
||||
//Iterators
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::begin(void)noexcept -> iterator{return iterator{m_sentinel.next};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::begin(void)const noexcept -> const_iterator{return const_iterator{m_sentinel.next};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::cbegin(void)const noexcept -> const_iterator{return const_iterator{m_sentinel.next};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::end(void)noexcept -> iterator{return iterator{&m_sentinel};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::end(void)const noexcept -> const_iterator{return const_iterator{&m_sentinel};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::cend(void)const noexcept -> const_iterator{return const_iterator{&m_sentinel};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::next(iterator i)noexcept -> iterator{
|
||||
return i.next();
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::next(const_iterator i)noexcept -> const_iterator{return i.next();}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::prev(iterator i)noexcept -> iterator{return i.prev();}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::prev(const_iterator i)noexcept -> const_iterator{return i.prev();}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::rbegin(void)noexcept -> reverse_iterator{return reverse_iterator{end()};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::rbegin(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{end()};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::crbegin(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{end()};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::rend(void)noexcept -> reverse_iterator{return reverse_iterator{begin()};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::rend(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{begin()};}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::crend(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{begin()};}
|
||||
|
||||
//Queries
|
||||
template<class T, class Alloc>
|
||||
constexpr bool list<T,Alloc>::empty(void)const noexcept{return m_sentinel.next == nullptr;}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::size(void)const noexcept -> size_type{return m_size;}
|
||||
template<class T, class Alloc>
|
||||
constexpr auto list<T,Alloc>::max_size(void)const noexcept -> size_type{return std::numeric_limits<difference_type>::max();}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::clear(void)noexcept{
|
||||
erase(begin(), end());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::insert(const_iterator pos, const_reference value) -> iterator{
|
||||
return insert(pos, value_type{value});
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::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<node*>(prev->next), node{{next, prev}, std::move(value)});
|
||||
#else
|
||||
std::construct_at(static_cast<node*>(prev->next), detail::node_base{next, prev}, std::move(value));
|
||||
#endif
|
||||
++m_size;
|
||||
return iterator{prev->next};
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::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<class T, class Alloc>
|
||||
template<class InputIt>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::insert(const_iterator pos, InputIt first, InputIt last) -> iterator{
|
||||
auto start = pos.unconst();
|
||||
while(first != last){
|
||||
pos = ++(insert(pos, *first++));
|
||||
}
|
||||
return start;
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::insert(const_iterator pos, std::initializer_list<value_type> l) -> iterator{
|
||||
return insert(pos, l.begin(), l.end());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
template<class... Args>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::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<node*>(prev->next), node{{next, prev}, value_type{std::forward<Args>(args)...}});
|
||||
#else
|
||||
std::construct_at(static_cast<node*>(prev->next), detail::node_base{next, prev}, value_type{std::forward<Args>(args)...});
|
||||
#endif
|
||||
++m_size;
|
||||
return iterator{prev->next};
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::erase(const_iterator pos) -> iterator{
|
||||
auto* n = pos.unconst().nod();
|
||||
auto* next = n->next;
|
||||
|
||||
remove_node_(n);
|
||||
std::destroy_at(static_cast<node*>(n));
|
||||
this->deallocate(static_cast<node*>(n), 1);
|
||||
--m_size;
|
||||
return iterator{next};
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::erase(const_iterator first, const_iterator last) -> iterator{
|
||||
while(first != last){
|
||||
first = erase(first);
|
||||
}
|
||||
return last.unconst();
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::push_back(const_reference value) -> reference{
|
||||
return insert(cend(), value);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::push_back(value_type&& value) -> reference{
|
||||
return insert(cend(), std::move(value));
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class... Args>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::emplace_back(Args&&... args) -> reference{
|
||||
return emplace(cend(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::pop_back(void){
|
||||
erase(--cend());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::push_front(const_reference value) -> reference{
|
||||
return insert(cbegin(), value);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::push_front(value_type&& value) -> reference{
|
||||
return insert(cbegin(), std::move(value));
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class... Args>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::emplace_front(Args&&... args) -> reference{
|
||||
return emplace(cbegin(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::pop_front(void){
|
||||
erase(cbegin());
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::resize(size_type count){
|
||||
resize(count, value_type{});
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::resize(size_type count, value_type value){
|
||||
while(count > m_size){
|
||||
insert(cend(), value);
|
||||
}
|
||||
while(m_size > count){
|
||||
erase(--cend());
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::swap(list& other){
|
||||
std::swap(m_sentinel, other.m_sentinel);
|
||||
std::swap(m_size, other.m_size);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::merge(list&& other){
|
||||
merge(std::move(other), [](const_reference a, const_reference b){return a < b;});
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class Comp>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::splice(const_iterator pos, list&& other){
|
||||
splice(pos, std::move(other), other.begin(), other.end());
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::remove(const_reference value) -> size_type{
|
||||
return remove_if(
|
||||
[&value](const_reference r) -> bool{
|
||||
return r == value;
|
||||
}
|
||||
);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class UnaryPred>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::unique(void) -> size_type{
|
||||
return unique(
|
||||
[](const_reference first, const_reference second) -> bool{
|
||||
return first == second;
|
||||
}
|
||||
);
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class BinaryPred>
|
||||
REXY_CPP20_CONSTEXPR auto list<T,Alloc>::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<class T, class Alloc>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::sort(void){
|
||||
mergesort(begin(), m_size, [](const_reference first, const_reference second)->bool{
|
||||
return first < second;
|
||||
});
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
template<class Comp>
|
||||
REXY_CPP20_CONSTEXPR void list<T,Alloc>::sort(Comp comp){
|
||||
mergesort(begin(), m_size, comp);
|
||||
}
|
||||
|
||||
template<class T, class Alloc>
|
||||
template<class Comp>
|
||||
auto list<T,Alloc>::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<class T, class Alloc>
|
||||
auto list<T,Alloc>::ms_split(iterator it, size_type len) -> std::pair<iterator,size_type>{
|
||||
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<class T, class Alloc>
|
||||
void list<T,Alloc>::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<class T, class Alloc>
|
||||
void list<T,Alloc>::remove_node_(detail::node_base* rm){
|
||||
rm->prev->next = rm->next;
|
||||
rm->next->prev = rm->prev;
|
||||
}
|
||||
template<class T, class Alloc>
|
||||
detail::node_base* list<T,Alloc>::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
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user