| //===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator ------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ADT_ILIST_ITERATOR_H |
| #define LLVM_ADT_ILIST_ITERATOR_H |
| |
| #include "llvm/ADT/ilist_node.h" |
| #include <cassert> |
| #include <cstddef> |
| #include <iterator> |
| #include <type_traits> |
| |
| namespace llvm { |
| |
| namespace ilist_detail { |
| |
| /// Find const-correct node types. |
| template <class OptionsT, bool IsConst> struct IteratorTraits; |
| template <class OptionsT> struct IteratorTraits<OptionsT, false> { |
| using value_type = typename OptionsT::value_type; |
| using pointer = typename OptionsT::pointer; |
| using reference = typename OptionsT::reference; |
| using node_pointer = ilist_node_impl<OptionsT> *; |
| using node_reference = ilist_node_impl<OptionsT> &; |
| }; |
| template <class OptionsT> struct IteratorTraits<OptionsT, true> { |
| using value_type = const typename OptionsT::value_type; |
| using pointer = typename OptionsT::const_pointer; |
| using reference = typename OptionsT::const_reference; |
| using node_pointer = const ilist_node_impl<OptionsT> *; |
| using node_reference = const ilist_node_impl<OptionsT> &; |
| }; |
| |
| template <bool IsReverse> struct IteratorHelper; |
| template <> struct IteratorHelper<false> : ilist_detail::NodeAccess { |
| using Access = ilist_detail::NodeAccess; |
| |
| template <class T> static void increment(T *&I) { I = Access::getNext(*I); } |
| template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); } |
| }; |
| template <> struct IteratorHelper<true> : ilist_detail::NodeAccess { |
| using Access = ilist_detail::NodeAccess; |
| |
| template <class T> static void increment(T *&I) { I = Access::getPrev(*I); } |
| template <class T> static void decrement(T *&I) { I = Access::getNext(*I); } |
| }; |
| |
| } // end namespace ilist_detail |
| |
| /// Iterator for intrusive lists based on ilist_node. |
| template <class OptionsT, bool IsReverse, bool IsConst> |
| class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> { |
| friend ilist_iterator<OptionsT, IsReverse, !IsConst>; |
| friend ilist_iterator<OptionsT, !IsReverse, IsConst>; |
| friend ilist_iterator<OptionsT, !IsReverse, !IsConst>; |
| |
| using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>; |
| using Access = ilist_detail::SpecificNodeAccess<OptionsT>; |
| |
| public: |
| using value_type = typename Traits::value_type; |
| using pointer = typename Traits::pointer; |
| using reference = typename Traits::reference; |
| using difference_type = ptrdiff_t; |
| using iterator_category = std::bidirectional_iterator_tag; |
| using const_pointer = typename OptionsT::const_pointer; |
| using const_reference = typename OptionsT::const_reference; |
| |
| private: |
| using node_pointer = typename Traits::node_pointer; |
| using node_reference = typename Traits::node_reference; |
| |
| node_pointer NodePtr = nullptr; |
| |
| public: |
| /// Create from an ilist_node. |
| explicit ilist_iterator(node_reference N) : NodePtr(&N) {} |
| |
| explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {} |
| explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {} |
| ilist_iterator() = default; |
| |
| // This is templated so that we can allow constructing a const iterator from |
| // a nonconst iterator... |
| template <bool RHSIsConst> |
| ilist_iterator(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS, |
| std::enable_if_t<IsConst || !RHSIsConst, void *> = nullptr) |
| : NodePtr(RHS.NodePtr) {} |
| |
| // This is templated so that we can allow assigning to a const iterator from |
| // a nonconst iterator... |
| template <bool RHSIsConst> |
| std::enable_if_t<IsConst || !RHSIsConst, ilist_iterator &> |
| operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) { |
| NodePtr = RHS.NodePtr; |
| return *this; |
| } |
| |
| /// Explicit conversion between forward/reverse iterators. |
| /// |
| /// Translate between forward and reverse iterators without changing range |
| /// boundaries. The resulting iterator will dereference (and have a handle) |
| /// to the previous node, which is somewhat unexpected; but converting the |
| /// two endpoints in a range will give the same range in reverse. |
| /// |
| /// This matches std::reverse_iterator conversions. |
| explicit ilist_iterator( |
| const ilist_iterator<OptionsT, !IsReverse, IsConst> &RHS) |
| : ilist_iterator(++RHS.getReverse()) {} |
| |
| /// Get a reverse iterator to the same node. |
| /// |
| /// Gives a reverse iterator that will dereference (and have a handle) to the |
| /// same node. Converting the endpoint iterators in a range will give a |
| /// different range; for range operations, use the explicit conversions. |
| ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const { |
| if (NodePtr) |
| return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr); |
| return ilist_iterator<OptionsT, !IsReverse, IsConst>(); |
| } |
| |
| /// Const-cast. |
| ilist_iterator<OptionsT, IsReverse, false> getNonConst() const { |
| if (NodePtr) |
| return ilist_iterator<OptionsT, IsReverse, false>( |
| const_cast<typename ilist_iterator<OptionsT, IsReverse, |
| false>::node_reference>(*NodePtr)); |
| return ilist_iterator<OptionsT, IsReverse, false>(); |
| } |
| |
| // Accessors... |
| reference operator*() const { |
| assert(!NodePtr->isKnownSentinel()); |
| return *Access::getValuePtr(NodePtr); |
| } |
| pointer operator->() const { return &operator*(); } |
| |
| // Comparison operators |
| friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) { |
| return LHS.NodePtr == RHS.NodePtr; |
| } |
| friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) { |
| return LHS.NodePtr != RHS.NodePtr; |
| } |
| |
| // Increment and decrement operators... |
| ilist_iterator &operator--() { |
| NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev(); |
| return *this; |
| } |
| ilist_iterator &operator++() { |
| NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext(); |
| return *this; |
| } |
| ilist_iterator operator--(int) { |
| ilist_iterator tmp = *this; |
| --*this; |
| return tmp; |
| } |
| ilist_iterator operator++(int) { |
| ilist_iterator tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| |
| /// Get the underlying ilist_node. |
| node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); } |
| |
| /// Check for end. Only valid if ilist_sentinel_tracking<true>. |
| bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; } |
| }; |
| |
| template <typename From> struct simplify_type; |
| |
| /// Allow ilist_iterators to convert into pointers to a node automatically when |
| /// used by the dyn_cast, cast, isa mechanisms... |
| /// |
| /// FIXME: remove this, since there is no implicit conversion to NodeTy. |
| template <class OptionsT, bool IsConst> |
| struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> { |
| using iterator = ilist_iterator<OptionsT, false, IsConst>; |
| using SimpleType = typename iterator::pointer; |
| |
| static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; } |
| }; |
| template <class OptionsT, bool IsConst> |
| struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>> |
| : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {}; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_ADT_ILIST_ITERATOR_H |