10b57cec5SDimitry Andric //===- llvm/ADT/simple_ilist.h - Simple Intrusive List ----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_ADT_SIMPLE_ILIST_H
100b57cec5SDimitry Andric #define LLVM_ADT_SIMPLE_ILIST_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "llvm/ADT/ilist_base.h"
130b57cec5SDimitry Andric #include "llvm/ADT/ilist_iterator.h"
140b57cec5SDimitry Andric #include "llvm/ADT/ilist_node.h"
150b57cec5SDimitry Andric #include "llvm/ADT/ilist_node_options.h"
160b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
170b57cec5SDimitry Andric #include <algorithm>
180b57cec5SDimitry Andric #include <cassert>
190b57cec5SDimitry Andric #include <cstddef>
200b57cec5SDimitry Andric #include <functional>
210b57cec5SDimitry Andric #include <iterator>
220b57cec5SDimitry Andric #include <utility>
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace llvm {
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric /// A simple intrusive list implementation.
270b57cec5SDimitry Andric ///
280b57cec5SDimitry Andric /// This is a simple intrusive list for a \c T that inherits from \c
290b57cec5SDimitry Andric /// ilist_node<T>.  The list never takes ownership of anything inserted in it.
300b57cec5SDimitry Andric ///
31e8d8bef9SDimitry Andric /// Unlike \a iplist<T> and \a ilist<T>, \a simple_ilist<T> never deletes
32e8d8bef9SDimitry Andric /// values, and has no callback traits.
330b57cec5SDimitry Andric ///
340b57cec5SDimitry Andric /// The API for adding nodes include \a push_front(), \a push_back(), and \a
350b57cec5SDimitry Andric /// insert().  These all take values by reference (not by pointer), except for
360b57cec5SDimitry Andric /// the range version of \a insert().
370b57cec5SDimitry Andric ///
380b57cec5SDimitry Andric /// There are three sets of API for discarding nodes from the list: \a
390b57cec5SDimitry Andric /// remove(), which takes a reference to the node to remove, \a erase(), which
400b57cec5SDimitry Andric /// takes an iterator or iterator range and returns the next one, and \a
410b57cec5SDimitry Andric /// clear(), which empties out the container.  All three are constant time
420b57cec5SDimitry Andric /// operations.  None of these deletes any nodes; in particular, if there is a
430b57cec5SDimitry Andric /// single node in the list, then these have identical semantics:
440b57cec5SDimitry Andric /// \li \c L.remove(L.front());
450b57cec5SDimitry Andric /// \li \c L.erase(L.begin());
460b57cec5SDimitry Andric /// \li \c L.clear();
470b57cec5SDimitry Andric ///
480b57cec5SDimitry Andric /// As a convenience for callers, there are parallel APIs that take a \c
490b57cec5SDimitry Andric /// Disposer (such as \c std::default_delete<T>): \a removeAndDispose(), \a
500b57cec5SDimitry Andric /// eraseAndDispose(), and \a clearAndDispose().  These have different names
510b57cec5SDimitry Andric /// because the extra semantic is otherwise non-obvious.  They are equivalent
520b57cec5SDimitry Andric /// to calling \a std::for_each() on the range to be discarded.
530b57cec5SDimitry Andric ///
540b57cec5SDimitry Andric /// The currently available \p Options customize the nodes in the list.  The
55e8d8bef9SDimitry Andric /// same options must be specified in the \a ilist_node instantiation for
560b57cec5SDimitry Andric /// compatibility (although the order is irrelevant).
570b57cec5SDimitry Andric /// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
580b57cec5SDimitry Andric /// list should use.  This is useful if a type \p T is part of multiple,
590b57cec5SDimitry Andric /// independent lists simultaneously.
600b57cec5SDimitry Andric /// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
610b57cec5SDimitry Andric /// node is a sentinel.  Specifying \c true enables the \a
620b57cec5SDimitry Andric /// ilist_node::isSentinel() API.  Unlike \a ilist_node::isKnownSentinel(),
630b57cec5SDimitry Andric /// which is only appropriate for assertions, \a ilist_node::isSentinel() is
640b57cec5SDimitry Andric /// appropriate for real logic.
650b57cec5SDimitry Andric ///
660b57cec5SDimitry Andric /// Here are examples of \p Options usage:
670b57cec5SDimitry Andric /// \li \c simple_ilist<T> gives the defaults.  \li \c
680b57cec5SDimitry Andric /// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a
690b57cec5SDimitry Andric /// ilist_node::isSentinel() API.
700b57cec5SDimitry Andric /// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>>
710b57cec5SDimitry Andric /// specifies a tag of A and that tracking should be off (even when
720b57cec5SDimitry Andric /// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
730b57cec5SDimitry Andric /// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is
740b57cec5SDimitry Andric /// equivalent to the last.
750b57cec5SDimitry Andric ///
760b57cec5SDimitry Andric /// See \a is_valid_option for steps on adding a new option.
770b57cec5SDimitry Andric template <typename T, class... Options>
780b57cec5SDimitry Andric class simple_ilist
790b57cec5SDimitry Andric     : ilist_detail::compute_node_options<T, Options...>::type::list_base_type,
800b57cec5SDimitry Andric       ilist_detail::SpecificNodeAccess<
810b57cec5SDimitry Andric           typename ilist_detail::compute_node_options<T, Options...>::type> {
820b57cec5SDimitry Andric   static_assert(ilist_detail::check_options<Options...>::value,
830b57cec5SDimitry Andric                 "Unrecognized node option!");
840b57cec5SDimitry Andric   using OptionsT =
850b57cec5SDimitry Andric       typename ilist_detail::compute_node_options<T, Options...>::type;
860b57cec5SDimitry Andric   using list_base_type = typename OptionsT::list_base_type;
870b57cec5SDimitry Andric   ilist_sentinel<OptionsT> Sentinel;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric public:
900b57cec5SDimitry Andric   using value_type = typename OptionsT::value_type;
910b57cec5SDimitry Andric   using pointer = typename OptionsT::pointer;
920b57cec5SDimitry Andric   using reference = typename OptionsT::reference;
930b57cec5SDimitry Andric   using const_pointer = typename OptionsT::const_pointer;
940b57cec5SDimitry Andric   using const_reference = typename OptionsT::const_reference;
955f757f3fSDimitry Andric   using iterator =
965f757f3fSDimitry Andric       typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
975f757f3fSDimitry Andric                                           false, false>::type;
985f757f3fSDimitry Andric   using const_iterator =
995f757f3fSDimitry Andric       typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
1005f757f3fSDimitry Andric                                           false, true>::type;
1015f757f3fSDimitry Andric   using reverse_iterator =
1025f757f3fSDimitry Andric       typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
1035f757f3fSDimitry Andric                                           true, false>::type;
1045f757f3fSDimitry Andric   using const_reverse_iterator =
1055f757f3fSDimitry Andric       typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
1065f757f3fSDimitry Andric                                           true, true>::type;
1070b57cec5SDimitry Andric   using size_type = size_t;
1080b57cec5SDimitry Andric   using difference_type = ptrdiff_t;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   simple_ilist() = default;
1110b57cec5SDimitry Andric   ~simple_ilist() = default;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   // No copy constructors.
1140b57cec5SDimitry Andric   simple_ilist(const simple_ilist &) = delete;
1150b57cec5SDimitry Andric   simple_ilist &operator=(const simple_ilist &) = delete;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   // Move constructors.
simple_ilist(simple_ilist && X)1180b57cec5SDimitry Andric   simple_ilist(simple_ilist &&X) { splice(end(), X); }
1190b57cec5SDimitry Andric   simple_ilist &operator=(simple_ilist &&X) {
1200b57cec5SDimitry Andric     clear();
1210b57cec5SDimitry Andric     splice(end(), X);
1220b57cec5SDimitry Andric     return *this;
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric 
begin()1250b57cec5SDimitry Andric   iterator begin() { return ++iterator(Sentinel); }
begin()1260b57cec5SDimitry Andric   const_iterator begin() const { return ++const_iterator(Sentinel); }
end()1270b57cec5SDimitry Andric   iterator end() { return iterator(Sentinel); }
end()1280b57cec5SDimitry Andric   const_iterator end() const { return const_iterator(Sentinel); }
rbegin()1290b57cec5SDimitry Andric   reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); }
rbegin()1300b57cec5SDimitry Andric   const_reverse_iterator rbegin() const {
1310b57cec5SDimitry Andric     return ++const_reverse_iterator(Sentinel);
1320b57cec5SDimitry Andric   }
rend()1330b57cec5SDimitry Andric   reverse_iterator rend() { return reverse_iterator(Sentinel); }
rend()1340b57cec5SDimitry Andric   const_reverse_iterator rend() const {
1350b57cec5SDimitry Andric     return const_reverse_iterator(Sentinel);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   /// Check if the list is empty in constant time.
empty()139bdd1243dSDimitry Andric   [[nodiscard]] bool empty() const { return Sentinel.empty(); }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// Calculate the size of the list in linear time.
size()142bdd1243dSDimitry Andric   [[nodiscard]] size_type size() const { return std::distance(begin(), end()); }
1430b57cec5SDimitry Andric 
front()1440b57cec5SDimitry Andric   reference front() { return *begin(); }
front()1450b57cec5SDimitry Andric   const_reference front() const { return *begin(); }
back()1460b57cec5SDimitry Andric   reference back() { return *rbegin(); }
back()1470b57cec5SDimitry Andric   const_reference back() const { return *rbegin(); }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   /// Insert a node at the front; never copies.
push_front(reference Node)1500b57cec5SDimitry Andric   void push_front(reference Node) { insert(begin(), Node); }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   /// Insert a node at the back; never copies.
push_back(reference Node)1530b57cec5SDimitry Andric   void push_back(reference Node) { insert(end(), Node); }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   /// Remove the node at the front; never deletes.
pop_front()1560b57cec5SDimitry Andric   void pop_front() { erase(begin()); }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   /// Remove the node at the back; never deletes.
pop_back()1590b57cec5SDimitry Andric   void pop_back() { erase(--end()); }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   /// Swap with another list in place using std::swap.
swap(simple_ilist & X)1620b57cec5SDimitry Andric   void swap(simple_ilist &X) { std::swap(*this, X); }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   /// Insert a node by reference; never copies.
insert(iterator I,reference Node)1650b57cec5SDimitry Andric   iterator insert(iterator I, reference Node) {
1660b57cec5SDimitry Andric     list_base_type::insertBefore(*I.getNodePtr(), *this->getNodePtr(&Node));
1670b57cec5SDimitry Andric     return iterator(&Node);
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   /// Insert a range of nodes; never copies.
1710b57cec5SDimitry Andric   template <class Iterator>
insert(iterator I,Iterator First,Iterator Last)1720b57cec5SDimitry Andric   void insert(iterator I, Iterator First, Iterator Last) {
1730b57cec5SDimitry Andric     for (; First != Last; ++First)
1740b57cec5SDimitry Andric       insert(I, *First);
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   /// Clone another list.
1780b57cec5SDimitry Andric   template <class Cloner, class Disposer>
cloneFrom(const simple_ilist & L2,Cloner clone,Disposer dispose)1790b57cec5SDimitry Andric   void cloneFrom(const simple_ilist &L2, Cloner clone, Disposer dispose) {
1800b57cec5SDimitry Andric     clearAndDispose(dispose);
1810b57cec5SDimitry Andric     for (const_reference V : L2)
1820b57cec5SDimitry Andric       push_back(*clone(V));
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   /// Remove a node by reference; never deletes.
1860b57cec5SDimitry Andric   ///
1870b57cec5SDimitry Andric   /// \see \a erase() for removing by iterator.
1880b57cec5SDimitry Andric   /// \see \a removeAndDispose() if the node should be deleted.
remove(reference N)1890b57cec5SDimitry Andric   void remove(reference N) { list_base_type::remove(*this->getNodePtr(&N)); }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   /// Remove a node by reference and dispose of it.
1920b57cec5SDimitry Andric   template <class Disposer>
removeAndDispose(reference N,Disposer dispose)1930b57cec5SDimitry Andric   void removeAndDispose(reference N, Disposer dispose) {
1940b57cec5SDimitry Andric     remove(N);
1950b57cec5SDimitry Andric     dispose(&N);
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   /// Remove a node by iterator; never deletes.
1990b57cec5SDimitry Andric   ///
2000b57cec5SDimitry Andric   /// \see \a remove() for removing by reference.
2010b57cec5SDimitry Andric   /// \see \a eraseAndDispose() it the node should be deleted.
erase(iterator I)2020b57cec5SDimitry Andric   iterator erase(iterator I) {
2030b57cec5SDimitry Andric     assert(I != end() && "Cannot remove end of list!");
2040b57cec5SDimitry Andric     remove(*I++);
2050b57cec5SDimitry Andric     return I;
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   /// Remove a range of nodes; never deletes.
2090b57cec5SDimitry Andric   ///
2100b57cec5SDimitry Andric   /// \see \a eraseAndDispose() if the nodes should be deleted.
erase(iterator First,iterator Last)2110b57cec5SDimitry Andric   iterator erase(iterator First, iterator Last) {
2120b57cec5SDimitry Andric     list_base_type::removeRange(*First.getNodePtr(), *Last.getNodePtr());
2130b57cec5SDimitry Andric     return Last;
2140b57cec5SDimitry Andric   }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   /// Remove a node by iterator and dispose of it.
2170b57cec5SDimitry Andric   template <class Disposer>
eraseAndDispose(iterator I,Disposer dispose)2180b57cec5SDimitry Andric   iterator eraseAndDispose(iterator I, Disposer dispose) {
2190b57cec5SDimitry Andric     auto Next = std::next(I);
2200b57cec5SDimitry Andric     erase(I);
2210b57cec5SDimitry Andric     dispose(&*I);
2220b57cec5SDimitry Andric     return Next;
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   /// Remove a range of nodes and dispose of them.
2260b57cec5SDimitry Andric   template <class Disposer>
eraseAndDispose(iterator First,iterator Last,Disposer dispose)2270b57cec5SDimitry Andric   iterator eraseAndDispose(iterator First, iterator Last, Disposer dispose) {
2280b57cec5SDimitry Andric     while (First != Last)
2290b57cec5SDimitry Andric       First = eraseAndDispose(First, dispose);
2300b57cec5SDimitry Andric     return Last;
2310b57cec5SDimitry Andric   }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   /// Clear the list; never deletes.
2340b57cec5SDimitry Andric   ///
2350b57cec5SDimitry Andric   /// \see \a clearAndDispose() if the nodes should be deleted.
clear()2360b57cec5SDimitry Andric   void clear() { Sentinel.reset(); }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   /// Clear the list and dispose of the nodes.
clearAndDispose(Disposer dispose)2390b57cec5SDimitry Andric   template <class Disposer> void clearAndDispose(Disposer dispose) {
2400b57cec5SDimitry Andric     eraseAndDispose(begin(), end(), dispose);
2410b57cec5SDimitry Andric   }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric   /// Splice in another list.
splice(iterator I,simple_ilist & L2)2440b57cec5SDimitry Andric   void splice(iterator I, simple_ilist &L2) {
2450b57cec5SDimitry Andric     splice(I, L2, L2.begin(), L2.end());
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   /// Splice in a node from another list.
splice(iterator I,simple_ilist & L2,iterator Node)2490b57cec5SDimitry Andric   void splice(iterator I, simple_ilist &L2, iterator Node) {
2500b57cec5SDimitry Andric     splice(I, L2, Node, std::next(Node));
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   /// Splice in a range of nodes from another list.
splice(iterator I,simple_ilist &,iterator First,iterator Last)2540b57cec5SDimitry Andric   void splice(iterator I, simple_ilist &, iterator First, iterator Last) {
2550b57cec5SDimitry Andric     list_base_type::transferBefore(*I.getNodePtr(), *First.getNodePtr(),
2560b57cec5SDimitry Andric                                    *Last.getNodePtr());
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   /// Merge in another list.
2600b57cec5SDimitry Andric   ///
2610b57cec5SDimitry Andric   /// \pre \c this and \p RHS are sorted.
2620b57cec5SDimitry Andric   ///@{
merge(simple_ilist & RHS)2630b57cec5SDimitry Andric   void merge(simple_ilist &RHS) { merge(RHS, std::less<T>()); }
2640b57cec5SDimitry Andric   template <class Compare> void merge(simple_ilist &RHS, Compare comp);
2650b57cec5SDimitry Andric   ///@}
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   /// Sort the list.
2680b57cec5SDimitry Andric   ///@{
sort()2690b57cec5SDimitry Andric   void sort() { sort(std::less<T>()); }
2700b57cec5SDimitry Andric   template <class Compare> void sort(Compare comp);
2710b57cec5SDimitry Andric   ///@}
2720b57cec5SDimitry Andric };
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric template <class T, class... Options>
2750b57cec5SDimitry Andric template <class Compare>
merge(simple_ilist & RHS,Compare comp)2760b57cec5SDimitry Andric void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
2770b57cec5SDimitry Andric   if (this == &RHS || RHS.empty())
2780b57cec5SDimitry Andric     return;
2790b57cec5SDimitry Andric   iterator LI = begin(), LE = end();
2800b57cec5SDimitry Andric   iterator RI = RHS.begin(), RE = RHS.end();
2810b57cec5SDimitry Andric   while (LI != LE) {
2820b57cec5SDimitry Andric     if (comp(*RI, *LI)) {
2830b57cec5SDimitry Andric       // Transfer a run of at least size 1 from RHS to LHS.
2840b57cec5SDimitry Andric       iterator RunStart = RI++;
2850b57cec5SDimitry Andric       RI = std::find_if(RI, RE, [&](reference RV) { return !comp(RV, *LI); });
2860b57cec5SDimitry Andric       splice(LI, RHS, RunStart, RI);
2870b57cec5SDimitry Andric       if (RI == RE)
2880b57cec5SDimitry Andric         return;
2890b57cec5SDimitry Andric     }
2900b57cec5SDimitry Andric     ++LI;
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric   // Transfer the remaining RHS nodes once LHS is finished.
2930b57cec5SDimitry Andric   splice(LE, RHS, RI, RE);
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric template <class T, class... Options>
2970b57cec5SDimitry Andric template <class Compare>
sort(Compare comp)2980b57cec5SDimitry Andric void simple_ilist<T, Options...>::sort(Compare comp) {
2990b57cec5SDimitry Andric   // Vacuously sorted.
3000b57cec5SDimitry Andric   if (empty() || std::next(begin()) == end())
3010b57cec5SDimitry Andric     return;
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   // Split the list in the middle.
3040b57cec5SDimitry Andric   iterator Center = begin(), End = begin();
3050b57cec5SDimitry Andric   while (End != end() && ++End != end()) {
3060b57cec5SDimitry Andric     ++Center;
3070b57cec5SDimitry Andric     ++End;
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric   simple_ilist RHS;
3100b57cec5SDimitry Andric   RHS.splice(RHS.end(), *this, Center, end());
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   // Sort the sublists and merge back together.
3130b57cec5SDimitry Andric   sort(comp);
3140b57cec5SDimitry Andric   RHS.sort(comp);
3150b57cec5SDimitry Andric   merge(RHS, comp);
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric } // end namespace llvm
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric #endif // LLVM_ADT_SIMPLE_ILIST_H
321