LLVM 22.0.0git
ilist_node.h
Go to the documentation of this file.
1//===- llvm/ADT/ilist_node.h - Intrusive Linked List Helper -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file defines the ilist_node class template, which is a convenient
11/// base class for creating classes that can be used with ilists.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_ILIST_NODE_H
16#define LLVM_ADT_ILIST_NODE_H
17
20
21#include <type_traits>
22
23namespace llvm {
24
25namespace ilist_detail {
26
27struct NodeAccess;
28
29/// Mixin base class that is used to add \a getParent() and
30/// \a setParent(ParentTy*) methods to \a ilist_node_impl iff \a ilist_parent
31/// has been set in the list options.
32template <class NodeTy, class ParentTy> class node_parent_access {
33public:
34 inline const ParentTy *getParent() const {
35 return static_cast<const NodeTy *>(this)->getNodeBaseParent();
36 }
37 inline ParentTy *getParent() {
38 return static_cast<NodeTy *>(this)->getNodeBaseParent();
39 }
40 void setParent(ParentTy *Parent) {
41 return static_cast<NodeTy *>(this)->setNodeBaseParent(Parent);
42 }
43};
44template <class NodeTy> class node_parent_access<NodeTy, void> {};
45
46} // end namespace ilist_detail
47
48template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
49template <class OptionsT, bool IsReverse, bool IsConst>
51template <class OptionsT> class ilist_sentinel;
52
53// Selector for which iterator type to pick given the iterator-bits node option.
54template <bool use_iterator_bits, typename Opts, bool arg1, bool arg2>
56 using type = std::conditional_t<use_iterator_bits,
59};
60
61/// Implementation for an ilist node.
62///
63/// Templated on an appropriate \a ilist_detail::node_options, usually computed
64/// by \a ilist_detail::compute_node_options.
65///
66/// This is a wrapper around \a ilist_node_base whose main purpose is to
67/// provide type safety: you can't insert nodes of \a ilist_node_impl into the
68/// wrong \a simple_ilist or \a iplist.
69template <class OptionsT>
71 : OptionsT::node_base_type,
72 public ilist_detail::node_parent_access<ilist_node_impl<OptionsT>,
73 typename OptionsT::parent_ty> {
74 using value_type = typename OptionsT::value_type;
75 using node_base_type = typename OptionsT::node_base_type;
76 using list_base_type = typename OptionsT::list_base_type;
77
78 friend typename OptionsT::list_base_type;
80 friend class ilist_sentinel<OptionsT>;
81
83 typename OptionsT::parent_ty>;
84 friend class ilist_iterator<OptionsT, false, false>;
85 friend class ilist_iterator<OptionsT, false, true>;
86 friend class ilist_iterator<OptionsT, true, false>;
87 friend class ilist_iterator<OptionsT, true, true>;
88 friend class ilist_iterator_w_bits<OptionsT, false, false>;
89 friend class ilist_iterator_w_bits<OptionsT, false, true>;
90 friend class ilist_iterator_w_bits<OptionsT, true, false>;
91 friend class ilist_iterator_w_bits<OptionsT, true, true>;
92
93protected:
95 typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
96 false, false>::type;
98 typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
99 false, true>::type;
101 typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
102 true, false>::type;
104 typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
105 true, true>::type;
106
107 ilist_node_impl() = default;
108
109private:
110 ilist_node_impl *getPrev() {
111 return static_cast<ilist_node_impl *>(node_base_type::getPrev());
112 }
113
114 ilist_node_impl *getNext() {
115 return static_cast<ilist_node_impl *>(node_base_type::getNext());
116 }
117
118 const ilist_node_impl *getPrev() const {
119 return static_cast<ilist_node_impl *>(node_base_type::getPrev());
120 }
121
122 const ilist_node_impl *getNext() const {
123 return static_cast<ilist_node_impl *>(node_base_type::getNext());
124 }
125
126 void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); }
127 void setNext(ilist_node_impl *N) { node_base_type::setNext(N); }
128
129public:
132
136
140
141 // Under-approximation, but always available for assertions.
142 using node_base_type::isKnownSentinel;
143
144 /// Check whether this is the sentinel node.
145 ///
146 /// This requires sentinel tracking to be explicitly enabled. Use the
147 /// ilist_sentinel_tracking<true> option to get this API.
148 ///
149 /// Rather than using static_assert to enforce the API is not called when
150 /// configured with is_sentinel_tracking_explicit=false, the method is
151 /// conditionally provided using std::enable_if. This way, clients of
152 /// ilist_node_impl can be fully instantiated for DLLExport on Windows.
153 template <typename T = OptionsT>
154 std::enable_if_t<T::is_sentinel_tracking_explicit, bool> isSentinel() const {
155 return node_base_type::isSentinel();
156 }
157};
158
159/// An intrusive list node.
160///
161/// A base class to enable membership in intrusive lists, including \a
162/// simple_ilist, \a iplist, and \a ilist. The first template parameter is the
163/// \a value_type for the list.
164///
165/// An ilist node can be configured with compile-time options to change
166/// behaviour and/or add API.
167///
168/// By default, an \a ilist_node knows whether it is the list sentinel (an
169/// instance of \a ilist_sentinel) if and only if
170/// LLVM_ENABLE_ABI_BREAKING_CHECKS. The function \a isKnownSentinel() always
171/// returns \c false tracking is off. Sentinel tracking steals a bit from the
172/// "prev" link, which adds a mask operation when decrementing an iterator, but
173/// enables bug-finding assertions in \a ilist_iterator.
174///
175/// To turn sentinel tracking on all the time, pass in the
176/// ilist_sentinel_tracking<true> template parameter. This also enables the \a
177/// isSentinel() function. The same option must be passed to the intrusive
178/// list. (ilist_sentinel_tracking<false> turns sentinel tracking off all the
179/// time.)
180///
181/// A type can inherit from ilist_node multiple times by passing in different
182/// \a ilist_tag options. This allows a single instance to be inserted into
183/// multiple lists simultaneously, where each list is given the same tag.
184///
185/// \example
186/// struct A {};
187/// struct B {};
188/// struct N : ilist_node<N, ilist_tag<A>>, ilist_node<N, ilist_tag<B>> {};
189///
190/// void foo() {
191/// simple_ilist<N, ilist_tag<A>> ListA;
192/// simple_ilist<N, ilist_tag<B>> ListB;
193/// N N1;
194/// ListA.push_back(N1);
195/// ListB.push_back(N1);
196/// }
197/// \endexample
198///
199/// When the \a ilist_parent<ParentTy> option is passed to an ilist_node and the
200/// owning ilist, each node contains a pointer to the ilist's owner. This adds
201/// \a getParent() and \a setParent(ParentTy*) methods to the ilist_node, which
202/// will be used for node access by the ilist if the node class publicly
203/// inherits from \a ilist_node_with_parent. By default, setParent() is not
204/// automatically called by the ilist; a SymbolTableList will call setParent()
205/// on inserted nodes, but the sentinel must still be manually set after the
206/// list is created (e.g. SymTabList.end()->setParent(Parent)).
207///
208/// The primary benefit of using ilist_parent is that a parent
209/// pointer will be stored in the sentinel, meaning that you can safely use \a
210/// ilist_iterator::getNodeParent() to get the node parent from any valid (i.e.
211/// non-null) iterator, even one that points to a sentinel value.
212///
213/// See \a is_valid_option for steps on adding a new option.
214template <class T, class... Options>
216 : public ilist_node_impl<
217 typename ilist_detail::compute_node_options<T, Options...>::type> {
218 static_assert(ilist_detail::check_options<Options...>::value,
219 "Unrecognized node option!");
220};
221
222namespace ilist_detail {
223
224/// An access class for ilist_node private API.
225///
226/// This gives access to the private parts of ilist nodes. Nodes for an ilist
227/// should friend this class if they inherit privately from ilist_node.
228///
229/// Using this class outside of the ilist implementation is unsupported.
231protected:
232 template <class OptionsT>
233 static ilist_node_impl<OptionsT> *getNodePtr(typename OptionsT::pointer N) {
234 return N;
235 }
236
237 template <class OptionsT>
238 static const ilist_node_impl<OptionsT> *
239 getNodePtr(typename OptionsT::const_pointer N) {
240 return N;
241 }
242
243 template <class OptionsT>
244 static typename OptionsT::pointer getValuePtr(ilist_node_impl<OptionsT> *N) {
245 return static_cast<typename OptionsT::pointer>(N);
246 }
247
248 template <class OptionsT>
249 static typename OptionsT::const_pointer
251 return static_cast<typename OptionsT::const_pointer>(N);
252 }
253
254 template <class OptionsT>
256 return N.getPrev();
257 }
258
259 template <class OptionsT>
261 return N.getNext();
262 }
263
264 template <class OptionsT>
265 static const ilist_node_impl<OptionsT> *
267 return N.getPrev();
268 }
269
270 template <class OptionsT>
271 static const ilist_node_impl<OptionsT> *
273 return N.getNext();
274 }
275};
276
277template <class OptionsT> struct SpecificNodeAccess : NodeAccess {
278protected:
279 using pointer = typename OptionsT::pointer;
280 using const_pointer = typename OptionsT::const_pointer;
282
286
290
294
298};
299
300} // end namespace ilist_detail
301
302template <class OptionsT>
303class ilist_sentinel : public ilist_node_impl<OptionsT> {
304public:
306 this->initializeSentinel();
307 reset();
308 }
309
310 void reset() {
311 this->setPrev(this);
312 this->setNext(this);
313 }
314
315 bool empty() const { return this == this->getPrev(); }
316};
317
318/// An ilist node that can access its parent list.
319///
320/// Requires \c NodeTy to have \a getParent() to find the parent node, and the
321/// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
322template <typename NodeTy, typename ParentTy, class... Options>
323class ilist_node_with_parent : public ilist_node<NodeTy, Options...> {
324protected:
326
327private:
328 /// Forward to NodeTy::getParent().
329 ///
330 /// Note: do not use the name "getParent()". We want a compile error
331 /// (instead of recursion) when the subclass fails to implement \a
332 /// getParent().
333 const ParentTy *getNodeParent() const {
334 return static_cast<const NodeTy *>(this)->getParent();
335 }
336
337public:
338 /// @name Adjacent Node Accessors
339 /// @{
340 /// Get the previous node, or \c nullptr for the list head.
341 NodeTy *getPrevNode() {
342 // Should be separated to a reused function, but then we couldn't use auto
343 // (and would need the type of the list).
344 const auto &List =
345 getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
346 return List.getPrevNode(*static_cast<NodeTy *>(this));
347 }
348
349 /// Get the previous node, or \c nullptr for the list head.
350 const NodeTy *getPrevNode() const {
351 return const_cast<ilist_node_with_parent *>(this)->getPrevNode();
352 }
353
354 /// Get the next node, or \c nullptr for the list tail.
355 NodeTy *getNextNode() {
356 // Should be separated to a reused function, but then we couldn't use auto
357 // (and would need the type of the list).
358 const auto &List =
359 getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
360 return List.getNextNode(*static_cast<NodeTy *>(this));
361 }
362
363 /// Get the next node, or \c nullptr for the list tail.
364 const NodeTy *getNextNode() const {
365 return const_cast<ilist_node_with_parent *>(this)->getNextNode();
366 }
367 /// @}
368};
369
370} // end namespace llvm
371
372#endif // LLVM_ADT_ILIST_NODE_H
static LVOptions Options
Definition LVOptions.cpp:25
#define T
Mixin base class that is used to add getParent() and setParent(ParentTy*) methods to ilist_node_impl ...
Definition ilist_node.h:32
const ParentTy * getParent() const
Definition ilist_node.h:34
void setParent(ParentTy *Parent)
Definition ilist_node.h:40
Iterator for intrusive lists based on ilist_node.
Iterator for intrusive lists based on ilist_node.
Implementation for an ilist node.
Definition ilist_node.h:73
typename ilist_select_iterator_type< OptionsT::has_iterator_bits, OptionsT, false, true >::type const_self_iterator
Definition ilist_node.h:97
const_reverse_self_iterator getReverseIterator() const
Definition ilist_node.h:137
typename ilist_select_iterator_type< OptionsT::has_iterator_bits, OptionsT, true, true >::type const_reverse_self_iterator
Definition ilist_node.h:103
typename ilist_select_iterator_type< OptionsT::has_iterator_bits, OptionsT, false, false >::type self_iterator
Definition ilist_node.h:94
const_self_iterator getIterator() const
Definition ilist_node.h:131
typename ilist_select_iterator_type< OptionsT::has_iterator_bits, OptionsT, true, false >::type reverse_self_iterator
Definition ilist_node.h:100
reverse_self_iterator getReverseIterator()
Definition ilist_node.h:133
std::enable_if_t< T::is_sentinel_tracking_explicit, bool > isSentinel() const
Check whether this is the sentinel node.
Definition ilist_node.h:154
self_iterator getIterator()
Definition ilist_node.h:130
const NodeTy * getPrevNode() const
Get the previous node, or nullptr for the list head.
Definition ilist_node.h:350
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:355
const NodeTy * getNextNode() const
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:364
bool empty() const
Definition ilist_node.h:315
This is an optimization pass for GlobalISel generic memory operations.
#define N
An access class for ilist_node private API.
Definition ilist_node.h:230
static ilist_node_impl< OptionsT > * getPrev(ilist_node_impl< OptionsT > &N)
Definition ilist_node.h:255
static const ilist_node_impl< OptionsT > * getNext(const ilist_node_impl< OptionsT > &N)
Definition ilist_node.h:272
static ilist_node_impl< OptionsT > * getNext(ilist_node_impl< OptionsT > &N)
Definition ilist_node.h:260
static const ilist_node_impl< OptionsT > * getPrev(const ilist_node_impl< OptionsT > &N)
Definition ilist_node.h:266
static ilist_node_impl< OptionsT > * getNodePtr(typename OptionsT::pointer N)
Definition ilist_node.h:233
static const ilist_node_impl< OptionsT > * getNodePtr(typename OptionsT::const_pointer N)
Definition ilist_node.h:239
static OptionsT::pointer getValuePtr(ilist_node_impl< OptionsT > *N)
Definition ilist_node.h:244
static OptionsT::const_pointer getValuePtr(const ilist_node_impl< OptionsT > *N)
Definition ilist_node.h:250
static pointer getValuePtr(node_type *N)
Definition ilist_node.h:291
typename OptionsT::const_pointer const_pointer
Definition ilist_node.h:280
static const_pointer getValuePtr(const node_type *N)
Definition ilist_node.h:295
static const node_type * getNodePtr(const_pointer N)
Definition ilist_node.h:287
ilist_node_impl< OptionsT > node_type
Definition ilist_node.h:281
static node_type * getNodePtr(pointer N)
Definition ilist_node.h:283
typename OptionsT::pointer pointer
Definition ilist_node.h:279
Check whether options are valid.
std::conditional_t< use_iterator_bits, ilist_iterator_w_bits< Opts, arg1, arg2 >, ilist_iterator< Opts, arg1, arg2 > > type
Definition ilist_node.h:56