Add LockFreeStack iterators

This commit is contained in:
Vinnie Falco
2013-09-14 16:04:28 -07:00
parent d94e4c2491
commit 277e32bb1e

View File

@@ -23,6 +23,94 @@
struct LockFreeStackDefaultTag; struct LockFreeStackDefaultTag;
/*============================================================================*/ /*============================================================================*/
template <class Container, bool IsConst>
class LockFreeStackIterator
: public std::iterator <
std::forward_iterator_tag,
typename Container::value_type,
typename Container::difference_type,
typename mpl::IfCond <IsConst,
typename Container::const_pointer,
typename Container::pointer>::type,
typename mpl::IfCond <IsConst,
typename Container::const_reference,
typename Container::reference>::type>
{
protected:
typedef typename Container::Node Node;
typedef typename mpl::IfCond <IsConst, Node const*, Node*>::type NodePtr;
public:
typedef typename Container::value_type value_type;
typedef typename mpl::IfCond <IsConst,
typename Container::const_pointer,
typename Container::pointer>::type pointer;
typedef typename mpl::IfCond <IsConst,
typename Container::const_reference,
typename Container::reference>::type reference;
LockFreeStackIterator ()
: m_node ()
{
}
LockFreeStackIterator (NodePtr node)
: m_node (node)
{
}
template <bool OtherIsConst>
explicit LockFreeStackIterator (LockFreeStackIterator <Container, OtherIsConst> const& other)
: m_node (other.m_node)
{
}
LockFreeStackIterator& operator= (NodePtr node)
{
m_node = node;
return static_cast <LockFreeStackIterator&> (*this);
}
LockFreeStackIterator& operator++ ()
{
m_node = m_node->m_next;
return static_cast <LockFreeStackIterator&> (*this);
}
LockFreeStackIterator operator++ (int)
{
LockFreeStackIterator result (*this);
m_node = m_node->m_next;
return result;
}
template <bool OtherIsConst>
bool operator== (LockFreeStackIterator <Container, OtherIsConst> const& other)
{
return m_node == other.m_node;
}
template <bool OtherIsConst>
bool operator!= (LockFreeStackIterator <Container, OtherIsConst> const& other)
{
return m_node != other.m_node;
}
reference operator* () const
{
return *this->operator-> ();
}
pointer operator-> () const
{
return static_cast <pointer> (m_node);
}
private:
NodePtr m_node;
};
/** /**
Multiple Producer, Multiple Consumer (MPMC) intrusive stack. Multiple Producer, Multiple Consumer (MPMC) intrusive stack.
@@ -38,7 +126,7 @@ struct LockFreeStackDefaultTag;
@ingroup beast_core intrusive @ingroup beast_core intrusive
*/ */
template <class Element, class Tag = LockFreeStackDefaultTag> template <class Element, class Tag = void>
class LockFreeStack : public Uncopyable class LockFreeStack : public Uncopyable
{ {
public: public:
@@ -56,15 +144,31 @@ public:
private: private:
friend class LockFreeStack; friend class LockFreeStack;
template <class Container, bool IsConst>
friend class LockFreeStackIterator;
// VFALCO TODO Use regular Atomic<> // VFALCO TODO Use regular Atomic<>
AtomicPointer <Node> m_next; AtomicPointer <Node> m_next;
}; };
public: public:
LockFreeStack () : m_head (0) typedef Element value_type;
typedef Element* pointer;
typedef Element& reference;
typedef Element const* const_pointer;
typedef Element const& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef LockFreeStackIterator <
LockFreeStack <Element, Tag>, false> iterator;
typedef LockFreeStackIterator <
LockFreeStack <Element, Tag>, true> const_iterator;
LockFreeStack () : m_head (nullptr)
{ {
} }
#if 0
/** Create a LockFreeStack from another stack. /** Create a LockFreeStack from another stack.
The contents of the other stack are atomically acquired. The contents of the other stack are atomically acquired.
@@ -84,6 +188,17 @@ public:
m_head = head; m_head = head;
} }
#endif
/** Return the number of elements in the stack.
Thread safety:
Safe to call from any thread but the value may be inaccurate.
*/
size_type size () const
{
return m_size.get ();
}
/** Push a node onto the stack. /** Push a node onto the stack.
@@ -108,6 +223,8 @@ public:
} }
while (!m_head.compareAndSet (node, head)); while (!m_head.compareAndSet (node, head));
++m_size;
return first; return first;
} }
@@ -134,6 +251,8 @@ public:
} }
while (!m_head.compareAndSet (head, node)); while (!m_head.compareAndSet (head, node));
--m_size;
return node ? static_cast <Element*> (node) : nullptr; return node ? static_cast <Element*> (node) : nullptr;
} }
@@ -149,17 +268,43 @@ public:
Node* temp = other.m_head.get (); Node* temp = other.m_head.get ();
other.m_head.set (m_head.get ()); other.m_head.set (m_head.get ());
m_head.set (temp); m_head.set (temp);
std::swap (m_size.value, other.m_size.value);
}
iterator begin ()
{
return iterator (m_head.get ());
}
iterator end ()
{
return iterator ();
}
const_iterator begin () const
{
return const_iterator (m_head.get ());
}
const_iterator end () const
{
return const_iterator ();
}
const_iterator cbegin () const
{
return const_iterator (m_head.get ());
}
const_iterator cend () const
{
return const_iterator ();
} }
private: private:
Atomic <size_type> m_size;
AtomicPointer <Node> m_head; AtomicPointer <Node> m_head;
}; };
/*============================================================================*/
/** Default tag for LockFreeStack
@ingroup beast_core intrusive
*/
struct LockFreeStackDefaultTag { };
#endif #endif