#ifndef __CDS_INTRUSIVE_OPTIMISTIC_QUEUE_H
#define __CDS_INTRUSIVE_OPTIMISTIC_QUEUE_H
-#include <cds/intrusive/base.h>
+#include <type_traits>
+#include <functional> // ref
+#include <cds/intrusive/details/base.h>
#include <cds/cxx11_atomic.h>
#include <cds/gc/default_gc.h>
#include <cds/gc/hrc/gc_fwd.h>
-#include <cds/intrusive/queue_stat.h>
-#include <cds/ref.h>
-
-#include <cds/details/std/type_traits.h>
+#include <cds/intrusive/details/queue_stat.h>
namespace cds { namespace intrusive {
atomic_node_ptr m_pNext ; ///< Pointer to next node
CDS_CONSTEXPR node() CDS_NOEXCEPT
- : m_pPrev( null_ptr<node *>() )
- , m_pNext( null_ptr<node *>() )
+ : m_pPrev( nullptr )
+ , m_pNext( nullptr )
{}
};
//@endcond
//@cond
- template < typename HookType, CDS_DECL_OPTIONS2>
+ template < typename HookType, typename... Options>
struct hook
{
- typedef typename opt::make_options< default_hook, CDS_OPTIONS2>::type options;
+ typedef typename opt::make_options< default_hook, Options...>::type options;
typedef typename options::gc gc;
typedef typename options::tag tag;
typedef node<gc, tag> node_type;
- opt::gc - garbage collector used.
- opt::tag - tag
*/
- template < CDS_DECL_OPTIONS2 >
- struct base_hook: public hook< opt::base_hook_tag, CDS_OPTIONS2 >
+ template < typename... Options >
+ struct base_hook: public hook< opt::base_hook_tag, Options... >
{};
/// Member hook
- opt::gc - garbage collector used.
- opt::tag - tag
*/
- template < size_t MemberOffset, CDS_DECL_OPTIONS2 >
- struct member_hook: public hook< opt::member_hook_tag, CDS_OPTIONS2 >
+ template < size_t MemberOffset, typename... Options >
+ struct member_hook: public hook< opt::member_hook_tag, Options... >
{
//@cond
static const size_t c_nMemberOffset = MemberOffset;
- opt::gc - garbage collector used.
- opt::tag - tag
*/
- template <typename NodeTraits, CDS_DECL_OPTIONS2 >
- struct traits_hook: public hook< opt::traits_hook_tag, CDS_OPTIONS2 >
+ template <typename NodeTraits, typename... Options >
+ struct traits_hook: public hook< opt::traits_hook_tag, Options... >
{
//@cond
typedef NodeTraits node_traits;
typedef Node node_type;
//@endcond
- /// Checks if the link fields of node \p pNode is NULL
+ /// Checks if the link fields of node \p pNode is \p nullptr
/**
- An asserting is generated if \p pNode link fields is not NULL
+ An asserting is generated if \p pNode link fields is not \p nullptr
*/
static void is_empty( const node_type * pNode )
{
- assert( pNode->m_pNext.load(CDS_ATOMIC::memory_order_relaxed) == null_ptr<node_type *>() );
- assert( pNode->m_pPrev.load(CDS_ATOMIC::memory_order_relaxed) == null_ptr<node_type *>() );
+ assert( pNode->m_pNext.load( atomics::memory_order_relaxed ) == nullptr );
+ assert( pNode->m_pPrev.load( atomics::memory_order_relaxed ) == nullptr );
}
};
\endcode
*/
- template <typename GC, typename T, CDS_DECL_OPTIONS9>
+ template <typename GC, typename T, typename... Options>
class OptimisticQueue
{
//@cond
public:
//@cond
typedef typename opt::make_options<
- typename cds::opt::find_type_traits< default_options, CDS_OPTIONS9 >::type
- ,CDS_OPTIONS9
+ typename cds::opt::find_type_traits< default_options, Options... >::type
+ ,Options...
>::type options;
typedef typename std::conditional<
#endif
/// Rebind template arguments
- template <typename GC2, typename T2, CDS_DECL_OTHER_OPTIONS9>
+ template <typename GC2, typename T2, typename... Options2>
struct rebind {
- typedef OptimisticQueue< GC2, T2, CDS_OTHER_OPTIONS9> other ; ///< Rebinding result
+ typedef OptimisticQueue< GC2, T2, Options2...> other ; ///< Rebinding result
};
protected:
{
void operator ()( value_type * p )
{
- assert( p != null_ptr<value_type *>());
+ assert( p != nullptr );
OptimisticQueue::clear_links( node_traits::to_node_ptr(*p) );
disposer()( p );
//@cond
static void clear_links( node_type * pNode )
{
- pNode->m_pNext.store( null_ptr<node_type *>(), memory_model::memory_order_release );
- pNode->m_pPrev.store( null_ptr<node_type *>(), memory_model::memory_order_release );
+ pNode->m_pNext.store( nullptr, memory_model::memory_order_release );
+ pNode->m_pPrev.store( nullptr, memory_model::memory_order_release );
}
struct dequeue_result {
while ( true ) { // Try till success or empty
pHead = res.guards.protect( 0, m_pHead, node_to_value() );
pTail = res.guards.protect( 1, m_pTail, node_to_value() );
- assert( pHead != null_ptr<node_type *>() );
+ assert( pHead != nullptr );
pFirstNodePrev = res.guards.protect( 2, pHead->m_pPrev, node_to_value() );
if ( pHead == m_pHead.load(memory_model::memory_order_relaxed)) {
if ( pTail != pHead ) {
- if ( pFirstNodePrev == null_ptr<node_type *>()
+ if ( pFirstNodePrev == nullptr
|| pFirstNodePrev->m_pNext.load(memory_model::memory_order_relaxed) != pHead )
{
fix_list( pTail, pHead );
continue;
}
- if ( m_pHead.compare_exchange_weak( pHead, pFirstNodePrev, memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed )) {
+ if ( m_pHead.compare_exchange_weak( pHead, pFirstNodePrev, memory_model::memory_order_release, atomics::memory_order_relaxed )) {
// dequeue success
break;
}
void dispose_node( node_type * p )
{
- assert( p != null_ptr<node_type *>());
+ assert( p != nullptr );
if ( p != &m_Dummy ) {
gc::template retire<internal_disposer>( node_traits::to_value_ptr(p) );
public:
/// Constructor creates empty queue
OptimisticQueue()
- : m_pTail( null_ptr<node_type *>() )
- , m_pHead( null_ptr<node_type *>() )
+ : m_pTail( nullptr )
+ , m_pHead( nullptr )
{
// GC and node_type::gc must be the same
static_assert(( std::is_same<gc, typename node_type::gc>::value ), "GC and node_type::gc must be the same");
{
clear();
node_type * pHead = m_pHead.load(memory_model::memory_order_relaxed);
- CDS_DEBUG_DO( node_type * pTail = m_pTail.load(memory_model::memory_order_relaxed); )
- CDS_DEBUG_DO( assert( pHead == pTail ); )
- assert( pHead != null_ptr<node_type *>() );
+ CDS_DEBUG_ONLY( node_type * pTail = m_pTail.load(memory_model::memory_order_relaxed); )
+ CDS_DEBUG_ONLY( assert( pHead == pTail ); )
+ assert( pHead != nullptr );
- m_pHead.store( null_ptr<node_type *>(), memory_model::memory_order_relaxed );
- m_pTail.store( null_ptr<node_type *>(), memory_model::memory_order_relaxed );
+ m_pHead.store( nullptr, memory_model::memory_order_relaxed );
+ m_pTail.store( nullptr, memory_model::memory_order_relaxed );
dispose_node( pHead );
}
node_type * pTail = guards.protect( 0, m_pTail, node_to_value() ) ; // Read the tail
while( true ) {
pNew->m_pNext.store( pTail, memory_model::memory_order_release );
- if ( m_pTail.compare_exchange_strong( pTail, pNew, memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed ) ) { // Try to CAS the tail
+ if ( m_pTail.compare_exchange_strong( pTail, pNew, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) { // Try to CAS the tail
pTail->m_pPrev.store( pNew, memory_model::memory_order_release ) ; // Success, write prev
++m_ItemCounter;
m_Stat.onEnqueue();
/// Dequeues a value from the queue
/** @anchor cds_intrusive_OptimisticQueue_dequeue
- If the queue is empty the function returns \a NULL
+ If the queue is empty the function returns \p nullptr
\par Warning
The queue algorithm has following feature: when \p dequeue is called,
return node_traits::to_value_ptr( *res.pNext );
}
- return null_ptr<value_type *>();
+ return nullptr;
}
/// Synonym for @ref cds_intrusive_OptimisticQueue_enqueue "enqueue"
/// Clear the stack
/**
- The function repeatedly calls \ref dequeue until it returns NULL.
+ The function repeatedly calls \ref dequeue until it returns \p nullptr.
The disposer defined in template \p Options is called for each item
that can be safely disposed.
*/
void clear()
{
value_type * pv;
- while ( (pv = dequeue()) != null_ptr<value_type *>() );
+ while ( (pv = dequeue()) != nullptr );
}
/// Returns queue's item count