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