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