//======================================================================= // Copyright Baptiste Wicht 2013-2018. // Distributed under the terms of the MIT License. // (See accompanying file LICENSE or copy at // http://www.opensource.org/licenses/MIT) //======================================================================= #ifndef LIST_H #define LIST_H #include #include #include #include namespace std { template struct list_node; template struct list; template struct list_iterator { using value_type = V; using node_type = list_node; using reference = value_type&; using pointer = value_type*; using difference_type = void; list_iterator(node_type* current) : current(current){ //Nothing else to init } value_type& operator*(){ return current->value; } const value_type& operator*() const { return current->value; } list_iterator& operator++(){ current = current->next; return *this; } list_iterator operator++(int){ list_iterator v = *this; current = current->next; return v; } list_iterator& operator--(){ current = current->prev; return *this; } list_iterator operator--(int){ list_iterator v = *this; current = current->prev; return v; } bool operator==(const list_iterator& rhs){ return current == rhs.current; } bool operator!=(const list_iterator& rhs){ return !(*this == rhs); } friend struct list; private: node_type* current; }; /*! * \brief A doubly-linked list implementation. * * This container should almost never be preferred over vector. The only time when list is better than vector * is when the data is very expensive to copy or it is necessary to have stable references. */ template struct list { using value_type = T; ///7< The value type of the container using pointer_type = value_type*; ///< The pointer type of the container using reference_type = value_type&; ///< The pointer type of the container using const_reference_type = const value_type&; ///< The pointer type of the container using size_type = size_t; ///< The size type of the container using node_type = list_node; ///< The type of nodes using iterator = list_iterator; ///< The iterator type using const_iterator = list_iterator>; ///< The const iterator type using reverse_iterator = std::reverse_iterator>; ///< The reverse iterator type using const_reverse_iterator = std::reverse_iterator>>; ///< The const reverse iterator type /*! * \brief Construct a ne empty list */ list() : _size(0), head(nullptr), tail(nullptr) { //Nothing else to init } /*! * \brief Destructs a list */ ~list(){ clear(); } // Disable copy for now list(const list& rhs) = delete; list& operator=(const list& rhs) = delete; //Allow move list(list&& rhs) : _size(rhs._size), head(rhs.head), tail(rhs.tail){ rhs._size = 0; rhs.head = nullptr; rhs.tail = nullptr; } list(initializer_list values) : list() { for(auto& v : values){ push_back(v); } } list& operator=(list&& rhs){ if(size() > 0){ clear(); } _size = rhs._size; head = rhs.head; tail = rhs.tail; rhs._size = 0; rhs.head = nullptr; rhs.tail = nullptr; return *this; } /*! * \brief Returns the size of the container */ size_t size() const { return _size; } /*! * \brief Indicates if the list is empty */ bool empty() const { return !_size; } /*! * \brief Empty the list */ void clear(){ while(!empty()){ pop_back(); } } /*! * \brief Add a new element at the front of the list */ void push_front(const value_type& value){ if(_size == 0){ head = new node_type(value, nullptr, nullptr); tail = head; } else { auto node = new node_type(value, head, nullptr); head->prev = node; head = node; } ++_size; } /*! * \brief Add a new element at the back of the list */ void push_back(const value_type& value){ if(_size == 0){ head = new node_type(value, nullptr, nullptr); tail = head; } else { auto node = new node_type(value, nullptr, tail); tail->next = node; tail = node; } ++_size; } template value_type& emplace_front(Args&&... args){ if(_size == 0){ head = new node_type(nullptr, nullptr, std::forward(args)...); tail = head; } else { auto node = new node_type(head, nullptr, std::forward(args)...); head->prev = node; head = node; } ++_size; return head->value; } template value_type& emplace_back(Args&&... args){ if(_size == 0){ head = new node_type(nullptr, nullptr, std::forward(args)...); tail = head; } else { auto node = new node_type(nullptr, tail, std::forward(args)...); tail->next = node; tail = node; } ++_size; return tail->value; } /*! * \brief Removes the element at the front of the list */ void pop_front(){ auto old = head; if(_size == 1){ tail = head = nullptr; } else { head = head->next; head->prev = nullptr; } delete old; --_size; } /*! * \brief Removes the element at the back of the list */ void pop_back(){ auto old = tail; if(_size == 1){ tail = head = nullptr; } else { tail = tail->prev; tail->next = nullptr; } delete old; --_size; } private: iterator erase_node(node_type* node){ if(!node){ return end(); } if(node->prev){ node->prev->next = node->next; } if(node->next){ node->next->prev = node->prev; } if(head == node){ head = node->next; } if(tail == node){ tail = node->prev; } auto next = node->next; delete node; --_size; return iterator(next); } public: iterator erase(iterator it){ return erase_node(it.current); } iterator erase(const_iterator it){ return erase_node(it.current); } iterator erase(iterator it, iterator last){ while(it != last){ it = erase_node(it.current); } return last; } iterator erase(const_iterator it, const_iterator last){ while(it != last){ it = erase_node(it.current); } return iterator(last.current); } // Element access /*! * \brief Returns a reference to the element at the front of the list */ T& front(){ return head->value; } /*! * \brief Returns a const reference to the element at the front of the list */ const T& front() const { return head->value; } /*! * \brief Returns a reference to the element at the back of the list */ T& back(){ return tail->value; } /*! * \brief Returns a const reference to the element at the back of the list */ const T& back() const { return tail->value; } // Iterators /*! * \brief Returns an iterator pointing to the first element of the list */ iterator begin(){ return iterator(head); } /*! * \brief Returns a const iterator pointing to the first element of the list */ const iterator begin() const { return const_iterator(head); } /*! * \brief Returns an iterator pointing to the past-the-end element of the list */ iterator end(){ return iterator(nullptr); } /*! * \brief Returns a const iterator pointing to the past-the-end element of the list */ const_iterator end() const { return const_iterator(nullptr); } reverse_iterator rbegin(){ return reverse_iterator(tail); } constexpr const_reverse_iterator rbegin() const { return const_iterator(tail); } reverse_iterator rend(){ return reverse_iterator(nullptr); } constexpr const_reverse_iterator rend() const { return const_reverse_iterator(nullptr); } private: size_t _size; ///< The size of the list node_type* head; ///< The front node of the list node_type* tail; ///< The tail node of the list }; template struct list_node { list_node(const T& v, list_node* n, list_node* p) : value(v), next(n), prev(p) { //Nothing else to init } template list_node(list_node* n, list_node* p, Args&&... args) : value(std::forward(args)...), next(n), prev(p) { //Nothing else to init } friend struct list; friend struct list_iterator; friend struct list_iterator>; private: T value; list_node* next; list_node* prev; }; } //end of namespace std #endif