diff options
Diffstat (limited to 'include/estd/IntrusiveList.hpp')
-rw-r--r-- | include/estd/IntrusiveList.hpp | 1208 |
1 files changed, 1208 insertions, 0 deletions
diff --git a/include/estd/IntrusiveList.hpp b/include/estd/IntrusiveList.hpp new file mode 100644 index 0000000..82597f4 --- /dev/null +++ b/include/estd/IntrusiveList.hpp @@ -0,0 +1,1208 @@ +/** + * \file + * \brief IntrusiveList template class header + * + * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info + * + * \par License + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not + * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef ESTD_INTRUSIVELIST_HPP_ +#define ESTD_INTRUSIVELIST_HPP_ + +#include <iterator> + +#include <cstddef> + +namespace estd +{ + +namespace internal +{ + +class IntrusiveListBase; + +} + +/** + * \brief IntrusiveListNode class is the node that is needed for the object to be linked in IntrusiveList + * + * To some extent, this class can be considered to be a limited (raw) iterator. + * + * The object that wants to be linked in IntrusiveList must contain a variable of this type - one for each intrusive + * list that will be used with object. + */ + +class IntrusiveListNode +{ +public: + + /// LinkAccessKey class is used to limit access to IntrusiveListNode::link() function - only + /// internal::IntrusiveListBase can link nodes to the list + class LinkAccessKey + { + friend class internal::IntrusiveListBase; + + /** + * \brief LinkAccessKey's constructor + */ + + constexpr LinkAccessKey() + { + + } + + LinkAccessKey(const LinkAccessKey&) = delete; + LinkAccessKey(LinkAccessKey&&) = delete; + const LinkAccessKey& operator=(const LinkAccessKey&) = delete; + LinkAccessKey& operator=(LinkAccessKey&&) = delete; + }; + + /** + * \brief IntrusiveListNode's constructor + */ + + constexpr IntrusiveListNode() : + nextNode_{this}, + previousNode_{this} + { + + } + + /** + * \brief IntrusiveListNode's move constructor + * + * \param [in] other is a rvalue reference to IntrusiveListNode used as source of move construction + */ + + IntrusiveListNode(IntrusiveListNode&& other) + { + if (other.isLinked() == false) + { + reset(); + return; + } + + nextNode_ = other.nextNode_; + previousNode_ = other.previousNode_; + nextNode_->previousNode_ = previousNode_->nextNode_ = this; + other.reset(); + } + + /** + * \brief IntrusiveListNode's destructor + * + * Unlinks the node from the list. + */ + + ~IntrusiveListNode() + { + unlink(); + } + + /** + * \return reference to next node on the list + */ + + IntrusiveListNode& getNextNode() const + { + return *nextNode_; + } + + /** + * \return reference to previous node on the list + */ + + IntrusiveListNode& getPreviousNode() const + { + return *previousNode_; + } + + /** + * \return true if the node is linked in some list, false otherwise + */ + + bool isLinked() const + { + return nextNode_ != this; + } + + /** + * \brief Links the node in the list before \a position. + * + * \note Access to this function is restricted only to functions from internal::IntrusiveListBase class + * + * \param [in] position is a reference to node before which this node will be linked + * \param [in] linkAccessKey is used to limit access to this function + */ + + void link(IntrusiveListNode& position, LinkAccessKey) + { + unlink(); + + nextNode_ = &position; + previousNode_ = position.previousNode_; + position.previousNode_->nextNode_ = this; + position.previousNode_ = this; + } + + /** + * \brief Swaps contents with another node. + * + * \param [in] other is a reference to IntrusiveListNode with which contents of this node will be swapped + */ + + void swap(IntrusiveListNode& other) + { + const auto thisWasLinked = isLinked(); + const auto otherWasLinked = other.isLinked(); + + if (thisWasLinked == true || otherWasLinked == true) + { + using std::swap; + swap(nextNode_, other.nextNode_); + swap(previousNode_, other.previousNode_); + + if (thisWasLinked == true) + other.nextNode_->previousNode_ = other.previousNode_->nextNode_ = &other; + else + other.reset(); + + if (otherWasLinked == true) + nextNode_->previousNode_ = previousNode_->nextNode_ = this; + else + reset(); + } + } + + /** + * \brief Unlinks the node from the list. + */ + + void unlink() + { + previousNode_->nextNode_ = nextNode_; + nextNode_->previousNode_ = previousNode_; + + reset(); + } + + IntrusiveListNode(const IntrusiveListNode&) = delete; + const IntrusiveListNode& operator=(const IntrusiveListNode&) = delete; + IntrusiveListNode& operator=(IntrusiveListNode&&) = delete; + +private: + + /** + * \brief Resets the node to the same state as right after construction. + */ + + void reset() + { + nextNode_ = this; + previousNode_ = this; + } + + /// reference to next node on the list + IntrusiveListNode* nextNode_; + + /// reference to previous node on the list + IntrusiveListNode* previousNode_; +}; + +namespace internal +{ + +/** + * \brief IntrusiveListBase class provides base functionalities for IntrusiveList class, but without any knowledge about + * types + * + * This class tries to provide an interface similar to std::list. + */ + +class IntrusiveListBase +{ +public: + + /** + * \brief IntrusiveListBase's constructor + */ + + constexpr IntrusiveListBase() : + rootNode_{} + { + + } + + /** + * \brief IntrusiveListBase's destructor + * + * Unlinks all nodes from the list. + */ + + ~IntrusiveListBase() + { + clear(); + } + + /** + * \return reference to first node on the list + */ + + IntrusiveListNode& begin() + { + return rootNode_.getNextNode(); + } + + /** + * \return const reference to first node on the list + */ + + const IntrusiveListNode& begin() const + { + return rootNode_.getNextNode(); + } + + /** + * \return const reference to first node on the list + */ + + const IntrusiveListNode& cbegin() const + { + return begin(); + } + + /** + * \return const reference to "one past the last" node on the list + */ + + const IntrusiveListNode& cend() const + { + return end(); + } + + /** + * \brief Unlinks all nodes from the list. + */ + + void clear() + { + while (empty() == false) + pop_front(); + } + + /** + * \return true is the list is empty, false otherwise + */ + + bool empty() const + { + return &begin() == &end(); + } + + /** + * \return reference to "one past the last" node on the list + */ + + IntrusiveListNode& end() + { + return rootNode_; + } + + /** + * \return const reference to "one past the last" node on the list + */ + + const IntrusiveListNode& end() const + { + return rootNode_; + } + + /** + * \brief Unlinks the last node from the list. + */ + + void pop_back() + { + erase(end().getPreviousNode()); + } + + /** + * \brief Unlinks the first node from the list. + */ + + void pop_front() + { + erase(begin()); + } + + /** + * \brief Links the node at the end of the list. + * + * \param [in] newNode is a reference to node that will be linked in the list + */ + + void push_back(IntrusiveListNode& newNode) + { + insert(end(), newNode); + } + + /** + * \brief Links the node at the beginning of the list. + * + * \param [in] newNode is a reference to node that will be linked in the list + */ + + void push_front(IntrusiveListNode& newNode) + { + insert(begin(), newNode); + } + + /** + * \brief Swaps contents with another list. + * + * \param [in] other is a reference to IntrusiveListBase with which contents of this list will be swapped + */ + + void swap(IntrusiveListBase& other) + { + rootNode_.swap(other.rootNode_); + } + + /** + * \brief Unlinks the node at \a position from the list. + * + * \note No instance of the list is needed for this operation. + * + * \param [in] position is a reference to the node that will be unlinked from the list + * + * \return reference to the node that was following the node which was unlinked + */ + + static IntrusiveListNode& erase(IntrusiveListNode& position) + { + auto& next = position.getNextNode(); + position.unlink(); + return next; + } + + /** + * \brief Links the node in the list before \a position. + * + * \note No instance of the list is needed for this operation. + * + * \param [in] position is a reference to node before which \a newNode will be linked + * \param [in] newNode is a reference to node that will be linked in the list + */ + + static void insert(IntrusiveListNode& position, IntrusiveListNode& newNode) + { + newNode.link(position, {}); + } + + /** + * \brief Transfers the node from one list to another list before \a position. + * + * \note No instance of any list is needed for this operation. + * + * \param [in] position is a reference to node before which \a splicedNode will be linked + * \param [in] splicedNode is a reference to node that will be spliced from one list to another + */ + + static void splice(IntrusiveListNode& position, IntrusiveListNode& splicedNode) + { + insert(position, splicedNode); + } + + IntrusiveListBase(const IntrusiveListBase&) = delete; + IntrusiveListBase(IntrusiveListBase&&) = default; + const IntrusiveListBase& operator=(const IntrusiveListBase&) = delete; + IntrusiveListBase& operator=(IntrusiveListBase&&) = delete; + +private: + + /// root node of the intrusive list + IntrusiveListNode rootNode_; +}; + +/** + * \brief Swaps contents of two lists. + * + * \param [in] left is a reference to IntrusiveListBase with which contents of \a right will be swapped + * \param [in] right is a reference to IntrusiveListBase with which contents of \a left will be swapped + */ + +inline void swap(IntrusiveListBase& left, IntrusiveListBase& right) +{ + left.swap(right); +} + +} // namespace internal + +/** + * \brief IntrusiveListIterator class is an iterator of elements on IntrusiveList. + * + * This class provides an interface similar to std::list::iterator. + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + */ + +template<typename T, IntrusiveListNode T::* NodePointer, typename U = T> +class IntrusiveListIterator +{ +public: + + /// difference type + using difference_type = ptrdiff_t; + + /// category of the iterator + using iterator_category = std::bidirectional_iterator_tag; + + /// pointer to object "pointed to" by the iterator + using pointer = U*; + + /// reference to object "pointed to" by the iterator + using reference = U&; + + /// value "pointed to" by the iterator + using value_type = U; + + /** + * \brief IntrusiveListIterator's constructor + */ + + constexpr IntrusiveListIterator() : + node_{} + { + + } + + /** + * \brief IntrusiveListIterator's constructor + * + * \param [in] node is a pointer to IntrusiveListNode of element that will be "pointed to" by the iterator + */ + + constexpr explicit IntrusiveListIterator(IntrusiveListNode* const node) : + node_{node} + { + + } + + /** + * \brief IntrusiveListIterator's constructor + * + * \param [in] element is a reference to element that will be "pointed to" by the iterator + */ + + constexpr explicit IntrusiveListIterator(reference element) : + node_{&(element.*NodePointer)} + { + static_assert(std::is_convertible<U, T>::value == true, "U must be implicitly convertible to T!"); + } + + /** + * \brief IntrusiveListIterator's binary infix pointer member access operator + * + * \return pointer to object "pointed to" by the iterator + */ + + pointer operator->() const + { + return getPointer(); + } + + /** + * \brief IntrusiveListIterator's unary prefix dereference operator + * + * \return reference to object "pointed to" by the iterator + */ + + reference operator*() const + { + return *getPointer(); + } + + /** + * \brief IntrusiveListIterator's unary prefix increment operator + * + * \return reference to "this" iterator + */ + + IntrusiveListIterator& operator++() + { + node_ = &node_->getNextNode(); + return *this; + } + + /** + * \brief IntrusiveListIterator's unary postfix increment operator + * + * \return copy of "this" iterator before increment + */ + + IntrusiveListIterator operator++(int) + { + const auto temporary = *this; + node_ = &node_->getNextNode(); + return temporary; + } + + /** + * \brief IntrusiveListIterator's unary prefix decrement operator + * + * \return reference to "this" iterator + */ + + IntrusiveListIterator& operator--() + { + node_ = &node_->getPreviousNode(); + return *this; + } + + /** + * \brief IntrusiveListIterator's unary postfix decrement operator + * + * \return copy of "this" iterator before decrement + */ + + IntrusiveListIterator operator--(int) + { + const auto temporary = *this; + node_ = &node_->getPreviousNode(); + return temporary; + } + + /** + * \brief IntrusiveListIterator's "equal to" comparison operator + * + * \param [in] other is a const reference to IntrusiveListIterator on right-hand side of comparison operator + * + * \return true if both iterators are equal, false otherwise + */ + + bool operator==(const IntrusiveListIterator& other) const + { + return node_ == other.node_; + } + +private: + + /** + * \brief Converts contained pointer to IntrusiveListNode to pointer to object that contains this node. + * + * \return pointer to object "pointed to" by the iterator + */ + + pointer getPointer() const + { + static_assert(std::is_convertible<U, T>::value == true, "U must be implicitly convertible to T!"); + + const auto offset = reinterpret_cast<size_t>(&(static_cast<pointer>(nullptr)->*NodePointer)); + return reinterpret_cast<pointer>(reinterpret_cast<size_t>(node_) - offset); + } + + /// pointer to IntrusiveListNode of the object "pointed to" by the iterator + IntrusiveListNode* node_; +}; + +/** + * \brief IntrusiveListIterator's "not equal to" comparison operator + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + * + * \param [in] left is a const reference to IntrusiveListIterator on left-hand side of comparison operator + * \param [in] right is a const reference to IntrusiveListIterator on right-hand side of comparison operator + * + * \return true if iterators are not equal, false otherwise + */ + +template<typename T, IntrusiveListNode T::* NodePointer, typename U = T> +inline bool operator!=(const IntrusiveListIterator<T, NodePointer, U>& left, + const IntrusiveListIterator<T, NodePointer, U>& right) +{ + return (left == right) == false; +} + +/** + * \brief IntrusiveListConstIterator class is a const iterator of elements on IntrusiveList. + * + * This class provides an interface similar to std::list::const_iterator. + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a const pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + */ + +template<typename T, const IntrusiveListNode T::* NodePointer, typename U = T> +class IntrusiveListConstIterator +{ +public: + + /// difference type + using difference_type = ptrdiff_t; + + /// category of the iterator + using iterator_category = std::bidirectional_iterator_tag; + + /// pointer to object "pointed to" by the iterator + using pointer = const U*; + + /// reference to object "pointed to" by the iterator + using reference = const U&; + + /// value "pointed to" by the iterator + using value_type = U; + + /** + * \brief IntrusiveListConstIterator's constructor + */ + + constexpr IntrusiveListConstIterator() : + node_{} + { + + } + + /** + * \brief IntrusiveListConstIterator's constructor + * + * \param [in] node is a pointer to const IntrusiveListNode of element that will be "pointed to" by the iterator + */ + + constexpr explicit IntrusiveListConstIterator(const IntrusiveListNode* const node) : + node_{node} + { + + } + + /** + * \brief IntrusiveListConstIterator's constructor + * + * \param [in] element is a const reference to element that will be "pointed to" by the iterator + */ + + constexpr explicit IntrusiveListConstIterator(reference element) : + node_{&(element.*NodePointer)} + { + static_assert(std::is_convertible<U, T>::value == true, "U must be implicitly convertible to T!"); + } + + /** + * \brief IntrusiveListConstIterator's constructor + * + * Converts non-const iterator (IntrusiveListIterator) to const iterator (IntrusiveListConstIterator). + * + * \tparam NonConstNodePointer is a non-const version of \a NodePointer + * + * \param [in] iterator is a const reference to non-const iterator (IntrusiveListIterator) + */ + + template<IntrusiveListNode T::* NonConstNodePointer> + constexpr IntrusiveListConstIterator(const IntrusiveListIterator<T, NonConstNodePointer, U>& iterator) : + IntrusiveListConstIterator{*iterator} + { + + } + + /** + * \brief IntrusiveListConstIterator's binary infix pointer member access operator + * + * \return pointer to object "pointed to" by the iterator + */ + + pointer operator->() const + { + return getPointer(); + } + + /** + * \brief IntrusiveListConstIterator's unary prefix dereference operator + * + * \return reference to object "pointed to" by the iterator + */ + + reference operator*() const + { + return *getPointer(); + } + + /** + * \brief IntrusiveListConstIterator's unary prefix increment operator + * + * \return reference to "this" iterator + */ + + IntrusiveListConstIterator& operator++() + { + node_ = &node_->getNextNode(); + return *this; + } + + /** + * \brief IntrusiveListConstIterator's unary postfix increment operator + * + * \return copy of "this" iterator before increment + */ + + IntrusiveListConstIterator operator++(int) + { + const auto temporary = *this; + node_ = &node_->getNextNode(); + return temporary; + } + + /** + * \brief IntrusiveListConstIterator's unary prefix decrement operator + * + * \return reference to "this" iterator + */ + + IntrusiveListConstIterator& operator--() + { + node_ = &node_->getPreviousNode(); + return *this; + } + + /** + * \brief IntrusiveListConstIterator's unary postfix decrement operator + * + * \return copy of "this" iterator before decrement + */ + + IntrusiveListConstIterator operator--(int) + { + const auto temporary = *this; + node_ = &node_->getPreviousNode(); + return temporary; + } + + /** + * \brief IntrusiveListConstIterator's "equal to" comparison operator + * + * \param [in] other is a const reference to IntrusiveListConstIterator on right-hand side of comparison operator + * + * \return true if both iterators are equal, false otherwise + */ + + bool operator==(const IntrusiveListConstIterator& other) const + { + return node_ == other.node_; + } + +private: + + /** + * \brief Converts contained pointer to IntrusiveListNode to pointer to object that contains this node. + * + * \return pointer to object "pointed to" by the iterator + */ + + pointer getPointer() const + { + static_assert(std::is_convertible<U, T>::value == true, "U must be implicitly convertible to T!"); + + const auto offset = reinterpret_cast<size_t>(&(static_cast<pointer>(nullptr)->*NodePointer)); + return reinterpret_cast<pointer>(reinterpret_cast<size_t>(node_) - offset); + } + + /// pointer to const IntrusiveListNode of the object "pointed to" by the iterator + const IntrusiveListNode* node_; +}; + +/** + * \brief IntrusiveListConstIterator's "not equal to" comparison operator + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a const pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + * + * \param [in] left is a const reference to IntrusiveListConstIterator on left-hand side of comparison operator + * \param [in] right is a const reference to IntrusiveListConstIterator on right-hand side of comparison operator + * + * \return true if iterators are not equal, false otherwise + */ + +template<typename T, const IntrusiveListNode T::* NodePointer, typename U = T> +inline bool operator!=(const IntrusiveListConstIterator<T, NodePointer, U>& left, + const IntrusiveListConstIterator<T, NodePointer, U>& right) +{ + return (left == right) == false; +} + +/** + * \brief "Equal to" comparison operator for IntrusiveListIterator and IntrusiveListConstIterator + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam ConstNodePointer is a const pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + * + * \param [in] left is a const reference to IntrusiveListIterator on left-hand side of comparison operator + * \param [in] right is a const reference to IntrusiveListConstIterator on right-hand side of comparison operator + * + * \return true if both iterators are equal, false otherwise + */ + +template<typename T, IntrusiveListNode T::* NodePointer, const IntrusiveListNode T::* ConstNodePointer, typename U = T> +inline bool operator==(const IntrusiveListIterator<T, NodePointer, U>& left, + const IntrusiveListConstIterator<T, ConstNodePointer, U>& right) +{ + return decltype(right){left} == right; +} + +/** + * \brief "Not equal to" comparison operator for IntrusiveListIterator and IntrusiveListConstIterator + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam ConstNodePointer is a const pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + * + * \param [in] left is a const reference to IntrusiveListIterator on left-hand side of comparison operator + * \param [in] right is a const reference to IntrusiveListConstIterator on right-hand side of comparison operator + * + * \return true if iterators are not equal, false otherwise + */ + +template<typename T, IntrusiveListNode T::* NodePointer, const IntrusiveListNode T::* ConstNodePointer, typename U = T> +inline bool operator!=(const IntrusiveListIterator<T, NodePointer, U>& left, + const IntrusiveListConstIterator<T, ConstNodePointer, U>& right) +{ + return (left == right) == false; +} + +/** + * \brief "Not equal to" comparison operator for IntrusiveListConstIterator and IntrusiveListIterator + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam ConstNodePointer is a const pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + * + * \param [in] left is a const reference to IntrusiveListConstIterator on left-hand side of comparison operator + * \param [in] right is a const reference to IntrusiveListIterator on right-hand side of comparison operator + * + * \return true if iterators are not equal, false otherwise + */ + +template<typename T, IntrusiveListNode T::* NodePointer, const IntrusiveListNode T::* ConstNodePointer, typename U = T> +inline bool operator!=(const IntrusiveListConstIterator<T, ConstNodePointer, U>& left, + const IntrusiveListIterator<T, NodePointer, U>& right) +{ + return right != left; +} + +/** + * \brief IntrusiveList class is an intrusive circular doubly linked list. + * + * This class tries to provide an interface similar to std::list. + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; using different type than \a T can be used + * to break circular dependencies, because \a T must be fully defined to instantiate this class, but it is enough to + * forward declare \a U - it only needs to be fully defined to use member functions + */ + +template<typename T, IntrusiveListNode T::* NodePointer, typename U = T> +class IntrusiveList +{ +public: + + /// const iterator of elements on the list + using const_iterator = IntrusiveListConstIterator<T, NodePointer, U>; + + /// const reverse iterator of elements on the list + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + /// const pointer to value linked in the list + using const_pointer = const U*; + + /// const reference to value linked in the list + using const_reference = const U&; + + /// iterator of elements on the list + using iterator = IntrusiveListIterator<T, NodePointer, U>; + + /// reverse iterator of elements on the list + using reverse_iterator = std::reverse_iterator<iterator>; + + /// pointer to value linked in the list + using pointer = U*; + + /// reference to value linked in the list + using reference = U&; + + /// value linked in the list + using value_type = U; + + /** + * \brief IntrusiveList's constructor + */ + + constexpr IntrusiveList() : + intrusiveListBase_{} + { + + } + + /** + * \return reference to last element on the list + */ + + reference back() + { + return *--end(); + } + + /** + * \return const reference to last element on the list + */ + + const_reference back() const + { + return *--end(); + } + + /** + * \return iterator of first element on the list + */ + + iterator begin() + { + return iterator{&intrusiveListBase_.begin()}; + } + + /** + * \return const iterator of first element on the list + */ + + const_iterator begin() const + { + return const_iterator{&intrusiveListBase_.begin()}; + } + + /** + * \return const iterator of first element on the list + */ + + const_iterator cbegin() const + { + return begin(); + } + + /** + * \return const iterator of "one past the last" element on the list + */ + + const_iterator cend() const + { + return end(); + } + + /** + * \brief Unlinks all elements from the list. + */ + + void clear() + { + intrusiveListBase_.clear(); + } + + /** + * \return true is the list is empty, false otherwise + */ + + bool empty() const + { + return intrusiveListBase_.empty(); + } + + /** + * \return iterator of "one past the last" element on the list + */ + + iterator end() + { + return iterator{&intrusiveListBase_.end()}; + } + + /** + * \return const iterator of "one past the last" element on the list + */ + + const_iterator end() const + { + return const_iterator{&intrusiveListBase_.end()}; + } + + /** + * \return reference to first element on the list + */ + + reference front() + { + return *begin(); + } + + /** + * \return const reference to first element on the list + */ + + const_reference front() const + { + return *begin(); + } + + /** + * \brief Unlinks the last element from the list. + */ + + void pop_back() + { + erase(--end()); + } + + /** + * \brief Unlinks the first element from the list. + */ + + void pop_front() + { + erase(begin()); + } + + /** + * \brief Links the element at the end of the list. + * + * \param [in] newElement is a reference to the element that will be linked in the list + */ + + void push_back(reference newElement) + { + insert(end(), newElement); + } + + /** + * \brief Links the element at the beginning of the list. + * + * \param [in] newElement is a reference to the element that will be linked in the list + */ + + void push_front(reference newElement) + { + insert(begin(), newElement); + } + + /** + * \brief Swaps contents with another list. + * + * \param [in] other is a reference to IntrusiveList with which contents of this list will be swapped + */ + + void swap(IntrusiveList& other) + { + intrusiveListBase_.swap(other.intrusiveListBase_); + } + + /** + * \brief Unlinks the element at \a position from the list. + * + * \note No instance of the list is needed for this operation. + * + * \param [in] position is an iterator of the element that will be unlinked from the list + * + * \return iterator of the element that was following the element which was unlinked + */ + + static iterator erase(const iterator position) + { + auto& positionNode = (*position).*NodePointer; + auto& nextNode = internal::IntrusiveListBase::erase(positionNode); + return iterator{&nextNode}; + } + + /** + * \brief Links the element in the list before \a position. + * + * \note No instance of the list is needed for this operation. + * + * \param [in] position is an iterator of the element before which \a newNode will be linked + * \param [in] newElement is a reference to the element that will be linked in the list + * + * \return iterator of \a newElement + */ + + static iterator insert(const iterator position, reference newElement) + { + static_assert(std::is_convertible<U, T>::value == true, "U must be implicitly convertible to T!"); + + auto& positionNode = (*position).*NodePointer; + auto& newElementNode = newElement.*NodePointer; + internal::IntrusiveListBase::insert(positionNode, newElementNode); + return iterator{&newElementNode}; + } + + /** + * \brief Transfers the element from one list to another list before \a position. + * + * \note No instance of any list is needed for this operation. + * + * \param [in] position is an iterator of the element before which \a splicedElement will be linked + * \param [in] splicedElement is an iterator of the element that will be spliced from one list to another + */ + + static void splice(const iterator position, const iterator splicedElement) + { + auto& positionNode = (*position).*NodePointer; + auto& splicedElementNode = (*splicedElement).*NodePointer; + internal::IntrusiveListBase::splice(positionNode, splicedElementNode); + } + + IntrusiveList(const IntrusiveList&) = delete; + IntrusiveList(IntrusiveList&&) = default; + const IntrusiveList& operator=(const IntrusiveList&) = delete; + IntrusiveList& operator=(IntrusiveList&&) = delete; + +private: + + /// internal IntrusiveListBase object + internal::IntrusiveListBase intrusiveListBase_; +}; + +/** + * \brief Swaps contents of two lists. + * + * \tparam T is the type that has the IntrusiveListNode variable + * \tparam NodePointer is a pointer-to-member to IntrusiveListNode variable in \a T + * \tparam U is the type that will be stored on the list; it can be different from \a T, but must be implicitly + * convertible to \a T (so usually a type derived from \a T); default - \a T; + * + * \param [in] left is a reference to IntrusiveList with which contents of \a right will be swapped + * \param [in] right is a reference to IntrusiveList with which contents of \a left will be swapped + */ + +template<typename T, IntrusiveListNode T::* NodePointer, typename U = T> +inline void swap(IntrusiveList<T, NodePointer, U>& left, IntrusiveList<T, NodePointer, U>& right) +{ + left.swap(right); +} + +} // namespace estd + +#endif // ESTD_INTRUSIVELIST_HPP_ |