[llvm] r281167 - ADT: Add sentinel tracking and custom tags to ilists
Duncan P. N. Exon Smith via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 11 09:20:53 PDT 2016
Author: dexonsmith
Date: Sun Sep 11 11:20:53 2016
New Revision: 281167
URL: http://llvm.org/viewvc/llvm-project?rev=281167&view=rev
Log:
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>).
Added:
llvm/trunk/include/llvm/ADT/ilist_node_options.h
llvm/trunk/unittests/ADT/IListNodeTest.cpp
Modified:
llvm/trunk/include/llvm/ADT/ilist.h
llvm/trunk/include/llvm/ADT/ilist_base.h
llvm/trunk/include/llvm/ADT/ilist_iterator.h
llvm/trunk/include/llvm/ADT/ilist_node.h
llvm/trunk/include/llvm/ADT/ilist_node_base.h
llvm/trunk/include/llvm/ADT/simple_ilist.h
llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h
llvm/trunk/unittests/ADT/CMakeLists.txt
llvm/trunk/unittests/ADT/IListBaseTest.cpp
llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp
llvm/trunk/unittests/ADT/IListSentinelTest.cpp
llvm/trunk/unittests/ADT/SimpleIListTest.cpp
Modified: llvm/trunk/include/llvm/ADT/ilist.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist.h Sun Sep 11 11:20:53 2016
@@ -362,13 +362,18 @@ public:
/// An intrusive list with ownership and callbacks specified/controlled by
/// ilist_traits, only with API safe for polymorphic types.
-template <class T>
-class iplist : public iplist_impl<simple_ilist<T>, ilist_traits<T>> {};
+///
+/// The \p Options parameters are the same as those for \a simple_ilist. See
+/// there for a description of what's available.
+template <class T, class... Options>
+class iplist
+ : public iplist_impl<simple_ilist<T, Options...>, ilist_traits<T>> {};
/// An intrusive list with ownership and callbacks specified/controlled by
/// ilist_traits, with API that is unsafe for polymorphic types.
-template <class T> class ilist : public iplist<T> {
- typedef iplist<T> base_list_type;
+template <class T, class... Options>
+class ilist : public iplist<T, Options...> {
+ typedef iplist<T, Options...> base_list_type;
public:
typedef typename base_list_type::size_type size_type;
Modified: llvm/trunk/include/llvm/ADT/ilist_base.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_base.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_base.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_base.h Sun Sep 11 11:20:53 2016
@@ -18,10 +18,10 @@
namespace llvm {
/// Implementations of list algorithms using ilist_node_base.
-class ilist_base {
- typedef ilist_node_base node_base_type;
-
+template <bool EnableSentinelTracking> class ilist_base {
public:
+ typedef ilist_node_base<EnableSentinelTracking> node_base_type;
+
static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
node_base_type &Prev = *Next.getPrev();
N.setNext(&Next);
Modified: llvm/trunk/include/llvm/ADT/ilist_iterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_iterator.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_iterator.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_iterator.h Sun Sep 11 11:20:53 2016
@@ -20,11 +20,21 @@ namespace llvm {
namespace ilist_detail {
-template <class NodeTy> struct ConstCorrectNodeType {
- typedef ilist_node<NodeTy> type;
-};
-template <class NodeTy> struct ConstCorrectNodeType<const NodeTy> {
- typedef const ilist_node<NodeTy> type;
+/// Find const-correct node types.
+template <class OptionsT, bool IsConst> struct IteratorTraits;
+template <class OptionsT> struct IteratorTraits<OptionsT, false> {
+ typedef typename OptionsT::value_type value_type;
+ typedef typename OptionsT::pointer pointer;
+ typedef typename OptionsT::reference reference;
+ typedef ilist_node_impl<OptionsT> *node_pointer;
+ typedef ilist_node_impl<OptionsT> &node_reference;
+};
+template <class OptionsT> struct IteratorTraits<OptionsT, true> {
+ typedef const typename OptionsT::value_type value_type;
+ typedef typename OptionsT::const_pointer pointer;
+ typedef typename OptionsT::const_reference reference;
+ typedef const ilist_node_impl<OptionsT> *node_pointer;
+ typedef const ilist_node_impl<OptionsT> &node_reference;
};
template <bool IsReverse> struct IteratorHelper;
@@ -42,28 +52,29 @@ template <> struct IteratorHelper<true>
} // end namespace ilist_detail
/// Iterator for intrusive lists based on ilist_node.
-template <typename NodeTy, bool IsReverse>
-class ilist_iterator : ilist_detail::SpecificNodeAccess<
- typename std::remove_const<NodeTy>::type> {
- typedef ilist_detail::SpecificNodeAccess<
- typename std::remove_const<NodeTy>::type>
- Access;
+template <class OptionsT, bool IsReverse, bool IsConst>
+class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
+ friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
+ friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
+ friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
+
+ typedef ilist_detail::IteratorTraits<OptionsT, IsConst> Traits;
+ typedef ilist_detail::SpecificNodeAccess<OptionsT> Access;
public:
- typedef NodeTy value_type;
- typedef value_type *pointer;
- typedef value_type &reference;
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
- typedef typename std::add_const<value_type>::type *const_pointer;
- typedef typename std::add_const<value_type>::type &const_reference;
-
- typedef typename ilist_detail::ConstCorrectNodeType<NodeTy>::type node_type;
- typedef node_type *node_pointer;
- typedef node_type &node_reference;
+ typedef typename OptionsT::const_pointer const_pointer;
+ typedef typename OptionsT::const_reference const_reference;
private:
+ typedef typename Traits::node_pointer node_pointer;
+ typedef typename Traits::node_reference node_reference;
+
node_pointer NodePtr;
public:
@@ -76,19 +87,18 @@ public:
// This is templated so that we can allow constructing a const iterator from
// a nonconst iterator...
- template <class node_ty>
+ template <bool RHSIsConst>
ilist_iterator(
- const ilist_iterator<node_ty, IsReverse> &RHS,
- typename std::enable_if<std::is_convertible<node_ty *, NodeTy *>::value,
- void *>::type = nullptr)
- : NodePtr(RHS.getNodePtr()) {}
+ const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS,
+ typename std::enable_if<IsConst || !RHSIsConst, void *>::type = nullptr)
+ : NodePtr(RHS.NodePtr) {}
// This is templated so that we can allow assigning to a const iterator from
// a nonconst iterator...
- template <class node_ty>
- const ilist_iterator &
- operator=(const ilist_iterator<node_ty, IsReverse> &RHS) {
- NodePtr = RHS.getNodePtr();
+ template <bool RHSIsConst>
+ typename std::enable_if<IsConst || !RHSIsConst, ilist_iterator &>::type
+ operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) {
+ NodePtr = RHS.NodePtr;
return *this;
}
@@ -96,10 +106,19 @@ public:
///
/// TODO: Roll this into the implicit constructor once we're sure that no one
/// is relying on the std::reverse_iterator off-by-one semantics.
- ilist_iterator<NodeTy, !IsReverse> getReverse() const {
+ ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const {
+ if (NodePtr)
+ return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr);
+ return ilist_iterator<OptionsT, !IsReverse, IsConst>();
+ }
+
+ /// Const-cast.
+ ilist_iterator<OptionsT, IsReverse, false> getNonConst() const {
if (NodePtr)
- return ilist_iterator<NodeTy, !IsReverse>(*NodePtr);
- return ilist_iterator<NodeTy, !IsReverse>();
+ return ilist_iterator<OptionsT, IsReverse, false>(
+ const_cast<typename ilist_iterator<OptionsT, IsReverse,
+ false>::node_reference>(*NodePtr));
+ return ilist_iterator<OptionsT, IsReverse, false>();
}
void reset(pointer NP) { NodePtr = NP; }
@@ -121,11 +140,11 @@ public:
// Increment and decrement operators...
ilist_iterator &operator--() {
- ilist_detail::IteratorHelper<IsReverse>::decrement(NodePtr);
+ NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
return *this;
}
ilist_iterator &operator++() {
- ilist_detail::IteratorHelper<IsReverse>::increment(NodePtr);
+ NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
return *this;
}
ilist_iterator operator--(int) {
@@ -149,20 +168,16 @@ template <typename From> struct simplify
/// used by the dyn_cast, cast, isa mechanisms...
///
/// FIXME: remove this, since there is no implicit conversion to NodeTy.
-template <typename NodeTy> struct simplify_type<ilist_iterator<NodeTy>> {
- typedef NodeTy *SimpleType;
-
- static SimpleType getSimplifiedValue(ilist_iterator<NodeTy> &Node) {
- return &*Node;
- }
-};
-template <typename NodeTy> struct simplify_type<const ilist_iterator<NodeTy>> {
- typedef /*const*/ NodeTy *SimpleType;
-
- static SimpleType getSimplifiedValue(const ilist_iterator<NodeTy> &Node) {
- return &*Node;
- }
-};
+template <class OptionsT, bool IsConst>
+struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> {
+ typedef ilist_iterator<OptionsT, false, IsConst> iterator;
+ typedef typename iterator::pointer SimpleType;
+
+ static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
+};
+template <class OptionsT, bool IsConst>
+struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>>
+ : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {};
} // end namespace llvm
Modified: llvm/trunk/include/llvm/ADT/ilist_node.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_node.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_node.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_node.h Sun Sep 11 11:20:53 2016
@@ -16,6 +16,7 @@
#define LLVM_ADT_ILIST_NODE_H
#include "llvm/ADT/ilist_node_base.h"
+#include "llvm/ADT/ilist_node_options.h"
namespace llvm {
@@ -26,46 +27,121 @@ struct NodeAccess;
template<typename NodeTy>
struct ilist_traits;
-template <typename NodeTy, bool IsReverse = false> class ilist_iterator;
-template <typename NodeTy> class ilist_sentinel;
+template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
+template <class OptionsT> class ilist_sentinel;
-/// Templated wrapper class.
-template <typename NodeTy> class ilist_node : ilist_node_base {
- friend class ilist_base;
+/// Implementation for an ilist node.
+///
+/// Templated on an appropriate \a ilist_detail::node_options, usually computed
+/// by \a ilist_detail::compute_node_options.
+///
+/// This is a wrapper around \a ilist_node_base whose main purpose is to
+/// provide type safety: you can't insert nodes of \a ilist_node_impl into the
+/// wrong \a simple_ilist or \a iplist.
+template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
+ typedef typename OptionsT::value_type value_type;
+ typedef typename OptionsT::node_base_type node_base_type;
+ typedef typename OptionsT::list_base_type list_base_type;
+
+ friend typename OptionsT::list_base_type;
friend struct ilist_detail::NodeAccess;
- friend struct ilist_traits<NodeTy>;
- friend class ilist_iterator<NodeTy, false>;
- friend class ilist_iterator<NodeTy, true>;
- friend class ilist_sentinel<NodeTy>;
+ friend class ilist_sentinel<OptionsT>;
+ friend class ilist_iterator<OptionsT, false, false>;
+ friend class ilist_iterator<OptionsT, false, true>;
+ friend class ilist_iterator<OptionsT, true, false>;
+ friend class ilist_iterator<OptionsT, true, true>;
protected:
- ilist_node() = default;
+ ilist_node_impl() = default;
+
+ typedef ilist_iterator<OptionsT, false, false> self_iterator;
+ typedef ilist_iterator<OptionsT, false, true> const_self_iterator;
+ typedef ilist_iterator<OptionsT, true, false> reverse_self_iterator;
+ typedef ilist_iterator<OptionsT, true, true> const_reverse_self_iterator;
private:
- ilist_node *getPrev() {
- return static_cast<ilist_node *>(ilist_node_base::getPrev());
+ ilist_node_impl *getPrev() {
+ return static_cast<ilist_node_impl *>(node_base_type::getPrev());
}
- ilist_node *getNext() {
- return static_cast<ilist_node *>(ilist_node_base::getNext());
+ ilist_node_impl *getNext() {
+ return static_cast<ilist_node_impl *>(node_base_type::getNext());
}
- const ilist_node *getPrev() const {
- return static_cast<ilist_node *>(ilist_node_base::getPrev());
+ const ilist_node_impl *getPrev() const {
+ return static_cast<ilist_node_impl *>(node_base_type::getPrev());
}
- const ilist_node *getNext() const {
- return static_cast<ilist_node *>(ilist_node_base::getNext());
+ const ilist_node_impl *getNext() const {
+ return static_cast<ilist_node_impl *>(node_base_type::getNext());
}
- void setPrev(ilist_node *N) { ilist_node_base::setPrev(N); }
- void setNext(ilist_node *N) { ilist_node_base::setNext(N); }
+ void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); }
+ void setNext(ilist_node_impl *N) { node_base_type::setNext(N); }
public:
- ilist_iterator<NodeTy> getIterator() { return ilist_iterator<NodeTy>(*this); }
- ilist_iterator<const NodeTy> getIterator() const {
- return ilist_iterator<const NodeTy>(*this);
+ self_iterator getIterator() { return self_iterator(*this); }
+ const_self_iterator getIterator() const { return const_self_iterator(*this); }
+
+ // Under-approximation, but always available for assertions.
+ using node_base_type::isKnownSentinel;
+
+ /// Check whether this is the sentinel node.
+ ///
+ /// This requires sentinel tracking to be explicitly enabled. Use the
+ /// ilist_sentinel_tracking<true> option to get this API.
+ bool isSentinel() const {
+ static_assert(OptionsT::is_sentinel_tracking_explicit,
+ "Use ilist_sentinel_tracking<true> to enable isSentinel()");
+ return node_base_type::isSentinel();
}
+};
- using ilist_node_base::isKnownSentinel;
+/// An intrusive list node.
+///
+/// A base class to enable membership in intrusive lists, including \a
+/// simple_ilist, \a iplist, and \a ilist. The first template parameter is the
+/// \a value_type for the list.
+///
+/// An ilist node can be configured with compile-time options to change
+/// behaviour and/or add API.
+///
+/// By default, an \a ilist_node knows whether it is the list sentinel (an
+/// instance of \a ilist_sentinel) if and only if
+/// LLVM_ENABLE_ABI_BREAKING_CHECKS. The function \a isKnownSentinel() always
+/// returns \c false tracking is off. Sentinel tracking steals a bit from the
+/// "prev" link, which adds a mask operation when decrementing an iterator, but
+/// enables bug-finding assertions in \a ilist_iterator.
+///
+/// To turn sentinel tracking on all the time, pass in the
+/// ilist_sentinel_tracking<true> template parameter. This also enables the \a
+/// isSentinel() function. The same option must be passed to the intrusive
+/// list. (ilist_sentinel_tracking<false> turns sentinel tracking off all the
+/// time.)
+///
+/// A type can inherit from ilist_node multiple times by passing in different
+/// \a ilist_tag options. This allows a single instance to be inserted into
+/// multiple lists simultaneously, where each list is given the same tag.
+///
+/// \example
+/// struct A {};
+/// struct B {};
+/// struct N : ilist_node<N, ilist_tag<A>>, ilist_node<N, ilist_tag<B>> {};
+///
+/// void foo() {
+/// simple_ilist<N, ilist_tag<A>> ListA;
+/// simple_ilist<N, ilist_tag<B>> ListB;
+/// N N1;
+/// ListA.push_back(N1);
+/// ListB.push_back(N1);
+/// }
+/// \endexample
+///
+/// See \a is_valid_option for steps on adding a new option.
+template <class T, class... Options>
+class ilist_node
+ : public ilist_node_impl<
+ typename ilist_detail::compute_node_options<T, Options...>::type> {
+ static_assert(ilist_detail::check_options<Options...>::value,
+ "Unrecognized node option!");
};
namespace ilist_detail {
@@ -77,58 +153,71 @@ namespace ilist_detail {
/// Using this class outside of the ilist implementation is unsupported.
struct NodeAccess {
protected:
- template <typename T> static ilist_node<T> *getNodePtr(T *N) { return N; }
- template <typename T> static const ilist_node<T> *getNodePtr(const T *N) {
+ template <class OptionsT>
+ static ilist_node_impl<OptionsT> *getNodePtr(typename OptionsT::pointer N) {
return N;
}
- template <typename T> static T *getValuePtr(ilist_node<T> *N) {
- return static_cast<T *>(N);
+ template <class OptionsT>
+ static const ilist_node_impl<OptionsT> *
+ getNodePtr(typename OptionsT::const_pointer N) {
+ return N;
}
- template <typename T> static const T *getValuePtr(const ilist_node<T> *N) {
- return static_cast<const T *>(N);
+ template <class OptionsT>
+ static typename OptionsT::pointer getValuePtr(ilist_node_impl<OptionsT> *N) {
+ return static_cast<typename OptionsT::pointer>(N);
+ }
+ template <class OptionsT>
+ static typename OptionsT::const_pointer
+ getValuePtr(const ilist_node_impl<OptionsT> *N) {
+ return static_cast<typename OptionsT::const_pointer>(N);
}
- template <typename T> static ilist_node<T> *getPrev(ilist_node<T> &N) {
+ template <class OptionsT>
+ static ilist_node_impl<OptionsT> *getPrev(ilist_node_impl<OptionsT> &N) {
return N.getPrev();
}
- template <typename T> static ilist_node<T> *getNext(ilist_node<T> &N) {
+ template <class OptionsT>
+ static ilist_node_impl<OptionsT> *getNext(ilist_node_impl<OptionsT> &N) {
return N.getNext();
}
- template <typename T>
- static const ilist_node<T> *getPrev(const ilist_node<T> &N) {
+ template <class OptionsT>
+ static const ilist_node_impl<OptionsT> *
+ getPrev(const ilist_node_impl<OptionsT> &N) {
return N.getPrev();
}
- template <typename T>
- static const ilist_node<T> *getNext(const ilist_node<T> &N) {
+ template <class OptionsT>
+ static const ilist_node_impl<OptionsT> *
+ getNext(const ilist_node_impl<OptionsT> &N) {
return N.getNext();
}
};
-template <class T> struct SpecificNodeAccess : NodeAccess {
+template <class OptionsT> struct SpecificNodeAccess : NodeAccess {
protected:
- typedef T *pointer;
- typedef const T *const_pointer;
- typedef ilist_node<T> node_type;
+ typedef typename OptionsT::pointer pointer;
+ typedef typename OptionsT::const_pointer const_pointer;
+ typedef ilist_node_impl<OptionsT> node_type;
static node_type *getNodePtr(pointer N) {
- return NodeAccess::getNodePtr<T>(N);
+ return NodeAccess::getNodePtr<OptionsT>(N);
}
- static const ilist_node<T> *getNodePtr(const_pointer N) {
- return NodeAccess::getNodePtr<T>(N);
+ static const node_type *getNodePtr(const_pointer N) {
+ return NodeAccess::getNodePtr<OptionsT>(N);
}
static pointer getValuePtr(node_type *N) {
- return NodeAccess::getValuePtr<T>(N);
+ return NodeAccess::getValuePtr<OptionsT>(N);
}
static const_pointer getValuePtr(const node_type *N) {
- return NodeAccess::getValuePtr<T>(N);
+ return NodeAccess::getValuePtr<OptionsT>(N);
}
};
} // end namespace ilist_detail
-template <typename NodeTy> class ilist_sentinel : public ilist_node<NodeTy> {
+template <class OptionsT>
+class ilist_sentinel : public ilist_node_impl<OptionsT> {
public:
ilist_sentinel() {
- ilist_node_base::initializeSentinel();
+ this->initializeSentinel();
reset();
}
@@ -144,8 +233,8 @@ public:
///
/// Requires \c NodeTy to have \a getParent() to find the parent node, and the
/// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
-template <typename NodeTy, typename ParentTy>
-class ilist_node_with_parent : public ilist_node<NodeTy> {
+template <typename NodeTy, typename ParentTy, class... Options>
+class ilist_node_with_parent : public ilist_node<NodeTy, Options...> {
protected:
ilist_node_with_parent() = default;
Modified: llvm/trunk/include/llvm/ADT/ilist_node_base.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_node_base.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_node_base.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_node_base.h Sun Sep 11 11:20:53 2016
@@ -15,31 +15,37 @@
namespace llvm {
/// Base class for ilist nodes.
-class ilist_node_base {
-#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
- PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
-#else
+///
+/// Optionally tracks whether this node is the sentinel.
+template <bool EnableSentinelTracking> class ilist_node_base;
+
+template <> class ilist_node_base<false> {
ilist_node_base *Prev = nullptr;
-#endif
ilist_node_base *Next = nullptr;
public:
-#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
- void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
- ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
-
- bool isKnownSentinel() const { return PrevAndSentinel.getInt(); }
- void initializeSentinel() { PrevAndSentinel.setInt(true); }
-#else
void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
+ void setNext(ilist_node_base *Next) { this->Next = Next; }
ilist_node_base *getPrev() const { return Prev; }
+ ilist_node_base *getNext() const { return Next; }
bool isKnownSentinel() const { return false; }
void initializeSentinel() {}
-#endif
+};
+template <> class ilist_node_base<true> {
+ PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
+ ilist_node_base *Next = nullptr;
+
+public:
+ void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
void setNext(ilist_node_base *Next) { this->Next = Next; }
+ ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
ilist_node_base *getNext() const { return Next; }
+
+ bool isSentinel() const { return PrevAndSentinel.getInt(); }
+ bool isKnownSentinel() const { return isSentinel(); }
+ void initializeSentinel() { PrevAndSentinel.setInt(true); }
};
} // end namespace llvm
Added: llvm/trunk/include/llvm/ADT/ilist_node_options.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_node_options.h?rev=281167&view=auto
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_node_options.h (added)
+++ llvm/trunk/include/llvm/ADT/ilist_node_options.h Sun Sep 11 11:20:53 2016
@@ -0,0 +1,128 @@
+//===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- 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_ILIST_NODE_OPTIONS_H
+#define LLVM_ADT_ILIST_NODE_OPTIONS_H
+
+namespace llvm {
+
+template <bool EnableSentinelTracking> class ilist_node_base;
+template <bool EnableSentinelTracking> class ilist_base;
+
+/// Option to choose whether to track sentinels.
+///
+/// This option affects the ABI for the nodes. When not specified explicitly,
+/// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS. Specify explicitly to
+/// enable \a ilist_node::isSentinel().
+template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {};
+
+/// Option to specify a tag for the node type.
+///
+/// This option allows a single value type to be inserted in multiple lists
+/// simultaneously. See \a ilist_node for usage examples.
+template <class Tag> struct ilist_tag {};
+
+namespace ilist_detail {
+
+/// Helper trait for recording whether an option is specified explicitly.
+template <bool IsExplicit> struct explicitness {
+ static const bool is_explicit = IsExplicit;
+};
+typedef explicitness<true> is_explicit;
+typedef explicitness<false> is_implicit;
+
+/// Check whether an option is valid.
+///
+/// The steps for adding and enabling a new ilist option include:
+/// \li define the option, ilist_foo<Bar>, above;
+/// \li add new parameters for Bar to \a ilist_detail::node_options;
+/// \li add an extraction meta-function, ilist_detail::extract_foo;
+/// \li call extract_foo from \a ilist_detail::compute_node_options and pass it
+/// into \a ilist_detail::node_options; and
+/// \li specialize \c is_valid_option<ilist_foo<Bar>> to inherit from \c
+/// std::true_type to get static assertions passing in \a simple_ilist and \a
+/// ilist_node.
+template <class Option> struct is_valid_option : std::false_type {};
+
+/// Extract sentinel tracking option.
+///
+/// Look through \p Options for the \a ilist_sentinel_tracking option, with the
+/// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS.
+template <class... Options> struct extract_sentinel_tracking;
+template <bool EnableSentinelTracking, class... Options>
+struct extract_sentinel_tracking<
+ ilist_sentinel_tracking<EnableSentinelTracking>, Options...>
+ : std::integral_constant<bool, EnableSentinelTracking>, is_explicit {};
+template <class Option1, class... Options>
+struct extract_sentinel_tracking<Option1, Options...>
+ : extract_sentinel_tracking<Options...> {};
+#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
+template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {};
+#else
+template <>
+struct extract_sentinel_tracking<> : std::false_type, is_implicit {};
+#endif
+template <bool EnableSentinelTracking>
+struct is_valid_option<ilist_sentinel_tracking<EnableSentinelTracking>>
+ : std::true_type {};
+
+/// Extract custom tag option.
+///
+/// Look through \p Options for the \a ilist_tag option, pulling out the
+/// custom tag type, using void as a default.
+template <class... Options> struct extract_tag;
+template <class Tag, class... Options>
+struct extract_tag<ilist_tag<Tag>, Options...> {
+ typedef Tag type;
+};
+template <class Option1, class... Options>
+struct extract_tag<Option1, Options...> : extract_tag<Options...> {};
+template <> struct extract_tag<> { typedef void type; };
+template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {};
+
+/// Check whether options are valid.
+///
+/// The conjunction of \a is_valid_option on each individual option.
+template <class... Options> struct check_options;
+template <> struct check_options<> : std::true_type {};
+template <class Option1, class... Options>
+struct check_options<Option1, Options...>
+ : std::integral_constant<bool, is_valid_option<Option1>::value &&
+ check_options<Options...>::value> {};
+
+/// Traits for options for \a ilist_node.
+///
+/// This is usually computed via \a compute_node_options.
+template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
+ class TagT>
+struct node_options {
+ typedef T value_type;
+ typedef T *pointer;
+ typedef T &reference;
+ typedef const T *const_pointer;
+ typedef const T &const_reference;
+
+ static const bool enable_sentinel_tracking = EnableSentinelTracking;
+ static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
+ typedef TagT tag;
+ typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
+ typedef ilist_base<enable_sentinel_tracking> list_base_type;
+};
+
+template <class T, class... Options> struct compute_node_options {
+ typedef node_options<T, extract_sentinel_tracking<Options...>::value,
+ extract_sentinel_tracking<Options...>::is_explicit,
+ typename extract_tag<Options...>::type>
+ type;
+};
+
+} // end namespace ilist_detail
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_NODE_OPTIONS_H
Modified: llvm/trunk/include/llvm/ADT/simple_ilist.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/simple_ilist.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/simple_ilist.h (original)
+++ llvm/trunk/include/llvm/ADT/simple_ilist.h Sun Sep 11 11:20:53 2016
@@ -46,23 +46,54 @@ namespace llvm {
/// 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.
-template <typename T>
-class simple_ilist : ilist_base, ilist_detail::SpecificNodeAccess<T> {
- typedef ilist_base list_base_type;
- ilist_sentinel<T> Sentinel;
+///
+/// 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!");
+ typedef
+ typename ilist_detail::compute_node_options<T, Options...>::type OptionsT;
+ typedef typename OptionsT::list_base_type list_base_type;
+ ilist_sentinel<OptionsT> Sentinel;
public:
- typedef T value_type;
- typedef T *pointer;
- typedef T &reference;
- typedef const T *const_pointer;
- typedef const T &const_reference;
- typedef ilist_iterator<T> iterator;
- typedef ilist_iterator<const T> const_iterator;
+ typedef typename OptionsT::value_type value_type;
+ typedef typename OptionsT::pointer pointer;
+ typedef typename OptionsT::reference reference;
+ typedef typename OptionsT::const_pointer const_pointer;
+ typedef typename OptionsT::const_reference const_reference;
+ typedef ilist_iterator<OptionsT, false, false> iterator;
+ typedef ilist_iterator<OptionsT, false, true> const_iterator;
+ typedef ilist_iterator<OptionsT, true, false> reverse_iterator;
+ typedef ilist_iterator<OptionsT, true, true> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
- typedef ilist_iterator<const T, true> const_reverse_iterator;
- typedef ilist_iterator<T, true> reverse_iterator;
simple_ilist() = default;
~simple_ilist() = default;
@@ -222,9 +253,9 @@ public:
///@}
};
-template <class T>
+template <class T, class... Options>
template <class Compare>
-void simple_ilist<T>::merge(simple_ilist<T> &RHS, Compare comp) {
+void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
if (this == &RHS || RHS.empty())
return;
iterator LI = begin(), LE = end();
@@ -244,9 +275,9 @@ void simple_ilist<T>::merge(simple_ilist
splice(LE, RHS, RI, RE);
}
-template <class T>
+template <class T, class... Options>
template <class Compare>
-void simple_ilist<T>::sort(Compare comp) {
+void simple_ilist<T, Options...>::sort(Compare comp) {
// Vacuously sorted.
if (empty() || std::next(begin()) == end())
return;
@@ -257,7 +288,7 @@ void simple_ilist<T>::sort(Compare comp)
++Center;
++End;
}
- simple_ilist<T> RHS;
+ simple_ilist RHS;
RHS.splice(RHS.end(), *this, Center, end());
// Sort the sublists and merge back together.
Modified: llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h Sun Sep 11 11:20:53 2016
@@ -19,10 +19,22 @@
namespace llvm {
+template <class T> struct MachineInstrBundleIteratorTraits {
+ typedef simple_ilist<T> list_type;
+ typedef typename list_type::iterator instr_iterator;
+ typedef typename list_type::iterator nonconst_instr_iterator;
+};
+template <class T> struct MachineInstrBundleIteratorTraits<const T> {
+ typedef simple_ilist<T> list_type;
+ typedef typename list_type::const_iterator instr_iterator;
+ typedef typename list_type::iterator nonconst_instr_iterator;
+};
+
/// MachineBasicBlock iterator that automatically skips over MIs that are
/// inside bundles (i.e. walk top level MIs only).
template <typename Ty> class MachineInstrBundleIterator {
- typedef ilist_iterator<Ty> instr_iterator;
+ typedef typename MachineInstrBundleIteratorTraits<Ty>::instr_iterator
+ instr_iterator;
instr_iterator MII;
public:
@@ -37,8 +49,8 @@ public:
private:
typedef typename std::remove_const<value_type>::type nonconst_value_type;
- typedef ilist_node<nonconst_value_type> node_type;
- typedef ilist_iterator<nonconst_value_type> nonconst_instr_iterator;
+ typedef typename MachineInstrBundleIteratorTraits<Ty>::nonconst_instr_iterator
+ nonconst_instr_iterator;
typedef MachineInstrBundleIterator<nonconst_value_type> nonconst_iterator;
public:
@@ -136,11 +148,7 @@ public:
instr_iterator getInstrIterator() const { return MII; }
- nonconst_iterator getNonConstIterator() const {
- if (auto *N = const_cast<node_type *>(MII.getNodePtr()))
- return nonconst_iterator(nonconst_instr_iterator(*N));
- return nonconst_iterator();
- }
+ nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); }
};
} // end namespace llvm
Modified: llvm/trunk/unittests/ADT/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/CMakeLists.txt (original)
+++ llvm/trunk/unittests/ADT/CMakeLists.txt Sun Sep 11 11:20:53 2016
@@ -20,6 +20,7 @@ set(ADTSources
IListBaseTest.cpp
IListIteratorTest.cpp
IListNodeBaseTest.cpp
+ IListNodeTest.cpp
IListSentinelTest.cpp
IListTest.cpp
ImmutableMapTest.cpp
Modified: llvm/trunk/unittests/ADT/IListBaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListBaseTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/IListBaseTest.cpp (original)
+++ llvm/trunk/unittests/ADT/IListBaseTest.cpp Sun Sep 11 11:20:53 2016
@@ -14,11 +14,20 @@ using namespace llvm;
namespace {
-typedef ilist_base list_base_type;
-typedef ilist_node_base node_base_type;
+// Test fixture.
+template <typename T> class IListBaseTest : public ::testing::Test {};
+
+// Test variants with the same test.
+typedef ::testing::Types<ilist_base<false>, ilist_base<true>>
+ IListBaseTestTypes;
+TYPED_TEST_CASE(IListBaseTest, IListBaseTestTypes);
+
+TYPED_TEST(IListBaseTest, insertBeforeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
-TEST(IListBaseTest, insertBeforeImpl) {
node_base_type S, A, B;
+
// [S] <-> [S]
S.setPrev(&S);
S.setNext(&S);
@@ -40,7 +49,10 @@ TEST(IListBaseTest, insertBeforeImpl) {
EXPECT_EQ(&S, B.getNext());
}
-TEST(IListBaseTest, removeImpl) {
+TYPED_TEST(IListBaseTest, removeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
node_base_type S, A, B;
// [S] <-> A <-> B <-> [S]
@@ -66,7 +78,10 @@ TEST(IListBaseTest, removeImpl) {
EXPECT_EQ(nullptr, B.getNext());
}
-TEST(IListBaseTest, removeRangeImpl) {
+TYPED_TEST(IListBaseTest, removeRangeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
node_base_type S, A, B, C, D;
// [S] <-> A <-> B <-> C <-> D <-> [S]
@@ -89,7 +104,10 @@ TEST(IListBaseTest, removeRangeImpl) {
EXPECT_EQ(nullptr, C.getNext());
}
-TEST(IListBaseTest, removeRangeImplAllButSentinel) {
+TYPED_TEST(IListBaseTest, removeRangeImplAllButSentinel) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
node_base_type S, A, B;
// [S] <-> A <-> B <-> [S]
@@ -106,7 +124,10 @@ TEST(IListBaseTest, removeRangeImplAllBu
EXPECT_EQ(nullptr, B.getNext());
}
-TEST(IListBaseTest, transferBeforeImpl) {
+TYPED_TEST(IListBaseTest, transferBeforeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
node_base_type S1, S2, A, B, C, D, E;
// [S1] <-> A <-> B <-> C <-> [S1]
Modified: llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp (original)
+++ llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp Sun Sep 11 11:20:53 2016
@@ -14,15 +14,24 @@ using namespace llvm;
namespace {
+typedef ilist_node_base<false> RawNode;
+typedef ilist_node_base<true> TrackingNode;
+
TEST(IListNodeBaseTest, DefaultConstructor) {
- ilist_node_base A;
+ RawNode A;
EXPECT_EQ(nullptr, A.getPrev());
EXPECT_EQ(nullptr, A.getNext());
EXPECT_FALSE(A.isKnownSentinel());
+
+ TrackingNode TA;
+ EXPECT_EQ(nullptr, TA.getPrev());
+ EXPECT_EQ(nullptr, TA.getNext());
+ EXPECT_FALSE(TA.isKnownSentinel());
+ EXPECT_FALSE(TA.isSentinel());
}
TEST(IListNodeBaseTest, setPrevAndNext) {
- ilist_node_base A, B, C;
+ RawNode A, B, C;
A.setPrev(&B);
EXPECT_EQ(&B, A.getPrev());
EXPECT_EQ(nullptr, A.getNext());
@@ -38,23 +47,54 @@ TEST(IListNodeBaseTest, setPrevAndNext)
EXPECT_EQ(nullptr, B.getNext());
EXPECT_EQ(nullptr, C.getPrev());
EXPECT_EQ(nullptr, C.getNext());
+
+ TrackingNode TA, TB, TC;
+ TA.setPrev(&TB);
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(nullptr, TA.getNext());
+ EXPECT_EQ(nullptr, TB.getPrev());
+ EXPECT_EQ(nullptr, TB.getNext());
+ EXPECT_EQ(nullptr, TC.getPrev());
+ EXPECT_EQ(nullptr, TC.getNext());
+
+ TA.setNext(&TC);
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(&TC, TA.getNext());
+ EXPECT_EQ(nullptr, TB.getPrev());
+ EXPECT_EQ(nullptr, TB.getNext());
+ EXPECT_EQ(nullptr, TC.getPrev());
+ EXPECT_EQ(nullptr, TC.getNext());
}
TEST(IListNodeBaseTest, isKnownSentinel) {
- ilist_node_base A, B;
+ // Without sentinel tracking.
+ RawNode A, B;
EXPECT_FALSE(A.isKnownSentinel());
A.setPrev(&B);
A.setNext(&B);
EXPECT_EQ(&B, A.getPrev());
EXPECT_EQ(&B, A.getNext());
+ EXPECT_FALSE(A.isKnownSentinel());
A.initializeSentinel();
-#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
- EXPECT_TRUE(A.isKnownSentinel());
-#else
EXPECT_FALSE(A.isKnownSentinel());
-#endif
EXPECT_EQ(&B, A.getPrev());
EXPECT_EQ(&B, A.getNext());
+
+ // With sentinel tracking.
+ TrackingNode TA, TB;
+ EXPECT_FALSE(TA.isKnownSentinel());
+ EXPECT_FALSE(TA.isSentinel());
+ TA.setPrev(&TB);
+ TA.setNext(&TB);
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(&TB, TA.getNext());
+ EXPECT_FALSE(TA.isKnownSentinel());
+ EXPECT_FALSE(TA.isSentinel());
+ TA.initializeSentinel();
+ EXPECT_TRUE(TA.isKnownSentinel());
+ EXPECT_TRUE(TA.isSentinel());
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(&TB, TA.getNext());
}
} // end namespace
Added: llvm/trunk/unittests/ADT/IListNodeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListNodeTest.cpp?rev=281167&view=auto
==============================================================================
--- llvm/trunk/unittests/ADT/IListNodeTest.cpp (added)
+++ llvm/trunk/unittests/ADT/IListNodeTest.cpp Sun Sep 11 11:20:53 2016
@@ -0,0 +1,70 @@
+//===- unittests/ADT/IListNodeTest.cpp - ilist_node unit tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_node.h"
+#include "gtest/gtest.h"
+#include <type_traits>
+
+using namespace llvm;
+using namespace llvm::ilist_detail;
+
+namespace {
+
+struct Node;
+
+struct TagA {};
+struct TagB {};
+
+TEST(IListNodeTest, Options) {
+ static_assert(
+ std::is_same<compute_node_options<Node>::type,
+ compute_node_options<Node, ilist_tag<void>>::type>::value,
+ "default tag is void");
+ static_assert(
+ !std::is_same<compute_node_options<Node, ilist_tag<TagA>>::type,
+ compute_node_options<Node, ilist_tag<void>>::type>::value,
+ "default tag is void, different from TagA");
+ static_assert(
+ !std::is_same<compute_node_options<Node, ilist_tag<TagA>>::type,
+ compute_node_options<Node, ilist_tag<TagB>>::type>::value,
+ "TagA is not TagB");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<false>>::type,
+ compute_node_options<Node, ilist_sentinel_tracking<false>,
+ ilist_tag<void>>::type>::value,
+ "default tag is void, even with sentinel tracking off");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<false>>::type,
+ compute_node_options<Node, ilist_tag<void>,
+ ilist_sentinel_tracking<false>>::type>::value,
+ "order shouldn't matter");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<true>>::type,
+ compute_node_options<Node, ilist_sentinel_tracking<true>,
+ ilist_tag<void>>::type>::value,
+ "default tag is void, even with sentinel tracking on");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<true>>::type,
+ compute_node_options<Node, ilist_tag<void>,
+ ilist_sentinel_tracking<true>>::type>::value,
+ "order shouldn't matter");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<true>,
+ ilist_tag<TagA>>::type,
+ compute_node_options<Node, ilist_tag<TagA>,
+ ilist_sentinel_tracking<true>>::type>::value,
+ "order shouldn't matter with real tags");
+}
+
+} // end namespace
Modified: llvm/trunk/unittests/ADT/IListSentinelTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListSentinelTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/IListSentinelTest.cpp (original)
+++ llvm/trunk/unittests/ADT/IListSentinelTest.cpp Sun Sep 11 11:20:53 2016
@@ -7,14 +7,26 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
+template <class T, class... Options> struct PickSentinel {
+ typedef ilist_sentinel<
+ typename ilist_detail::compute_node_options<T, Options...>::type>
+ type;
+};
+
class Node : public ilist_node<Node> {};
+class TrackingNode : public ilist_node<Node, ilist_sentinel_tracking<true>> {};
+typedef PickSentinel<Node>::type Sentinel;
+typedef PickSentinel<Node, ilist_sentinel_tracking<true>>::type
+ TrackingSentinel;
+typedef PickSentinel<Node, ilist_sentinel_tracking<false>>::type
+ NoTrackingSentinel;
struct LocalAccess : ilist_detail::NodeAccess {
using NodeAccess::getPrev;
@@ -22,7 +34,7 @@ struct LocalAccess : ilist_detail::NodeA
};
TEST(IListSentinelTest, DefaultConstructor) {
- ilist_sentinel<Node> S;
+ Sentinel S;
EXPECT_EQ(&S, LocalAccess::getPrev(S));
EXPECT_EQ(&S, LocalAccess::getNext(S));
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
@@ -30,6 +42,12 @@ TEST(IListSentinelTest, DefaultConstruct
#else
EXPECT_FALSE(S.isKnownSentinel());
#endif
+
+ TrackingSentinel TS;
+ NoTrackingSentinel NTS;
+ EXPECT_TRUE(TS.isSentinel());
+ EXPECT_TRUE(TS.isKnownSentinel());
+ EXPECT_FALSE(NTS.isKnownSentinel());
}
TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) {
@@ -37,6 +55,9 @@ TEST(IListSentinelTest, NormalNodeIsNotK
EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
EXPECT_EQ(nullptr, LocalAccess::getNext(N));
EXPECT_FALSE(N.isKnownSentinel());
+
+ TrackingNode TN;
+ EXPECT_FALSE(TN.isSentinel());
}
} // end namespace
Modified: llvm/trunk/unittests/ADT/SimpleIListTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/SimpleIListTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/SimpleIListTest.cpp (original)
+++ llvm/trunk/unittests/ADT/SimpleIListTest.cpp Sun Sep 11 11:20:53 2016
@@ -583,4 +583,55 @@ TEST(SimpleIListTest, sortEmpty) {
L.sort();
}
+struct Tag1 {};
+struct Tag2 {};
+
+struct DoubleNode : ilist_node<DoubleNode, ilist_tag<Tag1>>,
+ ilist_node<DoubleNode, ilist_tag<Tag2>> {
+ typedef ilist_node<DoubleNode, ilist_tag<Tag1>> Node1Type;
+ typedef ilist_node<DoubleNode, ilist_tag<Tag2>> Node2Type;
+
+ Node1Type::self_iterator getIterator1() { return Node1Type::getIterator(); }
+ Node2Type::self_iterator getIterator2() { return Node2Type::getIterator(); }
+ Node1Type::const_self_iterator getIterator1() const {
+ return Node1Type::getIterator();
+ }
+ Node2Type::const_self_iterator getIterator2() const {
+ return Node2Type::getIterator();
+ }
+};
+typedef simple_ilist<DoubleNode, ilist_tag<Tag1>> TaggedList1Type;
+typedef simple_ilist<DoubleNode, ilist_tag<Tag2>> TaggedList2Type;
+
+TEST(SimpleIListTest, TaggedLists) {
+ TaggedList1Type L1;
+ TaggedList2Type L2;
+
+ // Build the two lists, sharing a couple of nodes.
+ DoubleNode Ns[10];
+ int Order1[] = {0, 1, 2, 3, 4, 7, 9};
+ int Order2[] = {2, 5, 6, 7, 8, 4, 9, 1};
+ for (int I : Order1)
+ L1.push_back(Ns[I]);
+ for (int I : Order2)
+ L2.push_back(Ns[I]);
+
+ // Check that each list is correct.
+ EXPECT_EQ(sizeof(Order1) / sizeof(int), L1.size());
+ auto I1 = L1.begin();
+ for (int I : Order1) {
+ EXPECT_EQ(Ns[I].getIterator1(), I1);
+ EXPECT_EQ(&Ns[I], &*I1++);
+ }
+ EXPECT_EQ(L1.end(), I1);
+
+ EXPECT_EQ(sizeof(Order2) / sizeof(int), L2.size());
+ auto I2 = L2.begin();
+ for (int I : Order2) {
+ EXPECT_EQ(Ns[I].getIterator2(), I2);
+ EXPECT_EQ(&Ns[I], &*I2++);
+ }
+ EXPECT_EQ(L2.end(), I2);
+}
+
} // end namespace
More information about the llvm-commits
mailing list