llvm.org GIT mirror llvm / b4bd34e
ADT: Add sentinel tracking and custom tags to ilists This adds two declarative configuration options for intrusive lists (available for simple_ilist, iplist, and ilist). Both of these options affect ilist_node interoperability and need to be passed both to the node and the list. Instead of adding a new traits class, they're specified as optional template parameters (in any order). The two options: 1. Pass ilist_sentinel_tracking<true> or ilist_sentinel_tracking<false> to control whether there's a bit on ilist_node "prev" pointer indicating whether it's the sentinel. The default behaviour is to use a bit if and only if LLVM_ENABLE_ABI_BREAKING_CHECKS. 2. Pass ilist_tag<TagA> and ilist_tag<TagB> to allow insertion of a single node into two different lists (simultaneously). I have an immediate use-case for (1) ilist_sentinel_tracking: fixing the validation semantics of MachineBasicBlock::reverse_iterator to match ilist::reverse_iterator (ala r280032: see the comments at the end of the commit message there). I'm adding (2) ilist_tag in the same commit to validate that the options framework supports expansion. Justin Bogner mentioned this might enable a possible cleanup in SelectionDAG, but I'll leave this to others to explore. In the meantime, the unit tests and the comments for simple_ilist and ilist_node have usage examples. Note that there's a layer of indirection to support optional, out-of-order, template paramaters. Internal classes are templated on an instantiation of the non-variadic ilist_detail::node_options. User-facing classes use ilist_detail::compute_node_options to compute the correct instantiation of ilist_detail::node_options. The comments for ilist_detail::is_valid_option describe how to add new options (e.g., ilist_packed_int<int NumBits>). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281167 91177308-0d34-0410-b5e6-96231b3b80d8 Duncan P. N. Exon Smith 3 years ago
14 changed file(s) with 658 addition(s) and 172 deletion(s). Raw diff Collapse all Expand all
361361
362362 /// An intrusive list with ownership and callbacks specified/controlled by
363363 /// ilist_traits, only with API safe for polymorphic types.
364 template
365 class iplist : public iplist_impl, ilist_traits> {};
364 ///
365 /// The \p Options parameters are the same as those for \a simple_ilist. See
366 /// there for a description of what's available.
367 template
368 class iplist
369 : public iplist_impl, ilist_traits> {};
366370
367371 /// An intrusive list with ownership and callbacks specified/controlled by
368372 /// ilist_traits, with API that is unsafe for polymorphic types.
369 template class ilist : public iplist {
370 typedef iplist base_list_type;
373 template
374 class ilist : public iplist {
375 typedef iplist base_list_type;
371376
372377 public:
373378 typedef typename base_list_type::size_type size_type;
1717 namespace llvm {
1818
1919 /// Implementations of list algorithms using ilist_node_base.
20 class ilist_base {
21 typedef ilist_node_base node_base_type;
20 template class ilist_base {
21 public:
22 typedef ilist_node_base node_base_type;
2223
23 public:
2424 static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
2525 node_base_type &Prev = *Next.getPrev();
2626 N.setNext(&Next);
1919
2020 namespace ilist_detail {
2121
22 template struct ConstCorrectNodeType {
23 typedef ilist_node type;
22 /// Find const-correct node types.
23 template struct IteratorTraits;
24 template struct IteratorTraits {
25 typedef typename OptionsT::value_type value_type;
26 typedef typename OptionsT::pointer pointer;
27 typedef typename OptionsT::reference reference;
28 typedef ilist_node_impl *node_pointer;
29 typedef ilist_node_impl &node_reference;
2430 };
25 template struct ConstCorrectNodeType {
26 typedef const ilist_node type;
31 template struct IteratorTraits {
32 typedef const typename OptionsT::value_type value_type;
33 typedef typename OptionsT::const_pointer pointer;
34 typedef typename OptionsT::const_reference reference;
35 typedef const ilist_node_impl *node_pointer;
36 typedef const ilist_node_impl &node_reference;
2737 };
2838
2939 template struct IteratorHelper;
4151 } // end namespace ilist_detail
4252
4353 /// Iterator for intrusive lists based on ilist_node.
44 template
45 class ilist_iterator : ilist_detail::SpecificNodeAccess<
46 typename std::remove_const::type> {
47 typedef ilist_detail::SpecificNodeAccess<
48 typename std::remove_const::type>
49 Access;
54 template
55 class ilist_iterator : ilist_detail::SpecificNodeAccess {
56 friend ilist_iterator;
57 friend ilist_iterator;
58 friend ilist_iterator;
59
60 typedef ilist_detail::IteratorTraits Traits;
61 typedef ilist_detail::SpecificNodeAccess Access;
5062
5163 public:
52 typedef NodeTy value_type;
53 typedef value_type *pointer;
54 typedef value_type &reference;
64 typedef typename Traits::value_type value_type;
65 typedef typename Traits::pointer pointer;
66 typedef typename Traits::reference reference;
5567 typedef ptrdiff_t difference_type;
5668 typedef std::bidirectional_iterator_tag iterator_category;
5769
58 typedef typename std::add_const::type *const_pointer;
59 typedef typename std::add_const::type &const_reference;
60
61 typedef typename ilist_detail::ConstCorrectNodeType::type node_type;
62 typedef node_type *node_pointer;
63 typedef node_type &node_reference;
70 typedef typename OptionsT::const_pointer const_pointer;
71 typedef typename OptionsT::const_reference const_reference;
6472
6573 private:
74 typedef typename Traits::node_pointer node_pointer;
75 typedef typename Traits::node_reference node_reference;
76
6677 node_pointer NodePtr;
6778
6879 public:
7586
7687 // This is templated so that we can allow constructing a const iterator from
7788 // a nonconst iterator...
78 template <class node_ty>
89 template <bool RHSIsConst>
7990 ilist_iterator(
80 const ilist_iterator &RHS,
81 typename std::enable_if::value,
82 void *>::type = nullptr)
83 : NodePtr(RHS.getNodePtr()) {}
91 const ilist_iterator &RHS,
92 typename std::enable_if::type = nullptr)
93 : NodePtr(RHS.NodePtr) {}
8494
8595 // This is templated so that we can allow assigning to a const iterator from
8696 // a nonconst iterator...
87 template
88 const ilist_iterator &
89 operator=(const ilist_iterator &RHS) {
90 NodePtr = RHS.getNodePtr();
97 template
98 typename std::enable_if::type
99 operator=(const ilist_iterator &RHS) {
100 NodePtr = RHS.NodePtr;
91101 return *this;
92102 }
93103
95105 ///
96106 /// TODO: Roll this into the implicit constructor once we're sure that no one
97107 /// is relying on the std::reverse_iterator off-by-one semantics.
98 ilist_iterator<NodeTy, !IsReverse> getReverse() const {
108 ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const {
99109 if (NodePtr)
100 return ilist_iterator(*NodePtr);
101 return ilist_iterator();
110 return ilist_iterator(*NodePtr);
111 return ilist_iterator();
112 }
113
114 /// Const-cast.
115 ilist_iterator getNonConst() const {
116 if (NodePtr)
117 return ilist_iterator(
118 const_cast
119 false>::node_reference>(*NodePtr));
120 return ilist_iterator();
102121 }
103122
104123 void reset(pointer NP) { NodePtr = NP; }
120139
121140 // Increment and decrement operators...
122141 ilist_iterator &operator--() {
123 ilist_detail::IteratorHelper::decrement(NodePtr);
142 NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
124143 return *this;
125144 }
126145 ilist_iterator &operator++() {
127 ilist_detail::IteratorHelper::increment(NodePtr);
146 NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
128147 return *this;
129148 }
130149 ilist_iterator operator--(int) {
148167 /// used by the dyn_cast, cast, isa mechanisms...
149168 ///
150169 /// FIXME: remove this, since there is no implicit conversion to NodeTy.
151 template struct simplify_type> {
152 typedef NodeTy *SimpleType;
170 template
171 struct simplify_type> {
172 typedef ilist_iterator iterator;
173 typedef typename iterator::pointer SimpleType;
153174
154 static SimpleType getSimplifiedValue(ilist_iterator &Node) {
155 return &*Node;
156 }
175 static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
157176 };
158 template struct simplify_type> {
159 typedef /*const*/ NodeTy *SimpleType;
160
161 static SimpleType getSimplifiedValue(const ilist_iterator &Node) {
162 return &*Node;
163 }
164 };
177 template
178 struct simplify_type>
179 : simplify_type> {};
165180
166181 } // end namespace llvm
167182
1515 #define LLVM_ADT_ILIST_NODE_H
1616
1717 #include "llvm/ADT/ilist_node_base.h"
18 #include "llvm/ADT/ilist_node_options.h"
1819
1920 namespace llvm {
2021
2526 template
2627 struct ilist_traits;
2728
28 template class ilist_iterator;
29 template class ilist_sentinel;
30
31 /// Templated wrapper class.
32 template class ilist_node : ilist_node_base {
33 friend class ilist_base;
29 template class ilist_iterator;
30 template class ilist_sentinel;
31
32 /// Implementation for an ilist node.
33 ///
34 /// Templated on an appropriate \a ilist_detail::node_options, usually computed
35 /// by \a ilist_detail::compute_node_options.
36 ///
37 /// This is a wrapper around \a ilist_node_base whose main purpose is to
38 /// provide type safety: you can't insert nodes of \a ilist_node_impl into the
39 /// wrong \a simple_ilist or \a iplist.
40 template class ilist_node_impl : OptionsT::node_base_type {
41 typedef typename OptionsT::value_type value_type;
42 typedef typename OptionsT::node_base_type node_base_type;
43 typedef typename OptionsT::list_base_type list_base_type;
44
45 friend typename OptionsT::list_base_type;
3446 friend struct ilist_detail::NodeAccess;
35 friend struct ilist_traits;
36 friend class ilist_iterator;
37 friend class ilist_iterator;
38 friend class ilist_sentinel;
39
40 protected:
41 ilist_node() = default;
47 friend class ilist_sentinel;
48 friend class ilist_iterator;
49 friend class ilist_iterator;
50 friend class ilist_iterator;
51 friend class ilist_iterator;
52
53 protected:
54 ilist_node_impl() = default;
55
56 typedef ilist_iterator self_iterator;
57 typedef ilist_iterator const_self_iterator;
58 typedef ilist_iterator reverse_self_iterator;
59 typedef ilist_iterator const_reverse_self_iterator;
4260
4361 private:
44 ilist_node *getPrev() {
45 return static_cast(ilist_node_base::getPrev());
46 }
47 ilist_node *getNext() {
48 return static_cast(ilist_node_base::getNext());
49 }
50
51 const ilist_node *getPrev() const {
52 return static_cast(ilist_node_base::getPrev());
53 }
54 const ilist_node *getNext() const {
55 return static_cast(ilist_node_base::getNext());
56 }
57
58 void setPrev(ilist_node *N) { ilist_node_base::setPrev(N); }
59 void setNext(ilist_node *N) { ilist_node_base::setNext(N); }
62 ilist_node_impl *getPrev() {
63 return static_cast(node_base_type::getPrev());
64 }
65 ilist_node_impl *getNext() {
66 return static_cast(node_base_type::getNext());
67 }
68
69 const ilist_node_impl *getPrev() const {
70 return static_cast(node_base_type::getPrev());
71 }
72 const ilist_node_impl *getNext() const {
73 return static_cast(node_base_type::getNext());
74 }
75
76 void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); }
77 void setNext(ilist_node_impl *N) { node_base_type::setNext(N); }
6078
6179 public:
62 ilist_iterator getIterator() { return ilist_iterator(*this); }
63 ilist_iterator getIterator() const {
64 return ilist_iterator(*this);
65 }
66
67 using ilist_node_base::isKnownSentinel;
80 self_iterator getIterator() { return self_iterator(*this); }
81 const_self_iterator getIterator() const { return const_self_iterator(*this); }
82
83 // Under-approximation, but always available for assertions.
84 using node_base_type::isKnownSentinel;
85
86 /// Check whether this is the sentinel node.
87 ///
88 /// This requires sentinel tracking to be explicitly enabled. Use the
89 /// ilist_sentinel_tracking option to get this API.
90 bool isSentinel() const {
91 static_assert(OptionsT::is_sentinel_tracking_explicit,
92 "Use ilist_sentinel_tracking to enable isSentinel()");
93 return node_base_type::isSentinel();
94 }
95 };
96
97 /// An intrusive list node.
98 ///
99 /// A base class to enable membership in intrusive lists, including \a
100 /// simple_ilist, \a iplist, and \a ilist. The first template parameter is the
101 /// \a value_type for the list.
102 ///
103 /// An ilist node can be configured with compile-time options to change
104 /// behaviour and/or add API.
105 ///
106 /// By default, an \a ilist_node knows whether it is the list sentinel (an
107 /// instance of \a ilist_sentinel) if and only if
108 /// LLVM_ENABLE_ABI_BREAKING_CHECKS. The function \a isKnownSentinel() always
109 /// returns \c false tracking is off. Sentinel tracking steals a bit from the
110 /// "prev" link, which adds a mask operation when decrementing an iterator, but
111 /// enables bug-finding assertions in \a ilist_iterator.
112 ///
113 /// To turn sentinel tracking on all the time, pass in the
114 /// ilist_sentinel_tracking template parameter. This also enables the \a
115 /// isSentinel() function. The same option must be passed to the intrusive
116 /// list. (ilist_sentinel_tracking turns sentinel tracking off all the
117 /// time.)
118 ///
119 /// A type can inherit from ilist_node multiple times by passing in different
120 /// \a ilist_tag options. This allows a single instance to be inserted into
121 /// multiple lists simultaneously, where each list is given the same tag.
122 ///
123 /// \example
124 /// struct A {};
125 /// struct B {};
126 /// struct N : ilist_node>, ilist_node> {};
127 ///
128 /// void foo() {
129 /// simple_ilist> ListA;
130 /// simple_ilist> ListB;
131 /// N N1;
132 /// ListA.push_back(N1);
133 /// ListB.push_back(N1);
134 /// }
135 /// \endexample
136 ///
137 /// See \a is_valid_option for steps on adding a new option.
138 template
139 class ilist_node
140 : public ilist_node_impl<
141 typename ilist_detail::compute_node_options::type> {
142 static_assert(ilist_detail::check_options::value,
143 "Unrecognized node option!");
68144 };
69145
70146 namespace ilist_detail {
76152 /// Using this class outside of the ilist implementation is unsupported.
77153 struct NodeAccess {
78154 protected:
79 template static ilist_node *getNodePtr(T *N) { return N; }
80 template <typename T> static const ilist_node *getNodePtr(const T *N) {
155 template <class OptionsT>
156 static ilist_node_impl *getNodePtr(typename OptionsT::pointer N) {
81157 return N;
82158 }
83 template static T *getValuePtr(ilist_node *N) {
84 return static_cast(N);
85 }
86 template static const T *getValuePtr(const ilist_node *N) {
87 return static_cast(N);
88 }
89
90 template <typename T> static ilist_node *getPrev(ilist_node &N) {
159 template <class OptionsT>
160 static const ilist_node_impl *
161 getNodePtr(typename OptionsT::const_pointer N) {
162 return N;
163 }
164 template
165 static typename OptionsT::pointer getValuePtr(ilist_node_impl *N) {
166 return static_cast(N);
167 }
168 template
169 static typename OptionsT::const_pointer
170 getValuePtr(const ilist_node_impl *N) {
171 return static_cast(N);
172 }
173
174 template
175 static ilist_node_impl *getPrev(ilist_node_impl &N) {
91176 return N.getPrev();
92177 }
93 template <typename T> static ilist_node *getNext(ilist_node &N) {
178 template <class OptionsT>
179 static ilist_node_impl *getNext(ilist_node_impl &N) {
94180 return N.getNext();
95181 }
96 template
97 static const ilist_node *getPrev(const ilist_node &N) {
182 template
183 static const ilist_node_impl *
184 getPrev(const ilist_node_impl &N) {
98185 return N.getPrev();
99186 }
100 template
101 static const ilist_node *getNext(const ilist_node &N) {
187 template
188 static const ilist_node_impl *
189 getNext(const ilist_node_impl &N) {
102190 return N.getNext();
103191 }
104192 };
105193
106 template struct SpecificNodeAccess : NodeAccess {
107 protected:
108 typedef T *pointer;
109 typedef const T *const_pointer;
110 typedef ilist_node node_type;
194 template struct SpecificNodeAccess : NodeAccess {
195 protected:
196 typedef typename OptionsT::pointer pointer;
197 typedef typename OptionsT::const_pointer const_pointer;
198 typedef ilist_node_impl node_type;
111199
112200 static node_type *getNodePtr(pointer N) {
113 return NodeAccess::getNodePtr(N);
114 }
115 static const ilist_node *getNodePtr(const_pointer N) {
116 return NodeAccess::getNodePtr<T>(N);
201 return NodeAccess::getNodePtr<OptionsT>(N);
202 }
203 static const node_type *getNodePtr(const_pointer N) {
204 return NodeAccess::getNodePtr(N);
117205 }
118206 static pointer getValuePtr(node_type *N) {
119 return NodeAccess::getValuePtr<T>(N);
207 return NodeAccess::getValuePtr<OptionsT>(N);
120208 }
121209 static const_pointer getValuePtr(const node_type *N) {
122 return NodeAccess::getValuePtr<T>(N);
210 return NodeAccess::getValuePtr<OptionsT>(N);
123211 }
124212 };
125213 } // end namespace ilist_detail
126214
127 template <typename NodeTy> class ilist_sentinel : public ilist_node {
215 template <class OptionsT>
216 class ilist_sentinel : public ilist_node_impl {
128217 public:
129218 ilist_sentinel() {
130 ilist_node_base::initializeSentinel();
219 this->initializeSentinel();
131220 reset();
132221 }
133222
143232 ///
144233 /// Requires \c NodeTy to have \a getParent() to find the parent node, and the
145234 /// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
146 template
147 class ilist_node_with_parent : public ilist_node {
235 template
236 class ilist_node_with_parent : public ilist_node {
148237 protected:
149238 ilist_node_with_parent() = default;
150239
1414 namespace llvm {
1515
1616 /// Base class for ilist nodes.
17 class ilist_node_base {
18 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
19 PointerIntPair PrevAndSentinel;
20 #else
17 ///
18 /// Optionally tracks whether this node is the sentinel.
19 template class ilist_node_base;
20
21 template <> class ilist_node_base {
2122 ilist_node_base *Prev = nullptr;
22 #endif
2323 ilist_node_base *Next = nullptr;
2424
2525 public:
26 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
27 void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
28 ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
29
30 bool isKnownSentinel() const { return PrevAndSentinel.getInt(); }
31 void initializeSentinel() { PrevAndSentinel.setInt(true); }
32 #else
3326 void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
27 void setNext(ilist_node_base *Next) { this->Next = Next; }
3428 ilist_node_base *getPrev() const { return Prev; }
29 ilist_node_base *getNext() const { return Next; }
3530
3631 bool isKnownSentinel() const { return false; }
3732 void initializeSentinel() {}
38 #endif
33 };
3934
35 template <> class ilist_node_base {
36 PointerIntPair PrevAndSentinel;
37 ilist_node_base *Next = nullptr;
38
39 public:
40 void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
4041 void setNext(ilist_node_base *Next) { this->Next = Next; }
42 ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
4143 ilist_node_base *getNext() const { return Next; }
44
45 bool isSentinel() const { return PrevAndSentinel.getInt(); }
46 bool isKnownSentinel() const { return isSentinel(); }
47 void initializeSentinel() { PrevAndSentinel.setInt(true); }
4248 };
4349
4450 } // end namespace llvm
0 //===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_ADT_ILIST_NODE_OPTIONS_H
10 #define LLVM_ADT_ILIST_NODE_OPTIONS_H
11
12 namespace llvm {
13
14 template class ilist_node_base;
15 template class ilist_base;
16
17 /// Option to choose whether to track sentinels.
18 ///
19 /// This option affects the ABI for the nodes. When not specified explicitly,
20 /// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS. Specify explicitly to
21 /// enable \a ilist_node::isSentinel().
22 template struct ilist_sentinel_tracking {};
23
24 /// Option to specify a tag for the node type.
25 ///
26 /// This option allows a single value type to be inserted in multiple lists
27 /// simultaneously. See \a ilist_node for usage examples.
28 template struct ilist_tag {};
29
30 namespace ilist_detail {
31
32 /// Helper trait for recording whether an option is specified explicitly.
33 template struct explicitness {
34 static const bool is_explicit = IsExplicit;
35 };
36 typedef explicitness is_explicit;
37 typedef explicitness is_implicit;
38
39 /// Check whether an option is valid.
40 ///
41 /// The steps for adding and enabling a new ilist option include:
42 /// \li define the option, ilist_foo, above;
43 /// \li add new parameters for Bar to \a ilist_detail::node_options;
44 /// \li add an extraction meta-function, ilist_detail::extract_foo;
45 /// \li call extract_foo from \a ilist_detail::compute_node_options and pass it
46 /// into \a ilist_detail::node_options; and
47 /// \li specialize \c is_valid_option> to inherit from \c
48 /// std::true_type to get static assertions passing in \a simple_ilist and \a
49 /// ilist_node.
50 template struct is_valid_option : std::false_type {};
51
52 /// Extract sentinel tracking option.
53 ///
54 /// Look through \p Options for the \a ilist_sentinel_tracking option, with the
55 /// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS.
56 template struct extract_sentinel_tracking;
57 template
58 struct extract_sentinel_tracking<
59 ilist_sentinel_tracking, Options...>
60 : std::integral_constant, is_explicit {};
61 template
62 struct extract_sentinel_tracking
63 : extract_sentinel_tracking {};
64 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
65 template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {};
66 #else
67 template <>
68 struct extract_sentinel_tracking<> : std::false_type, is_implicit {};
69 #endif
70 template
71 struct is_valid_option>
72 : std::true_type {};
73
74 /// Extract custom tag option.
75 ///
76 /// Look through \p Options for the \a ilist_tag option, pulling out the
77 /// custom tag type, using void as a default.
78 template struct extract_tag;
79 template
80 struct extract_tag, Options...> {
81 typedef Tag type;
82 };
83 template
84 struct extract_tag : extract_tag {};
85 template <> struct extract_tag<> { typedef void type; };
86 template struct is_valid_option> : std::true_type {};
87
88 /// Check whether options are valid.
89 ///
90 /// The conjunction of \a is_valid_option on each individual option.
91 template struct check_options;
92 template <> struct check_options<> : std::true_type {};
93 template
94 struct check_options
95 : std::integral_constant::value &&
96 check_options::value> {};
97
98 /// Traits for options for \a ilist_node.
99 ///
100 /// This is usually computed via \a compute_node_options.
101 template
102 class TagT>
103 struct node_options {
104 typedef T value_type;
105 typedef T *pointer;
106 typedef T &reference;
107 typedef const T *const_pointer;
108 typedef const T &const_reference;
109
110 static const bool enable_sentinel_tracking = EnableSentinelTracking;
111 static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
112 typedef TagT tag;
113 typedef ilist_node_base node_base_type;
114 typedef ilist_base list_base_type;
115 };
116
117 template struct compute_node_options {
118 typedef node_options::value,
119 extract_sentinel_tracking::is_explicit,
120 typename extract_tag::type>
121 type;
122 };
123
124 } // end namespace ilist_detail
125 } // end namespace llvm
126
127 #endif // LLVM_ADT_ILIST_NODE_OPTIONS_H
4545 /// eraseAndDispose(), and \a clearAndDispose(). These have different names
4646 /// because the extra semantic is otherwise non-obvious. They are equivalent
4747 /// to calling \a std::for_each() on the range to be discarded.
48 template
49 class simple_ilist : ilist_base, ilist_detail::SpecificNodeAccess {
50 typedef ilist_base list_base_type;
51 ilist_sentinel Sentinel;
48 ///
49 /// The currently available \p Options customize the nodes in the list. The
50 /// same options must be specified in the \a ilist_node instantation for
51 /// compatibility (although the order is irrelevant).
52 /// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
53 /// list should use. This is useful if a type \p T is part of multiple,
54 /// independent lists simultaneously.
55 /// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
56 /// node is a sentinel. Specifying \c true enables the \a
57 /// ilist_node::isSentinel() API. Unlike \a ilist_node::isKnownSentinel(),
58 /// which is only appropriate for assertions, \a ilist_node::isSentinel() is
59 /// appropriate for real logic.
60 ///
61 /// Here are examples of \p Options usage:
62 /// \li \c simple_ilist gives the defaults. \li \c
63 /// simple_ilist> enables the \a
64 /// ilist_node::isSentinel() API.
65 /// \li \c simple_ilist,ilist_sentinel_tracking>
66 /// specifies a tag of A and that tracking should be off (even when
67 /// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
68 /// \li \c simple_ilist,ilist_tag> is
69 /// equivalent to the last.
70 ///
71 /// See \a is_valid_option for steps on adding a new option.
72 template
73 class simple_ilist
74 : ilist_detail::compute_node_options::type::list_base_type,
75 ilist_detail::SpecificNodeAccess<
76 typename ilist_detail::compute_node_options::type> {
77 static_assert(ilist_detail::check_options::value,
78 "Unrecognized node option!");
79 typedef
80 typename ilist_detail::compute_node_options::type OptionsT;
81 typedef typename OptionsT::list_base_type list_base_type;
82 ilist_sentinel Sentinel;
5283
5384 public:
54 typedef T value_type;
55 typedef T *pointer;
56 typedef T &reference;
57 typedef const T *const_pointer;
58 typedef const T &const_reference;
59 typedef ilist_iterator iterator;
60 typedef ilist_iterator const_iterator;
85 typedef typename OptionsT::value_type value_type;
86 typedef typename OptionsT::pointer pointer;
87 typedef typename OptionsT::reference reference;
88 typedef typename OptionsT::const_pointer const_pointer;
89 typedef typename OptionsT::const_reference const_reference;
90 typedef ilist_iterator iterator;
91 typedef ilist_iterator const_iterator;
92 typedef ilist_iterator reverse_iterator;
93 typedef ilist_iterator const_reverse_iterator;
6194 typedef size_t size_type;
6295 typedef ptrdiff_t difference_type;
63 typedef ilist_iterator const_reverse_iterator;
64 typedef ilist_iterator reverse_iterator;
6596
6697 simple_ilist() = default;
6798 ~simple_ilist() = default;
221252 ///@}
222253 };
223254
224 template >
255 template , class... Options>
225256 template
226 void simple_ilist>::merge(simple_ilist &RHS, Compare comp) {
257 void simple_ilist, Options...>::merge(simple_ilist &RHS, Compare comp) {
227258 if (this == &RHS || RHS.empty())
228259 return;
229260 iterator LI = begin(), LE = end();
243274 splice(LE, RHS, RI, RE);
244275 }
245276
246 template >
277 template , class... Options>
247278 template
248 void simple_ilist>::sort(Compare comp) {
279 void simple_ilist, Options...>::sort(Compare comp) {
249280 // Vacuously sorted.
250281 if (empty() || std::next(begin()) == end())
251282 return;
256287 ++Center;
257288 ++End;
258289 }
259 simple_ilist RHS;
290 simple_ilist RHS;
260291 RHS.splice(RHS.end(), *this, Center, end());
261292
262293 // Sort the sublists and merge back together.
1818
1919 namespace llvm {
2020
21 template struct MachineInstrBundleIteratorTraits {
22 typedef simple_ilist list_type;
23 typedef typename list_type::iterator instr_iterator;
24 typedef typename list_type::iterator nonconst_instr_iterator;
25 };
26 template struct MachineInstrBundleIteratorTraits {
27 typedef simple_ilist list_type;
28 typedef typename list_type::const_iterator instr_iterator;
29 typedef typename list_type::iterator nonconst_instr_iterator;
30 };
31
2132 /// MachineBasicBlock iterator that automatically skips over MIs that are
2233 /// inside bundles (i.e. walk top level MIs only).
2334 template class MachineInstrBundleIterator {
24 typedef ilist_iterator instr_iterator;
35 typedef typename MachineInstrBundleIteratorTraits::instr_iterator
36 instr_iterator;
2537 instr_iterator MII;
2638
2739 public:
3648
3749 private:
3850 typedef typename std::remove_const::type nonconst_value_type;
39 typedef ilist_node node_type;
40 typedef ilist_iterator nonconst_instr_iterator;
51 typedef typename MachineInstrBundleIteratorTraits::nonconst_instr_iterator
52 nonconst_instr_iterator;
4153 typedef MachineInstrBundleIterator nonconst_iterator;
4254
4355 public:
135147
136148 instr_iterator getInstrIterator() const { return MII; }
137149
138 nonconst_iterator getNonConstIterator() const {
139 if (auto *N = const_cast(MII.getNodePtr()))
140 return nonconst_iterator(nonconst_instr_iterator(*N));
141 return nonconst_iterator();
142 }
150 nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); }
143151 };
144152
145153 } // end namespace llvm
1919 IListBaseTest.cpp
2020 IListIteratorTest.cpp
2121 IListNodeBaseTest.cpp
22 IListNodeTest.cpp
2223 IListSentinelTest.cpp
2324 IListTest.cpp
2425 ImmutableMapTest.cpp
1313
1414 namespace {
1515
16 typedef ilist_base list_base_type;
17 typedef ilist_node_base node_base_type;
16 // Test fixture.
17 template class IListBaseTest : public ::testing::Test {};
1818
19 TEST(IListBaseTest, insertBeforeImpl) {
19 // Test variants with the same test.
20 typedef ::testing::Types, ilist_base>
21 IListBaseTestTypes;
22 TYPED_TEST_CASE(IListBaseTest, IListBaseTestTypes);
23
24 TYPED_TEST(IListBaseTest, insertBeforeImpl) {
25 typedef TypeParam list_base_type;
26 typedef typename list_base_type::node_base_type node_base_type;
27
2028 node_base_type S, A, B;
29
2130 // [S] <-> [S]
2231 S.setPrev(&S);
2332 S.setNext(&S);
3948 EXPECT_EQ(&S, B.getNext());
4049 }
4150
42 TEST(IListBaseTest, removeImpl) {
51 TYPED_TEST(IListBaseTest, removeImpl) {
52 typedef TypeParam list_base_type;
53 typedef typename list_base_type::node_base_type node_base_type;
54
4355 node_base_type S, A, B;
4456
4557 // [S] <-> A <-> B <-> [S]
6577 EXPECT_EQ(nullptr, B.getNext());
6678 }
6779
68 TEST(IListBaseTest, removeRangeImpl) {
80 TYPED_TEST(IListBaseTest, removeRangeImpl) {
81 typedef TypeParam list_base_type;
82 typedef typename list_base_type::node_base_type node_base_type;
83
6984 node_base_type S, A, B, C, D;
7085
7186 // [S] <-> A <-> B <-> C <-> D <-> [S]
88103 EXPECT_EQ(nullptr, C.getNext());
89104 }
90105
91 TEST(IListBaseTest, removeRangeImplAllButSentinel) {
106 TYPED_TEST(IListBaseTest, removeRangeImplAllButSentinel) {
107 typedef TypeParam list_base_type;
108 typedef typename list_base_type::node_base_type node_base_type;
109
92110 node_base_type S, A, B;
93111
94112 // [S] <-> A <-> B <-> [S]
105123 EXPECT_EQ(nullptr, B.getNext());
106124 }
107125
108 TEST(IListBaseTest, transferBeforeImpl) {
126 TYPED_TEST(IListBaseTest, transferBeforeImpl) {
127 typedef TypeParam list_base_type;
128 typedef typename list_base_type::node_base_type node_base_type;
129
109130 node_base_type S1, S2, A, B, C, D, E;
110131
111132 // [S1] <-> A <-> B <-> C <-> [S1]
1313
1414 namespace {
1515
16 typedef ilist_node_base RawNode;
17 typedef ilist_node_base TrackingNode;
18
1619 TEST(IListNodeBaseTest, DefaultConstructor) {
17 ilist_node_base A;
20 RawNode A;
1821 EXPECT_EQ(nullptr, A.getPrev());
1922 EXPECT_EQ(nullptr, A.getNext());
2023 EXPECT_FALSE(A.isKnownSentinel());
24
25 TrackingNode TA;
26 EXPECT_EQ(nullptr, TA.getPrev());
27 EXPECT_EQ(nullptr, TA.getNext());
28 EXPECT_FALSE(TA.isKnownSentinel());
29 EXPECT_FALSE(TA.isSentinel());
2130 }
2231
2332 TEST(IListNodeBaseTest, setPrevAndNext) {
24 ilist_node_base A, B, C;
33 RawNode A, B, C;
2534 A.setPrev(&B);
2635 EXPECT_EQ(&B, A.getPrev());
2736 EXPECT_EQ(nullptr, A.getNext());
3746 EXPECT_EQ(nullptr, B.getNext());
3847 EXPECT_EQ(nullptr, C.getPrev());
3948 EXPECT_EQ(nullptr, C.getNext());
49
50 TrackingNode TA, TB, TC;
51 TA.setPrev(&TB);
52 EXPECT_EQ(&TB, TA.getPrev());
53 EXPECT_EQ(nullptr, TA.getNext());
54 EXPECT_EQ(nullptr, TB.getPrev());
55 EXPECT_EQ(nullptr, TB.getNext());
56 EXPECT_EQ(nullptr, TC.getPrev());
57 EXPECT_EQ(nullptr, TC.getNext());
58
59 TA.setNext(&TC);
60 EXPECT_EQ(&TB, TA.getPrev());
61 EXPECT_EQ(&TC, TA.getNext());
62 EXPECT_EQ(nullptr, TB.getPrev());
63 EXPECT_EQ(nullptr, TB.getNext());
64 EXPECT_EQ(nullptr, TC.getPrev());
65 EXPECT_EQ(nullptr, TC.getNext());
4066 }
4167
4268 TEST(IListNodeBaseTest, isKnownSentinel) {
43 ilist_node_base A, B;
69 // Without sentinel tracking.
70 RawNode A, B;
4471 EXPECT_FALSE(A.isKnownSentinel());
4572 A.setPrev(&B);
4673 A.setNext(&B);
4774 EXPECT_EQ(&B, A.getPrev());
4875 EXPECT_EQ(&B, A.getNext());
76 EXPECT_FALSE(A.isKnownSentinel());
4977 A.initializeSentinel();
50 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
51 EXPECT_TRUE(A.isKnownSentinel());
52 #else
5378 EXPECT_FALSE(A.isKnownSentinel());
54 #endif
5579 EXPECT_EQ(&B, A.getPrev());
5680 EXPECT_EQ(&B, A.getNext());
81
82 // With sentinel tracking.
83 TrackingNode TA, TB;
84 EXPECT_FALSE(TA.isKnownSentinel());
85 EXPECT_FALSE(TA.isSentinel());
86 TA.setPrev(&TB);
87 TA.setNext(&TB);
88 EXPECT_EQ(&TB, TA.getPrev());
89 EXPECT_EQ(&TB, TA.getNext());
90 EXPECT_FALSE(TA.isKnownSentinel());
91 EXPECT_FALSE(TA.isSentinel());
92 TA.initializeSentinel();
93 EXPECT_TRUE(TA.isKnownSentinel());
94 EXPECT_TRUE(TA.isSentinel());
95 EXPECT_EQ(&TB, TA.getPrev());
96 EXPECT_EQ(&TB, TA.getNext());
5797 }
5898
5999 } // end namespace
0 //===- unittests/ADT/IListNodeTest.cpp - ilist_node unit tests ------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ADT/ilist_node.h"
10 #include "gtest/gtest.h"
11 #include
12
13 using namespace llvm;
14 using namespace llvm::ilist_detail;
15
16 namespace {
17
18 struct Node;
19
20 struct TagA {};
21 struct TagB {};
22
23 TEST(IListNodeTest, Options) {
24 static_assert(
25 std::is_same::type,
26 compute_node_options>::type>::value,
27 "default tag is void");
28 static_assert(
29 !std::is_same>::type,
30 compute_node_options>::type>::value,
31 "default tag is void, different from TagA");
32 static_assert(
33 !std::is_same>::type,
34 compute_node_options>::type>::value,
35 "TagA is not TagB");
36 static_assert(
37 std::is_same<
38 compute_node_options>::type,
39 compute_node_options,
40 ilist_tag>::type>::value,
41 "default tag is void, even with sentinel tracking off");
42 static_assert(
43 std::is_same<
44 compute_node_options>::type,
45 compute_node_options,
46 ilist_sentinel_tracking>::type>::value,
47 "order shouldn't matter");
48 static_assert(
49 std::is_same<
50 compute_node_options>::type,
51 compute_node_options,
52 ilist_tag>::type>::value,
53 "default tag is void, even with sentinel tracking on");
54 static_assert(
55 std::is_same<
56 compute_node_options>::type,
57 compute_node_options,
58 ilist_sentinel_tracking>::type>::value,
59 "order shouldn't matter");
60 static_assert(
61 std::is_same<
62 compute_node_options,
63 ilist_tag>::type,
64 compute_node_options,
65 ilist_sentinel_tracking>::type>::value,
66 "order shouldn't matter with real tags");
67 }
68
69 } // end namespace
66 //
77 //===----------------------------------------------------------------------===//
88
9 #include "llvm/ADT/ilist.h"
9 #include "llvm/ADT/ilist_node.h"
1010 #include "gtest/gtest.h"
1111
1212 using namespace llvm;
1313
1414 namespace {
1515
16 template struct PickSentinel {
17 typedef ilist_sentinel<
18 typename ilist_detail::compute_node_options::type>
19 type;
20 };
21
1622 class Node : public ilist_node {};
23 class TrackingNode : public ilist_node> {};
24 typedef PickSentinel::type Sentinel;
25 typedef PickSentinel>::type
26 TrackingSentinel;
27 typedef PickSentinel>::type
28 NoTrackingSentinel;
1729
1830 struct LocalAccess : ilist_detail::NodeAccess {
1931 using NodeAccess::getPrev;
2133 };
2234
2335 TEST(IListSentinelTest, DefaultConstructor) {
24 ilist_sentinel S;
36 Sentinel S;
2537 EXPECT_EQ(&S, LocalAccess::getPrev(S));
2638 EXPECT_EQ(&S, LocalAccess::getNext(S));
2739 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
2941 #else
3042 EXPECT_FALSE(S.isKnownSentinel());
3143 #endif
44
45 TrackingSentinel TS;
46 NoTrackingSentinel NTS;
47 EXPECT_TRUE(TS.isSentinel());
48 EXPECT_TRUE(TS.isKnownSentinel());
49 EXPECT_FALSE(NTS.isKnownSentinel());
3250 }
3351
3452 TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) {
3654 EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
3755 EXPECT_EQ(nullptr, LocalAccess::getNext(N));
3856 EXPECT_FALSE(N.isKnownSentinel());
57
58 TrackingNode TN;
59 EXPECT_FALSE(TN.isSentinel());
3960 }
4061
4162 } // end namespace
582582 L.sort();
583583 }
584584
585 struct Tag1 {};
586 struct Tag2 {};
587
588 struct DoubleNode : ilist_node>,
589 ilist_node> {
590 typedef ilist_node> Node1Type;
591 typedef ilist_node> Node2Type;
592
593 Node1Type::self_iterator getIterator1() { return Node1Type::getIterator(); }
594 Node2Type::self_iterator getIterator2() { return Node2Type::getIterator(); }
595 Node1Type::const_self_iterator getIterator1() const {
596 return Node1Type::getIterator();
597 }
598 Node2Type::const_self_iterator getIterator2() const {
599 return Node2Type::getIterator();
600 }
601 };
602 typedef simple_ilist> TaggedList1Type;
603 typedef simple_ilist> TaggedList2Type;
604
605 TEST(SimpleIListTest, TaggedLists) {
606 TaggedList1Type L1;
607 TaggedList2Type L2;
608
609 // Build the two lists, sharing a couple of nodes.
610 DoubleNode Ns[10];
611 int Order1[] = {0, 1, 2, 3, 4, 7, 9};
612 int Order2[] = {2, 5, 6, 7, 8, 4, 9, 1};
613 for (int I : Order1)
614 L1.push_back(Ns[I]);
615 for (int I : Order2)
616 L2.push_back(Ns[I]);
617
618 // Check that each list is correct.
619 EXPECT_EQ(sizeof(Order1) / sizeof(int), L1.size());
620 auto I1 = L1.begin();
621 for (int I : Order1) {
622 EXPECT_EQ(Ns[I].getIterator1(), I1);
623 EXPECT_EQ(&Ns[I], &*I1++);
624 }
625 EXPECT_EQ(L1.end(), I1);
626
627 EXPECT_EQ(sizeof(Order2) / sizeof(int), L2.size());
628 auto I2 = L2.begin();
629 for (int I : Order2) {
630 EXPECT_EQ(Ns[I].getIterator2(), I2);
631 EXPECT_EQ(&Ns[I], &*I2++);
632 }
633 EXPECT_EQ(L2.end(), I2);
634 }
635
585636 } // end namespace