1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
|
//===- llvm/ADT/simple_ilist.h - Simple Intrusive List ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SIMPLE_ILIST_H
#define LLVM_ADT_SIMPLE_ILIST_H
#include "llvm/ADT/ilist_base.h"
#include "llvm/ADT/ilist_iterator.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ilist_node_options.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <functional>
#include <iterator>
#include <utility>
namespace llvm {
/// A simple intrusive list implementation.
///
/// This is a simple intrusive list for a \c T that inherits from \c
/// ilist_node<T>. The list never takes ownership of anything inserted in it.
///
/// Unlike \a iplist<T> and \a ilist<T>, \a simple_ilist<T> never allocates or
/// deletes values, and has no callback traits.
///
/// The API for adding nodes include \a push_front(), \a push_back(), and \a
/// insert(). These all take values by reference (not by pointer), except for
/// the range version of \a insert().
///
/// There are three sets of API for discarding nodes from the list: \a
/// remove(), which takes a reference to the node to remove, \a erase(), which
/// takes an iterator or iterator range and returns the next one, and \a
/// clear(), which empties out the container. All three are constant time
/// operations. None of these deletes any nodes; in particular, if there is a
/// single node in the list, then these have identical semantics:
/// \li \c L.remove(L.front());
/// \li \c L.erase(L.begin());
/// \li \c L.clear();
///
/// As a convenience for callers, there are parallel APIs that take a \c
/// Disposer (such as \c std::default_delete<T>): \a removeAndDispose(), \a
/// eraseAndDispose(), and \a clearAndDispose(). These have different names
/// because the extra semantic is otherwise non-obvious. They are equivalent
/// to calling \a std::for_each() on the range to be discarded.
///
/// The currently available \p Options customize the nodes in the list. The
/// same options must be specified in the \a ilist_node instantation for
/// compatibility (although the order is irrelevant).
/// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
/// list should use. This is useful if a type \p T is part of multiple,
/// independent lists simultaneously.
/// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
/// node is a sentinel. Specifying \c true enables the \a
/// ilist_node::isSentinel() API. Unlike \a ilist_node::isKnownSentinel(),
/// which is only appropriate for assertions, \a ilist_node::isSentinel() is
/// appropriate for real logic.
///
/// Here are examples of \p Options usage:
/// \li \c simple_ilist<T> gives the defaults. \li \c
/// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a
/// ilist_node::isSentinel() API.
/// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>>
/// specifies a tag of A and that tracking should be off (even when
/// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
/// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is
/// equivalent to the last.
///
/// See \a is_valid_option for steps on adding a new option.
template <typename T, class... Options>
class simple_ilist
: ilist_detail::compute_node_options<T, Options...>::type::list_base_type,
ilist_detail::SpecificNodeAccess<
typename ilist_detail::compute_node_options<T, Options...>::type> {
static_assert(ilist_detail::check_options<Options...>::value,
"Unrecognized node option!");
using OptionsT =
typename ilist_detail::compute_node_options<T, Options...>::type;
using list_base_type = typename OptionsT::list_base_type;
ilist_sentinel<OptionsT> Sentinel;
public:
using value_type = typename OptionsT::value_type;
using pointer = typename OptionsT::pointer;
using reference = typename OptionsT::reference;
using const_pointer = typename OptionsT::const_pointer;
using const_reference = typename OptionsT::const_reference;
using iterator = ilist_iterator<OptionsT, false, false>;
using const_iterator = ilist_iterator<OptionsT, false, true>;
using reverse_iterator = ilist_iterator<OptionsT, true, false>;
using const_reverse_iterator = ilist_iterator<OptionsT, true, true>;
using size_type = size_t;
using difference_type = ptrdiff_t;
simple_ilist() = default;
~simple_ilist() = default;
// No copy constructors.
simple_ilist(const simple_ilist &) = delete;
simple_ilist &operator=(const simple_ilist &) = delete;
// Move constructors.
simple_ilist(simple_ilist &&X) { splice(end(), X); }
simple_ilist &operator=(simple_ilist &&X) {
clear();
splice(end(), X);
return *this;
}
iterator begin() { return ++iterator(Sentinel); }
const_iterator begin() const { return ++const_iterator(Sentinel); }
iterator end() { return iterator(Sentinel); }
const_iterator end() const { return const_iterator(Sentinel); }
reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); }
const_reverse_iterator rbegin() const {
return ++const_reverse_iterator(Sentinel);
}
reverse_iterator rend() { return reverse_iterator(Sentinel); }
const_reverse_iterator rend() const {
return const_reverse_iterator(Sentinel);
}
/// Check if the list is empty in constant time.
LLVM_NODISCARD bool empty() const { return Sentinel.empty(); }
/// Calculate the size of the list in linear time.
LLVM_NODISCARD size_type size() const {
return std::distance(begin(), end());
}
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *rbegin(); }
const_reference back() const { return *rbegin(); }
/// Insert a node at the front; never copies.
void push_front(reference Node) { insert(begin(), Node); }
/// Insert a node at the back; never copies.
void push_back(reference Node) { insert(end(), Node); }
/// Remove the node at the front; never deletes.
void pop_front() { erase(begin()); }
/// Remove the node at the back; never deletes.
void pop_back() { erase(--end()); }
/// Swap with another list in place using std::swap.
void swap(simple_ilist &X) { std::swap(*this, X); }
/// Insert a node by reference; never copies.
iterator insert(iterator I, reference Node) {
list_base_type::insertBefore(*I.getNodePtr(), *this->getNodePtr(&Node));
return iterator(&Node);
}
/// Insert a range of nodes; never copies.
template <class Iterator>
void insert(iterator I, Iterator First, Iterator Last) {
for (; First != Last; ++First)
insert(I, *First);
}
/// Clone another list.
template <class Cloner, class Disposer>
void cloneFrom(const simple_ilist &L2, Cloner clone, Disposer dispose) {
clearAndDispose(dispose);
for (const_reference V : L2)
push_back(*clone(V));
}
/// Remove a node by reference; never deletes.
///
/// \see \a erase() for removing by iterator.
/// \see \a removeAndDispose() if the node should be deleted.
void remove(reference N) { list_base_type::remove(*this->getNodePtr(&N)); }
/// Remove a node by reference and dispose of it.
template <class Disposer>
void removeAndDispose(reference N, Disposer dispose) {
remove(N);
dispose(&N);
}
/// Remove a node by iterator; never deletes.
///
/// \see \a remove() for removing by reference.
/// \see \a eraseAndDispose() it the node should be deleted.
iterator erase(iterator I) {
assert(I != end() && "Cannot remove end of list!");
remove(*I++);
return I;
}
/// Remove a range of nodes; never deletes.
///
/// \see \a eraseAndDispose() if the nodes should be deleted.
iterator erase(iterator First, iterator Last) {
list_base_type::removeRange(*First.getNodePtr(), *Last.getNodePtr());
return Last;
}
/// Remove a node by iterator and dispose of it.
template <class Disposer>
iterator eraseAndDispose(iterator I, Disposer dispose) {
auto Next = std::next(I);
erase(I);
dispose(&*I);
return Next;
}
/// Remove a range of nodes and dispose of them.
template <class Disposer>
iterator eraseAndDispose(iterator First, iterator Last, Disposer dispose) {
while (First != Last)
First = eraseAndDispose(First, dispose);
return Last;
}
/// Clear the list; never deletes.
///
/// \see \a clearAndDispose() if the nodes should be deleted.
void clear() { Sentinel.reset(); }
/// Clear the list and dispose of the nodes.
template <class Disposer> void clearAndDispose(Disposer dispose) {
eraseAndDispose(begin(), end(), dispose);
}
/// Splice in another list.
void splice(iterator I, simple_ilist &L2) {
splice(I, L2, L2.begin(), L2.end());
}
/// Splice in a node from another list.
void splice(iterator I, simple_ilist &L2, iterator Node) {
splice(I, L2, Node, std::next(Node));
}
/// Splice in a range of nodes from another list.
void splice(iterator I, simple_ilist &, iterator First, iterator Last) {
list_base_type::transferBefore(*I.getNodePtr(), *First.getNodePtr(),
*Last.getNodePtr());
}
/// Merge in another list.
///
/// \pre \c this and \p RHS are sorted.
///@{
void merge(simple_ilist &RHS) { merge(RHS, std::less<T>()); }
template <class Compare> void merge(simple_ilist &RHS, Compare comp);
///@}
/// Sort the list.
///@{
void sort() { sort(std::less<T>()); }
template <class Compare> void sort(Compare comp);
///@}
};
template <class T, class... Options>
template <class Compare>
void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
if (this == &RHS || RHS.empty())
return;
iterator LI = begin(), LE = end();
iterator RI = RHS.begin(), RE = RHS.end();
while (LI != LE) {
if (comp(*RI, *LI)) {
// Transfer a run of at least size 1 from RHS to LHS.
iterator RunStart = RI++;
RI = std::find_if(RI, RE, [&](reference RV) { return !comp(RV, *LI); });
splice(LI, RHS, RunStart, RI);
if (RI == RE)
return;
}
++LI;
}
// Transfer the remaining RHS nodes once LHS is finished.
splice(LE, RHS, RI, RE);
}
template <class T, class... Options>
template <class Compare>
void simple_ilist<T, Options...>::sort(Compare comp) {
// Vacuously sorted.
if (empty() || std::next(begin()) == end())
return;
// Split the list in the middle.
iterator Center = begin(), End = begin();
while (End != end() && ++End != end()) {
++Center;
++End;
}
simple_ilist RHS;
RHS.splice(RHS.end(), *this, Center, end());
// Sort the sublists and merge back together.
sort(comp);
RHS.sort(comp);
merge(RHS, comp);
}
} // end namespace llvm
#endif // LLVM_ADT_SIMPLE_ILIST_H
|