//$$CDS-header$$
-#ifndef __CDS_INTRUSIVE_SPLIT_LIST_NOGC_H
-#define __CDS_INTRUSIVE_SPLIT_LIST_NOGC_H
+#ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_NOGC_H
+#define CDSLIB_INTRUSIVE_SPLIT_LIST_NOGC_H
+
+#include <limits>
#include <cds/intrusive/details/split_list_base.h>
#include <cds/gc/nogc.h>
/// Hash functor for \p value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
+ //@cond
+ typedef cds::intrusive::split_list::implementation_tag implementation_tag;
+ //@endcond
+
protected:
//@cond
typedef split_list::details::rebind_list_traits<OrderedList, traits> wrapped_ordered_list;
ordered_list_wrapper m_List; ///< Ordered list containing split-list items
bucket_table m_Buckets; ///< bucket table
atomics::atomic<size_t> m_nBucketCountLog2; ///< log2( current bucket count )
+ atomics::atomic<size_t> m_nMaxItemCount; ///< number of items container can hold, before we have to resize
item_counter m_ItemCounter; ///< Item counter
hash m_HashFunctor; ///< Hash functor
stat m_Stat; ///< Internal statistics
size_t bucket_no( size_t nHash ) const
{
- return nHash & ( (1 << m_nBucketCountLog2.load(atomics::memory_order_relaxed)) - 1 );
+ return nHash & ( (1 << m_nBucketCountLog2.load(memory_model::memory_order_relaxed)) - 1 );
}
static size_t parent_bucket( size_t nBucket )
static_assert( std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
// atomicity::empty_item_counter is not allowed as a item counter
- static_assert( !std::is_same<item_counter, cds::atomicity::empty_item_counter>::value,
+ static_assert( !std::is_same<item_counter, cds::atomicity::empty_item_counter>::value,
"cds::atomicity::empty_item_counter is not allowed as a item counter");
// Initialize bucket 0
m_Buckets.bucket( 0, pNode );
}
- void inc_item_count()
+ static size_t max_item_count( size_t nBucketCount, size_t nLoadFactor )
{
- size_t sz = m_nBucketCountLog2.load(atomics::memory_order_relaxed);
- if ( ( ++m_ItemCounter >> sz ) > m_Buckets.load_factor() && ((size_t)(1 << sz )) < m_Buckets.capacity() )
- {
- m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, atomics::memory_order_seq_cst, atomics::memory_order_relaxed );
+ return nBucketCount * nLoadFactor;
+ }
+
+ void inc_item_count()
+ {
+ size_t nMaxCount = m_nMaxItemCount.load(memory_model::memory_order_relaxed);
+ if ( ++m_ItemCounter <= nMaxCount )
+ return;
+
+ size_t sz = m_nBucketCountLog2.load(memory_model::memory_order_relaxed);
+ const size_t nBucketCount = static_cast<size_t>(1) << sz;
+ if ( nBucketCount < m_Buckets.capacity() ) {
+ // we may grow the bucket table
+ const size_t nLoadFactor = m_Buckets.load_factor();
+ if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
+ return; // someone already have updated m_nBucketCountLog2, so stop here
+
+ const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
+ : std::numeric_limits<size_t>::max();
+ m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed,
+ atomics::memory_order_relaxed );
+ m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, atomics::memory_order_relaxed );
}
}
*/
SplitListSet()
: m_nBucketCountLog2(1)
+ , m_nMaxItemCount( max_item_count(2, m_Buckets.load_factor()) )
{
init();
}
)
: m_Buckets( nItemCount, nLoadFactor )
, m_nBucketCountLog2(1)
+ , m_nMaxItemCount( max_item_count(2, m_Buckets.load_factor()) )
{
init();
}
{
return find_( key, key_comparator(), f );
}
+ //@cond
+ template <typename Q, typename Func>
+ bool find( Q const& key, Func f )
+ {
+ return find_( key, key_comparator(), f );
+ }
+ //@endcond
/// Finds the key \p key with \p pred predicate for comparing
/**
template <typename Q, typename Less, typename Func>
bool find_with( Q& key, Less pred, Func f )
{
+ CDS_UNUSED( pred );
return find_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>(), f );
}
+ //@cond
+ template <typename Q, typename Less, typename Func>
+ bool find_with( Q const& key, Less pred, Func f )
+ {
+ CDS_UNUSED( pred );
+ return find_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>(), f );
+ }
+ //@endcond
/// Checks if the set is empty
/**
return m_ItemCounter;
}
+ /// Returns internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
template <bool IsConst>
{
return const_iterator( m_List.begin(), m_List.end() );
}
- const_iterator cbegin()
+ const_iterator cbegin() const
{
return const_iterator( m_List.cbegin(), m_List.cend() );
}
{
return const_iterator( m_List.end(), m_List.end() );
}
- const_iterator cend()
+ const_iterator cend() const
{
return const_iterator( m_List.cend(), m_List.cend() );
}
template <typename Q, typename Less >
iterator find_with_( Q& val, Less pred )
{
+ CDS_UNUSED( pred );
size_t nHash = hash_value( val );
split_list::details::search_value_type<Q const> sv( val, split_list::regular_hash( nHash ));
dummy_node_type * pHead = get_bucket( nHash );
}} // namespace cds::intrusive
-#endif // #ifndef __CDS_INTRUSIVE_SPLIT_LIST_NOGC_H
+#endif // #ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_NOGC_H