mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
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>). llvm-svn: 281167
This commit is contained in:
parent
ceb721fec8
commit
2a55cf5af8
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -20,11 +20,21 @@ namespace llvm {
|
||||
|
||||
namespace ilist_detail {
|
||||
|
||||
template <class NodeTy> struct ConstCorrectNodeType {
|
||||
typedef 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 NodeTy> struct ConstCorrectNodeType<const NodeTy> {
|
||||
typedef const ilist_node<NodeTy> type;
|
||||
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> : ilist_detail::NodeAccess {
|
||||
} // 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<NodeTy, !IsReverse>(*NodePtr);
|
||||
return ilist_iterator<NodeTy, !IsReverse>();
|
||||
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<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_type;
|
||||
/// 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;
|
||||
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(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;
|
||||
}
|
||||
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
|
||||
|
||||
|
@ -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); }
|
||||
|
||||
using ilist_node_base::isKnownSentinel;
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
|
||||
/// 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;
|
||||
|
||||
|
@ -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
|
||||
|
128
include/llvm/ADT/ilist_node_options.h
Normal file
128
include/llvm/ADT/ilist_node_options.h
Normal file
@ -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
|
@ -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<T> &RHS, Compare comp) {
|
||||
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.
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,7 @@ set(ADTSources
|
||||
IListBaseTest.cpp
|
||||
IListIteratorTest.cpp
|
||||
IListNodeBaseTest.cpp
|
||||
IListNodeTest.cpp
|
||||
IListSentinelTest.cpp
|
||||
IListTest.cpp
|
||||
ImmutableMapTest.cpp
|
||||
|
@ -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, removeRangeImplAllButSentinel) {
|
||||
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]
|
||||
|
@ -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());
|
||||
A.initializeSentinel();
|
||||
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
EXPECT_TRUE(A.isKnownSentinel());
|
||||
#else
|
||||
EXPECT_FALSE(A.isKnownSentinel());
|
||||
#endif
|
||||
A.initializeSentinel();
|
||||
EXPECT_FALSE(A.isKnownSentinel());
|
||||
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
|
||||
|
70
unittests/ADT/IListNodeTest.cpp
Normal file
70
unittests/ADT/IListNodeTest.cpp
Normal file
@ -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
|
@ -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::NodeAccess {
|
||||
};
|
||||
|
||||
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, DefaultConstructor) {
|
||||
#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, NormalNodeIsNotKnownSentinel) {
|
||||
EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
|
||||
EXPECT_EQ(nullptr, LocalAccess::getNext(N));
|
||||
EXPECT_FALSE(N.isKnownSentinel());
|
||||
|
||||
TrackingNode TN;
|
||||
EXPECT_FALSE(TN.isSentinel());
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user