ADT: Move ilist_node_access to ilist_detail::NodeAccess...

... and make a few ilist-internal API changes, in preparation for
changing how ilist_node is templated.  The only effect for ilist users
should be changing the friend target from llvm::ilist_node_access to
llvm::ilist_detail::NodeAccess (which is only necessary when they
inherit privately from ilist_node).
- Split out SpecificNodeAccess, which has overloads of getNodePtr and
  getValuePtr that are untemplated.
- Use more typedefs to prevent more changes later.
- Force inheritance to use *NodeAccess (to emphasize that ilist *users*
  shouldn't be doing this).

There should be no functionality change here.

llvm-svn: 281142
This commit is contained in:
Duncan P. N. Exon Smith 2016-09-10 16:55:06 +00:00
parent 41aceac37f
commit 34c4d2abfd
5 changed files with 60 additions and 29 deletions

View File

@ -27,27 +27,28 @@ template <class NodeTy> struct ConstCorrectNodeType<const NodeTy> {
typedef const ilist_node<NodeTy> type;
};
template <bool IsReverse = false> struct IteratorHelper {
template <class T> static void increment(T *&I) {
I = ilist_node_access::getNext(*I);
}
template <class T> static void decrement(T *&I) {
I = ilist_node_access::getPrev(*I);
}
template <bool IsReverse> struct IteratorHelper;
template <> struct IteratorHelper<false> : ilist_detail::NodeAccess {
typedef ilist_detail::NodeAccess Access;
template <class T> static void increment(T *&I) { I = Access::getNext(*I); }
template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); }
};
template <> struct IteratorHelper<true> {
template <class T> static void increment(T *&I) {
IteratorHelper<false>::decrement(I);
}
template <class T> static void decrement(T *&I) {
IteratorHelper<false>::increment(I);
}
template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
typedef ilist_detail::NodeAccess Access;
template <class T> static void increment(T *&I) { I = Access::getPrev(*I); }
template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
};
} // end namespace ilist_detail
/// Iterator for intrusive lists based on ilist_node.
template <typename NodeTy, bool IsReverse> class ilist_iterator {
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;
public:
typedef NodeTy value_type;
typedef value_type *pointer;
@ -69,10 +70,8 @@ public:
/// Create from an ilist_node.
explicit ilist_iterator(node_reference N) : NodePtr(&N) {}
explicit ilist_iterator(pointer NP)
: NodePtr(ilist_node_access::getNodePtr(NP)) {}
explicit ilist_iterator(reference NR)
: NodePtr(ilist_node_access::getNodePtr(&NR)) {}
explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {}
explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {}
ilist_iterator() : NodePtr(nullptr) {}
// This is templated so that we can allow constructing a const iterator from
@ -108,7 +107,7 @@ public:
// Accessors...
reference operator*() const {
assert(!NodePtr->isKnownSentinel());
return *ilist_node_access::getValuePtr(NodePtr);
return *Access::getValuePtr(NodePtr);
}
pointer operator->() const { return &operator*(); }

View File

@ -19,17 +19,20 @@
namespace llvm {
namespace ilist_detail {
struct NodeAccess;
} // end namespace ilist_detail
template<typename NodeTy>
struct ilist_traits;
struct ilist_node_access;
template <typename NodeTy, bool IsReverse = false> class ilist_iterator;
template <typename NodeTy> class ilist_sentinel;
/// Templated wrapper class.
template <typename NodeTy> class ilist_node : ilist_node_base {
friend class ilist_base;
friend struct ilist_node_access;
friend struct ilist_detail::NodeAccess;
friend struct ilist_traits<NodeTy>;
friend class ilist_iterator<NodeTy, false>;
friend class ilist_iterator<NodeTy, true>;
@ -65,13 +68,15 @@ public:
using ilist_node_base::isKnownSentinel;
};
namespace ilist_detail {
/// An access class for ilist_node private API.
///
/// This gives access to the private parts of ilist nodes. Nodes for an ilist
/// should friend this class if they inherit privately from ilist_node.
///
/// Using this class outside of the ilist implementation is unsupported.
struct ilist_node_access {
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) {
return N;
@ -99,6 +104,27 @@ struct ilist_node_access {
}
};
template <class T> struct SpecificNodeAccess : NodeAccess {
protected:
typedef T *pointer;
typedef const T *const_pointer;
typedef ilist_node<T> node_type;
static node_type *getNodePtr(pointer N) {
return NodeAccess::getNodePtr<T>(N);
}
static const ilist_node<T> *getNodePtr(const_pointer N) {
return NodeAccess::getNodePtr<T>(N);
}
static pointer getValuePtr(node_type *N) {
return NodeAccess::getValuePtr<T>(N);
}
static const_pointer getValuePtr(const node_type *N) {
return NodeAccess::getValuePtr<T>(N);
}
};
} // end namespace ilist_detail
template <typename NodeTy> class ilist_sentinel : public ilist_node<NodeTy> {
public:
ilist_sentinel() {

View File

@ -46,7 +46,8 @@ 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_node_access {
template <typename T>
class simple_ilist : ilist_base, ilist_detail::SpecificNodeAccess<T> {
typedef ilist_base list_base_type;
ilist_sentinel<T> Sentinel;

View File

@ -16,10 +16,15 @@ namespace {
class Node : public ilist_node<Node> {};
struct LocalAccess : ilist_detail::NodeAccess {
using NodeAccess::getPrev;
using NodeAccess::getNext;
};
TEST(IListSentinelTest, DefaultConstructor) {
ilist_sentinel<Node> S;
EXPECT_EQ(&S, ilist_node_access::getPrev(S));
EXPECT_EQ(&S, ilist_node_access::getNext(S));
EXPECT_EQ(&S, LocalAccess::getPrev(S));
EXPECT_EQ(&S, LocalAccess::getNext(S));
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
EXPECT_TRUE(S.isKnownSentinel());
#else
@ -29,8 +34,8 @@ TEST(IListSentinelTest, DefaultConstructor) {
TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) {
Node N;
EXPECT_EQ(nullptr, ilist_node_access::getPrev(N));
EXPECT_EQ(nullptr, ilist_node_access::getNext(N));
EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
EXPECT_EQ(nullptr, LocalAccess::getNext(N));
EXPECT_FALSE(N.isKnownSentinel());
}

View File

@ -218,7 +218,7 @@ TEST(IListTest, addNodeToList) {
}
struct PrivateNode : private ilist_node<PrivateNode> {
friend struct llvm::ilist_node_access;
friend struct llvm::ilist_detail::NodeAccess;
int Value = 0;