/* Copyright (c) 2019, 2020, MariaDB 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; version 2 of the License. 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef ILIST_H #define ILIST_H #include "my_dbug.h" #include #include // Derive your class from this struct to insert to a linked list. template struct ilist_node { #ifndef DBUG_OFF ilist_node() noexcept : next(NULL), prev(NULL) {} #else ilist_node() = default; #endif ilist_node(ilist_node *next, ilist_node *prev) noexcept : next(next), prev(prev) { } ilist_node *next; ilist_node *prev; }; // Modelled after std::list template class ilist { public: typedef ilist_node ListNode; class Iterator; // All containers in C++ should define these types to implement generic // container interface. typedef T value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef value_type &reference; typedef const value_type &const_reference; typedef T *pointer; typedef const T *const_pointer; typedef Iterator iterator; typedef Iterator const_iterator; /* FIXME */ typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; class Iterator { public: // All iterators in C++ should define these types to implement generic // iterator interface. typedef std::bidirectional_iterator_tag iterator_category; typedef T value_type; typedef std::ptrdiff_t difference_type; typedef T *pointer; typedef T &reference; explicit Iterator(ListNode *node) noexcept : node_(node) { DBUG_ASSERT(node_ != nullptr); } Iterator &operator++() noexcept { node_= node_->next; DBUG_ASSERT(node_ != nullptr); return *this; } Iterator operator++(int) noexcept { Iterator tmp(*this); operator++(); return tmp; } Iterator &operator--() noexcept { node_= node_->prev; DBUG_ASSERT(node_ != nullptr); return *this; } Iterator operator--(int) noexcept { Iterator tmp(*this); operator--(); return tmp; } reference operator*() noexcept { return *static_cast(node_); } const_reference operator*() const noexcept { return *static_cast(node_); } pointer operator->() noexcept { return static_cast(node_); } friend bool operator==(const Iterator &lhs, const Iterator &rhs) noexcept { return lhs.node_ == rhs.node_; } friend bool operator!=(const Iterator &lhs, const Iterator &rhs) noexcept { return !(lhs == rhs); } private: ListNode *node_; friend class ilist; }; ilist() noexcept : sentinel_(&sentinel_, &sentinel_) {} reference front() noexcept { return *begin(); } reference back() noexcept { return *--end(); } const_reference front() const noexcept { return *begin(); } const_reference back() const noexcept { return *--end(); } iterator begin() noexcept { return iterator(sentinel_.next); } const_iterator begin() const noexcept { return iterator(const_cast(sentinel_.next)); } iterator end() noexcept { return iterator(&sentinel_); } const_iterator end() const noexcept { return iterator(const_cast(&sentinel_)); } reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } const_reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } reverse_iterator rend() noexcept { return reverse_iterator(begin()); } const_reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } bool empty() const noexcept { return sentinel_.next == &sentinel_; } // Not implemented because it's O(N) // size_type size() const // { // return static_cast(std::distance(begin(), end())); // } void clear() noexcept { sentinel_.next= &sentinel_; sentinel_.prev= &sentinel_; } iterator insert(iterator pos, reference value) noexcept { ListNode *curr= pos.node_; ListNode *prev= pos.node_->prev; prev->next= &value; curr->prev= &value; static_cast(value).prev= prev; static_cast(value).next= curr; return iterator(&value); } iterator erase(iterator pos) noexcept { ListNode *prev= pos.node_->prev; ListNode *next= pos.node_->next; prev->next= next; next->prev= prev; #ifndef DBUG_OFF ListNode *curr= pos.node_; curr->prev= nullptr; curr->next= nullptr; #endif return Iterator(next); } void push_back(reference value) noexcept { insert(end(), value); } void pop_back() noexcept { erase(end()); } void push_front(reference value) noexcept { insert(begin(), value); } void pop_front() noexcept { erase(begin()); } // STL version is O(n) but this is O(1) because an element can't be inserted // several times in the same ilist. void remove(reference value) noexcept { erase(iterator(&value)); } private: ListNode sentinel_; }; // Similar to ilist but also has O(1) size() method. template class sized_ilist : public ilist { typedef ilist BASE; public: // All containers in C++ should define these types to implement generic // container interface. typedef T value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef value_type &reference; typedef const value_type &const_reference; typedef T *pointer; typedef const T *const_pointer; typedef typename BASE::Iterator iterator; typedef const typename BASE::Iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; sized_ilist() noexcept : size_(0) {} size_type size() const noexcept { return size_; } void clear() noexcept { BASE::clear(); size_= 0; } iterator insert(iterator pos, reference value) noexcept { ++size_; return BASE::insert(pos, value); } iterator erase(iterator pos) noexcept { --size_; return BASE::erase(pos); } void push_back(reference value) noexcept { insert(BASE::end(), value); } void pop_back() noexcept { erase(BASE::end()); } void push_front(reference value) noexcept { insert(BASE::begin(), value); } void pop_front() noexcept { erase(BASE::begin()); } void remove(reference value) noexcept { erase(iterator(&value)); } private: size_type size_; }; #endif