return bOk;
}
- /// Ensures that the \p key exists in the map
+ /// Updates the node
/**
The operation performs inserting or changing data with lock-free manner.
- If the \p key not found in the map, then the new item created from \p key
- is inserted into the map (note that in this case the \p key_type should be
- constructible from type \p K).
+ If \p key is not found in the map, then \p key is inserted iff \p bAllowInsert is \p true.
Otherwise, the functor \p func is called with item found.
- The functor \p Func may be a function with signature:
- \code
- void func( bool bNew, value_type& item );
- \endcode
- or a functor:
+
+ The functor signature is:
\code
struct my_functor {
void operator()( bool bNew, value_type& item );
};
\endcode
-
with arguments:
- \p bNew - \p true if the item has been inserted, \p false otherwise
- - \p item - item of the list
-
- The functor may change any fields of the \p item.second that is \p mapped_type.
+ - \p item - item of the map
Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
\p second is true if new item has been added or \p false if the item with \p key
- already is in the list.
+ already is in the map.
*/
template <typename K, typename Func>
- std::pair<bool, bool> ensure( K const& key, Func func )
+ std::pair<bool, bool> update( K const& key, Func func, bool bAllowInsert = true )
{
std::pair<bool, bool> result;
bool bResize;
scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
pBucket = base_class::bucket( nHash );
- result = pBucket->ensure( key, func );
+ result = pBucket->update( key, func, bAllowInsert );
bResize = result.first && result.second && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
}
base_class::resize();
return result;
}
+ //@cond
+ template <typename K, typename Func>
+ CDS_DEPRECATED("ensure() is deprecated, use update() instead")
+ std::pair<bool, bool> ensure( K const& key, Func func )
+ {
+ return update( key, func, true );
+ }
/// Delete \p key from the map
/** \anchor cds_nonintrusive_StripedMap_erase
[&f]( value_type& pair, K const& ) mutable { f(pair); } );
}
- /// Find the key \p key
- /** \anchor cds_nonintrusive_StripedMap_find_val
-
+ /// Checks whether the map contains \p key
+ /**
The function searches the item with key equal to \p key
and returns \p true if it is found, and \p false otherwise.
*/
template <typename K>
+ bool contains( K const& key )
+ {
+ return base_class::contains( key );
+ }
+ //@cond
+ template <typename K>
+ CDS_DEPRECATED("use contains()")
bool find( K const& key )
{
- return base_class::find( key );
+ return contains( key );
}
+ //@endcond
- /// Find the key \p val using \p pred predicate
+ /// Checks whether the set contains \p key using \p pred predicate for searching
/**
- The function is an analog of \ref cds_nonintrusive_StripedMap_find_val "find(K const&)"
- but \p pred is used for key comparing
- \p Less has the interface like \p std::less.
- \p pred must imply the same element order as the comparator used for building the set.
+ The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p Less must imply the same element order as the comparator used for building the set.
@note This function is enabled if the compiler supports C++11
default template arguments for function template <b>and</b> the underlying container
- supports \p %find_with feature.
+ supports \p %contains() feature.
*/
template <typename K, typename Less
,typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
- bool find_with( K const& key, Less pred )
+ bool contains( K const& key, Less pred )
{
CDS_UNUSED( pred );
- return base_class::find_with( key, cds::details::predicate_wrapper< value_type, Less, key_accessor >() );
+ return base_class::contains( key, cds::details::predicate_wrapper< value_type, Less, key_accessor >() );
+ }
+ //@cond
+ template <typename K, typename Less
+ ,typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
+ CDS_DEPRECATED("use contains()")
+ bool find_with( K const& key, Less pred )
+ {
+ return contains( key, pred );
}
+ //@endcond
/// Clears the map
void clear()
}
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( const Q& key, Func func )
+ std::pair<bool, bool> update( const Q& key, Func func, bool bAllowInsert )
{
iterator it = std::lower_bound( m_List.begin(), m_List.end(), key, find_predicate() );
if ( it == m_List.end() || key_comparator()( key, it->first ) != 0 ) {
// insert new
+ if ( !bAllowInsert )
+ return std::make_pair( false, false );
+
value_type newItem( key, mapped_type() );
it = m_List.insert( it, newItem );
func( true, *it );
}
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( const Q& key, Func func )
+ std::pair<bool, bool> update( const Q& key, Func func, bool bAllowInsert )
{
std::pair< iterator, bool > pos = find_prev_item( key );
if ( !pos.second ) {
// insert new
+ if ( !bAllowInsert )
+ return std::make_pair( false, false );
+
value_type newItem( key, mapped_type() );
pos.first = m_List.insert_after( pos.first, newItem );
func( true, *pos.first );
}
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( const Q& key, Func func )
+ std::pair<bool, bool> update( const Q& key, Func func, bool bAllowInsert )
{
- std::pair<iterator, bool> res = m_Map.insert( value_type( key, mapped_type() ) );
- func( res.second, const_cast<value_type&>(*res.first));
- return std::make_pair( true, res.second );
+ if ( bAllowInsert ) {
+ std::pair<iterator, bool> res = m_Map.insert( value_type( key, mapped_type() ) );
+ func( res.second, const_cast<value_type&>(*res.first));
+ return std::make_pair( true, res.second );
+ }
+ else {
+ auto it = m_Map.find(key_type( key ));
+ if ( it == end() )
+ return std::make_pair( false, false );
+ func( false, *it );
+ return std::make_pair( true, false );
+ }
}
template <typename Q, typename Func>
}
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( const Q& key, Func func )
+ std::pair<bool, bool> update( const Q& key, Func func, bool bAllowInsert )
{
iterator it = std::lower_bound( m_List.begin(), m_List.end(), key, find_predicate() );
if ( it == m_List.end() || key_comparator()( key, it->first ) != 0 ) {
// insert new
+ if ( !bAllowInsert )
+ return std::make_pair( false, false );
+
value_type newItem( key, mapped_type() );
it = m_List.insert( it, newItem );
func( true, *it );
}
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( const Q& key, Func func )
+ std::pair<bool, bool> update( const Q& key, Func func, bool bAllowInsert )
{
- std::pair<iterator, bool> res = m_Map.insert( value_type( key, mapped_type() ));
- func( res.second, *res.first );
- return std::make_pair( true, res.second );
+ if ( bAllowInsert ) {
+ std::pair<iterator, bool> res = m_Map.insert( value_type( key, mapped_type() ));
+ func( res.second, *res.first );
+ return std::make_pair( true, res.second );
+ }
+ else {
+ auto it = m_Map.find(key_type( key ));
+ if ( it == end() )
+ return std::make_pair( false, false );
+ func( false, *it );
+ return std::make_pair( true, false );
+ }
}
template <typename Q, typename Func>
variadic template and move semantics
<hr>
- <b>Ensures that the \p item exists in the container</b>
- \code template <typename Q, typename Func> std::pair<bool, bool> ensure( const Q& val, Func func ) \endcode
+ <b>Updates \p item</b>
+ \code template <typename Q, typename Func> std::pair<bool, bool> update( const Q& val, Func func, bool bAllowInsert ) \endcode
The operation performs inserting or changing data.
If the \p val key not found in the container, then the new item created from \p val
- is inserted. Otherwise, the functor \p func is called with the item found.
+ is inserted iff \p bAllowInsert is \p true. Otherwise, the functor \p func is called with the item found.
The \p Func functor has interface:
\code
void func( bool bNew, value_type& item, const Q& val );
where arguments are:
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - container's item
- - \p val - argument \p val passed into the \p ensure function
+ - \p val - argument \p val passed into the \p update() function
The functor can change non-key fields of the \p item.
}
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( const Q& val, Func func )
+ std::pair<bool, bool> update( const Q& key, Func func, bool bAllowInsert )
{
- std::pair<iterator, bool> res = m_Map.insert( value_type( val, mapped_type() ));
- func( res.second, *res.first );
- return std::make_pair( true, res.second );
+ if ( bAllowInsert ) {
+ std::pair<iterator, bool> res = m_Map.insert( value_type( key, mapped_type() ));
+ func( res.second, *res.first );
+ return std::make_pair( true, res.second );
+ }
+ else {
+ auto it = m_Map.find(key_type( key ));
+ if ( it == end() )
+ return std::make_pair( false, false );
+ func( false, *it );
+ return std::make_pair( true, false );
+ }
}
template <typename Q, typename Func>
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_cuckoo.cpp" />\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_ellentree.cpp" />\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_michael.cpp" />\r
- <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_refinable.cpp" />\r
+ <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_multilevelhashmap.cpp" />\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_skip.cpp" />\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_split.cpp" />\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_striped.cpp" />\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_michael.cpp">\r
<Filter>map_insdel_func</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_refinable.cpp">\r
- <Filter>map_insdel_func</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_skip.cpp">\r
<Filter>map_insdel_func</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_std.cpp">\r
<Filter>map_insdel_int</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_multilevelhashmap.cpp">\r
+ <Filter>map_insdel_func</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Filter Include="map_insdel_func">\r
tests/unit/map2/map_insfind_int_refinable.cpp \
tests/unit/map2/map_insfind_int_std.cpp \
tests/unit/map2/map_insdel_func.cpp \
+ tests/unit/map2/map_insdel_func_bronsonavltree.cpp \
+ tests/unit/map2/map_insdel_func_cuckoo.cpp \
+ tests/unit/map2/map_insdel_func_ellentree.cpp \
tests/unit/map2/map_insdel_func_michael.cpp \
- tests/unit/map2/map_insdel_func_split.cpp \
+ tests/unit/map2/map_insdel_func_multilevelhashmap.cpp \
tests/unit/map2/map_insdel_func_skip.cpp \
- tests/unit/map2/map_insdel_func_ellentree.cpp \
- tests/unit/map2/map_insdel_func_bronsonavltree.cpp \
+ tests/unit/map2/map_insdel_func_split.cpp \
tests/unit/map2/map_insdel_func_striped.cpp \
- tests/unit/map2/map_insdel_func_refinable.cpp \
- tests/unit/map2/map_insdel_func_cuckoo.cpp \
tests/unit/map2/map_insdel_int.cpp \
tests/unit/map2/map_insdel_int_bronsonavltree.cpp \
tests/unit/map2/map_insdel_int_cuckoo.cpp \
MultiLevelMapHeadBits=8\r
MultiLevelMapArrayBits=4\r
\r
-\r
[Map_InsDel_func]\r
InsertThreadCount=4\r
DeleteThreadCount=4\r
-EnsureThreadCount=4\r
+UpdateThreadCount=4\r
ThreadPassCount=8\r
MapSize=5000\r
MaxLoadFactor=4\r
PrintGCStateFlag=1\r
+# *** Cuckoo map properties\r
+CuckooInitialSize=256\r
+CuckooProbesetSize=8\r
+# 0 - use default\r
+CuckooProbesetThreshold=0 \r
+# *** MultiLevelHashMap properties\r
+MultiLevelMapHeadBits=8\r
+MultiLevelMapArrayBits=4\r
\r
[Map_InsDel_Item_int]\r
ThreadCount=4\r
MultiLevelMapHeadBits=8\r
MultiLevelMapArrayBits=4\r
\r
-\r
[Map_InsDel_func]\r
InsertThreadCount=4\r
DeleteThreadCount=4\r
-EnsureThreadCount=4\r
+UpdateThreadCount=4\r
ThreadPassCount=4\r
MapSize=100000\r
MaxLoadFactor=4\r
PrintGCStateFlag=1\r
+# *** Cuckoo map properties\r
+CuckooInitialSize=1024\r
+CuckooProbesetSize=16\r
+# 0 - use default\r
+CuckooProbesetThreshold=0 \r
+# *** MultiLevelHashMap properties\r
+MultiLevelMapHeadBits=8\r
+MultiLevelMapArrayBits=4\r
\r
[Map_InsDel_Item_int]\r
ThreadCount=8\r
[Map_InsDel_func]\r
InsertThreadCount=4\r
DeleteThreadCount=4\r
-EnsureThreadCount=4\r
+UpdateThreadCount=4\r
ThreadPassCount=2\r
MapSize=1000000\r
MaxLoadFactor=4\r
PrintGCStateFlag=1\r
+# *** Cuckoo map properties\r
+CuckooInitialSize=1024\r
+CuckooProbesetSize=16\r
+# 0 - use default\r
+CuckooProbesetThreshold=0 \r
+# *** MultiLevelHashMap properties\r
+MultiLevelMapHeadBits=10\r
+MultiLevelMapArrayBits=4\r
\r
[Map_InsDel_Item_int]\r
ThreadCount=8\r
map_insfind_int_refinable.cpp
map_insfind_int_std.cpp
map_insdel_func.cpp
+ map_insdel_func_bronsonavltree.cpp
+ map_insdel_func_cuckoo.cpp
+ map_insdel_func_ellentree.cpp
map_insdel_func_michael.cpp
- map_insdel_func_split.cpp
+ map_insdel_func_multilevelhashmap.cpp
map_insdel_func_skip.cpp
- map_insdel_func_ellentree.cpp
- map_insdel_func_bronsonavltree.cpp
+ map_insdel_func_split.cpp
map_insdel_func_striped.cpp
- map_insdel_func_refinable.cpp
- map_insdel_func_cuckoo.cpp
map_insdel_int.cpp
map_insdel_int_bronsonavltree.cpp
map_insdel_int_cuckoo.cpp
namespace map2 {
CPPUNIT_TEST_SUITE_REGISTRATION( Map_InsDel_func );
- static const size_t def_nMapSize = 1000000;
- static const size_t def_nInsertThreadCount = 4;
- static const size_t def_nDeleteThreadCount = 4;
- static const size_t def_nEnsureThreadCount = 4;
- static const size_t def_nThreadPassCount = 4;
- static const size_t def_nMaxLoadFactor = 8;
-
- size_t Map_InsDel_func::c_nMapSize = def_nMapSize ; // map size
- size_t Map_InsDel_func::c_nInsertThreadCount = def_nInsertThreadCount; // count of insertion thread
- size_t Map_InsDel_func::c_nDeleteThreadCount = def_nDeleteThreadCount; // count of deletion thread
- size_t Map_InsDel_func::c_nEnsureThreadCount = def_nEnsureThreadCount; // count of ensure thread
- size_t Map_InsDel_func::c_nThreadPassCount = def_nThreadPassCount; // pass count for each thread
- size_t Map_InsDel_func::c_nMaxLoadFactor = def_nMaxLoadFactor; // maximum load factor
- bool Map_InsDel_func::c_bPrintGCState = true;
-
void Map_InsDel_func::setUpParams( const CppUnitMini::TestCfg& cfg )
{
- c_nInsertThreadCount = cfg.getULong("InsertThreadCount", def_nInsertThreadCount );
- c_nDeleteThreadCount = cfg.getULong("DeleteThreadCount", def_nDeleteThreadCount );
- c_nEnsureThreadCount = cfg.getULong("EnsureThreadCount", def_nEnsureThreadCount );
- c_nThreadPassCount = cfg.getULong("ThreadPassCount", def_nThreadPassCount );
- c_nMapSize = cfg.getULong("MapSize", def_nMapSize );
- c_nMaxLoadFactor = cfg.getULong("MaxLoadFactor", def_nMaxLoadFactor );
+ c_nInsertThreadCount = cfg.getULong("InsertThreadCount", static_cast<unsigned long>(c_nInsertThreadCount));
+ c_nDeleteThreadCount = cfg.getULong("DeleteThreadCount", static_cast<unsigned long>(c_nDeleteThreadCount));
+ c_nUpdateThreadCount = cfg.getULong("UpdateThreadCount", static_cast<unsigned long>(c_nUpdateThreadCount));
+ c_nThreadPassCount = cfg.getULong("ThreadPassCount", static_cast<unsigned long>(c_nThreadPassCount));
+ c_nMapSize = cfg.getULong("MapSize", static_cast<unsigned long>(c_nMapSize));
+ c_nMaxLoadFactor = cfg.getULong("MaxLoadFactor", static_cast<unsigned long>(c_nMaxLoadFactor));
c_bPrintGCState = cfg.getBool("PrintGCStateFlag", true );
- }
- void Map_InsDel_func::myRun(const char *in_name, bool invert /*= false*/)
- {
- setUpParams( m_Cfg.get( "Map_InsDel_func" ));
+ c_nCuckooInitialSize = cfg.getULong("CuckooInitialSize", static_cast<unsigned long>(c_nCuckooInitialSize) );
+ c_nCuckooProbesetSize = cfg.getULong("CuckooProbesetSize", static_cast<unsigned long>(c_nCuckooProbesetSize) );
+ c_nCuckooProbesetThreshold = cfg.getULong("CuckooProbesetThreshold", static_cast<unsigned long>(c_nCuckooProbesetThreshold) );
- run_MichaelMap(in_name, invert);
- run_SplitList(in_name, invert);
- run_SkipListMap(in_name, invert);
- run_EllenBinTreeMap(in_name, invert);
- run_BronsonAVLTreeMap(in_name, invert);
- run_StripedMap(in_name, invert);
- run_RefinableMap(in_name, invert);
- run_CuckooMap(in_name, invert);
+ c_nMultiLevelMap_HeadBits = cfg.getULong("MultiLevelMapHeadBits", static_cast<unsigned long>(c_nMultiLevelMap_HeadBits) );
+ c_nMultiLevelMap_ArrayBits = cfg.getULong("MultiLevelMapArrayBits", static_cast<unsigned long>(c_nMultiLevelMap_ArrayBits) );
- endTestCase();
}
} // namespace map2
namespace map2 {
-# define TEST_MAP(IMPL, C, X) void C::X() { test<map_type<IMPL, key_type, value_type>::X >() ; }
-# define TEST_MAP_EXTRACT(IMPL, C, X) TEST_MAP(IMPL, C, X)
-# define TEST_MAP_NOLF(IMPL, C, X) void C::X() { test_nolf<map_type<IMPL, key_type, value_type>::X >() ; }
-# define TEST_MAP_NOLF_EXTRACT(IMPL, C, X) TEST_MAP_NOLF(IMPL, C, X)
+# define TEST_CASE(TAG, X) void X();
+
+//# define TEST_MAP(IMPL, C, X) void C::X() { test<map_type<IMPL, key_type, value_type>::X >() ; }
+//# define TEST_MAP_EXTRACT(IMPL, C, X) TEST_MAP(IMPL, C, X)
+//# define TEST_MAP_NOLF(IMPL, C, X) void C::X() { test_nolf<map_type<IMPL, key_type, value_type>::X >() ; }
+//# define TEST_MAP_NOLF_EXTRACT(IMPL, C, X) TEST_MAP_NOLF(IMPL, C, X)
class Map_InsDel_func: public CppUnitMini::TestCase
{
- static size_t c_nMapSize; // map size
- static size_t c_nInsertThreadCount; // count of insertion thread
- static size_t c_nDeleteThreadCount; // count of deletion thread
- static size_t c_nEnsureThreadCount; // count of ensure thread
- static size_t c_nThreadPassCount; // pass count for each thread
- static size_t c_nMaxLoadFactor; // maximum load factor
- static bool c_bPrintGCState;
+ public:
+ size_t c_nMapSize = 1000000; // map size
+ size_t c_nInsertThreadCount = 4; // count of insertion thread
+ size_t c_nDeleteThreadCount = 4; // count of deletion thread
+ size_t c_nUpdateThreadCount = 4; // count of updating thread
+ size_t c_nThreadPassCount = 4; // pass count for each thread
+ size_t c_nMaxLoadFactor = 8; // maximum load factor
+ bool c_bPrintGCState = true;
+
+ size_t c_nCuckooInitialSize = 1024;// initial size for CuckooMap
+ size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
+ size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
+
+ size_t c_nMultiLevelMap_HeadBits = 10;
+ size_t c_nMultiLevelMap_ArrayBits = 4;
+ size_t c_nLoadFactor; // current load factor
+
+ private:
typedef size_t key_type;
struct value_type {
size_t nKey;
size_t nData;
- atomics::atomic<size_t> nEnsureCall;
+ atomics::atomic<size_t> nUpdateCall;
atomics::atomic<bool> bInitialized;
cds::OS::ThreadId threadId ; // insert thread id
value_type()
: nKey(0)
, nData(0)
- , nEnsureCall(0)
+ , nUpdateCall(0)
, bInitialized( false )
, threadId( cds::OS::get_current_thread_id() )
{}
value_type( value_type const& s )
: nKey(s.nKey)
, nData(s.nData)
- , nEnsureCall(s.nEnsureCall.load(atomics::memory_order_relaxed))
+ , nUpdateCall(s.nUpdateCall.load(atomics::memory_order_relaxed))
, bInitialized( s.bInitialized.load(atomics::memory_order_relaxed) )
, threadId( cds::OS::get_current_thread_id() )
{}
{
nKey = v.nKey;
nData = v.nData;
- nEnsureCall.store( v.nEnsureCall.load(atomics::memory_order_relaxed), atomics::memory_order_relaxed );
+ nUpdateCall.store( v.nUpdateCall.load(atomics::memory_order_relaxed), atomics::memory_order_relaxed );
bInitialized.store(v.bInitialized.load(atomics::memory_order_relaxed), atomics::memory_order_relaxed);
return *this;
// func is passed by reference
insert_functor func;
key_array const& arr = getTest().m_arrValues;
+ size_t const nPassCount = getTest().c_nThreadPassCount;
if ( m_nThreadNo & 1 ) {
- for ( size_t nPass = 0; nPass < c_nThreadPassCount; ++nPass ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
for ( key_array::const_iterator it = arr.begin(), itEnd = arr.end(); it != itEnd; ++it ) {
if ( rMap.insert_with( *it, std::ref(func) ) )
++m_nInsertSuccess;
}
}
else {
- for ( size_t nPass = 0; nPass < c_nThreadPassCount; ++nPass ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
for ( key_array::const_reverse_iterator it = arr.rbegin(), itEnd = arr.rend(); it != itEnd; ++it ) {
if ( rMap.insert_with( *it, std::ref(func) ) )
++m_nInsertSuccess;
};
template <class Map>
- class Ensurer: public CppUnitMini::TestThread
+ class Updater: public CppUnitMini::TestThread
{
Map& m_Map;
- virtual Ensurer * clone()
+ virtual Updater * clone()
{
- return new Ensurer( *this );
+ return new Updater( *this );
}
- struct ensure_functor {
+ struct update_functor {
size_t nCreated;
size_t nModified;
- ensure_functor()
+ update_functor()
: nCreated(0)
, nModified(0)
{}
v.bInitialized.store( true, atomics::memory_order_relaxed);
}
else {
- v.nEnsureCall.fetch_add( 1, atomics::memory_order_relaxed );
+ v.nUpdateCall.fetch_add( 1, atomics::memory_order_relaxed );
++nModified;
}
}
{
operator()( bNew, val.first, val.second );
}
+
+ // For MultiLevelHashMap
+ template <typename Val>
+ void operator()( Val& cur, Val * old )
+ {
+ operator()( old != nullptr, cur.first, cur.second );
+ }
+
private:
- ensure_functor(const ensure_functor& );
+ update_functor(const update_functor& ) = delete;
};
public:
- size_t m_nEnsureFailed;
- size_t m_nEnsureCreated;
- size_t m_nEnsureExisted;
+ size_t m_nUpdateFailed;
+ size_t m_nUpdateCreated;
+ size_t m_nUpdateExisted;
size_t m_nFunctorCreated;
size_t m_nFunctorModified;
public:
- Ensurer( CppUnitMini::ThreadPool& pool, Map& rMap )
+ Updater( CppUnitMini::ThreadPool& pool, Map& rMap )
: CppUnitMini::TestThread( pool )
, m_Map( rMap )
{}
- Ensurer( Ensurer& src )
+ Updater( Updater& src )
: CppUnitMini::TestThread( src )
, m_Map( src.m_Map )
{}
{
Map& rMap = m_Map;
- m_nEnsureCreated =
- m_nEnsureExisted =
- m_nEnsureFailed = 0;
+ m_nUpdateCreated =
+ m_nUpdateExisted =
+ m_nUpdateFailed = 0;
- ensure_functor func;
+ update_functor func;
key_array const& arr = getTest().m_arrValues;
+ size_t const nPassCount = getTest().c_nThreadPassCount;
if ( m_nThreadNo & 1 ) {
- for ( size_t nPass = 0; nPass < c_nThreadPassCount; ++nPass ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
for ( key_array::const_iterator it = arr.begin(), itEnd = arr.end(); it != itEnd; ++it ) {
//for ( size_t nItem = 0; nItem < c_nMapSize; ++nItem ) {
- std::pair<bool, bool> ret = rMap.ensure( *it, std::ref( func ) );
+ std::pair<bool, bool> ret = rMap.update( *it, std::ref( func ) );
if ( ret.first ) {
if ( ret.second )
- ++m_nEnsureCreated;
+ ++m_nUpdateCreated;
else
- ++m_nEnsureExisted;
+ ++m_nUpdateExisted;
}
else
- ++m_nEnsureFailed;
+ ++m_nUpdateFailed;
}
}
}
else {
- for ( size_t nPass = 0; nPass < c_nThreadPassCount; ++nPass ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
for ( key_array::const_reverse_iterator it = arr.rbegin(), itEnd = arr.rend(); it != itEnd; ++it ) {
- std::pair<bool, bool> ret = rMap.ensure( *it, std::ref( func ) );
+ std::pair<bool, bool> ret = rMap.update( *it, std::ref( func ) );
if ( ret.first ) {
if ( ret.second )
- ++m_nEnsureCreated;
+ ++m_nUpdateCreated;
else
- ++m_nEnsureExisted;
+ ++m_nUpdateExisted;
}
else
- ++m_nEnsureFailed;
+ ++m_nUpdateFailed;
}
}
}
erase_functor func;
key_array const& arr = getTest().m_arrValues;
+ size_t const nPassCount = getTest().c_nThreadPassCount;
if ( m_nThreadNo & 1 ) {
- for ( size_t nPass = 0; nPass < c_nThreadPassCount; ++nPass ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
for ( key_array::const_iterator it = arr.begin(), itEnd = arr.end(); it != itEnd; ++it ) {
func.m_cnt.nKeyExpected = *it;
if ( rMap.erase( *it, std::ref(func) ))
}
}
else {
- for ( size_t nPass = 0; nPass < c_nThreadPassCount; ++nPass ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
for ( key_array::const_reverse_iterator it = arr.rbegin(), itEnd = arr.rend(); it != itEnd; ++it ) {
func.m_cnt.nKeyExpected = *it;
if ( rMap.erase( *it, std::ref(func) ))
{
typedef Inserter<Map> InserterThread;
typedef Deleter<Map> DeleterThread;
- typedef Ensurer<Map> EnsurerThread;
+ typedef Updater<Map> UpdaterThread;
cds::OS::Timer timer;
m_arrValues.clear();
CppUnitMini::ThreadPool pool( *this );
pool.add( new InserterThread( pool, testMap ), c_nInsertThreadCount );
pool.add( new DeleterThread( pool, testMap ), c_nDeleteThreadCount );
- pool.add( new EnsurerThread( pool, testMap ), c_nEnsureThreadCount );
+ pool.add( new UpdaterThread( pool, testMap ), c_nUpdateThreadCount );
pool.run();
CPPUNIT_MSG( " Duration=" << pool.avgDuration() );
size_t nDeleteFailed = 0;
size_t nDelValueSuccess = 0;
size_t nDelValueFailed = 0;
- size_t nEnsureFailed = 0;
- size_t nEnsureCreated = 0;
- size_t nEnsureModified = 0;
+ size_t nUpdateFailed = 0;
+ size_t nUpdateCreated = 0;
+ size_t nUpdateModified = 0;
size_t nEnsFuncCreated = 0;
size_t nEnsFuncModified = 0;
size_t nTestFunctorRef = 0;
nDelValueFailed += p->m_nValueFailed;
}
else {
- EnsurerThread * pEns = static_cast<EnsurerThread *>( *it );
- nEnsureCreated += pEns->m_nEnsureCreated;
- nEnsureModified += pEns->m_nEnsureExisted;
- nEnsureFailed += pEns->m_nEnsureFailed;
+ UpdaterThread * pEns = static_cast<UpdaterThread *>( *it );
+ nUpdateCreated += pEns->m_nUpdateCreated;
+ nUpdateModified += pEns->m_nUpdateExisted;
+ nUpdateFailed += pEns->m_nUpdateFailed;
nEnsFuncCreated += pEns->m_nFunctorCreated;
nEnsFuncModified += pEns->m_nFunctorModified;
}
<< " Del succ=" << nDeleteSuccess << "\n"
<< " : Ins fail=" << nInsertFailed
<< " Del fail=" << nDeleteFailed << "\n"
- << " : Ensure succ=" << (nEnsureCreated + nEnsureModified) << " fail=" << nEnsureFailed
- << " create=" << nEnsureCreated << " modify=" << nEnsureModified << "\n"
+ << " : Update succ=" << (nUpdateCreated + nUpdateModified) << " fail=" << nUpdateFailed
+ << " create=" << nUpdateCreated << " modify=" << nUpdateModified << "\n"
<< " Map size=" << testMap.size()
);
CPPUNIT_CHECK_EX( nDelValueFailed == 0, "Functor del failed=" << nDelValueFailed );
CPPUNIT_CHECK_EX( nDelValueSuccess == nDeleteSuccess, "Delete success=" << nDeleteSuccess << " functor=" << nDelValueSuccess );
- CPPUNIT_CHECK( nEnsureFailed == 0 );
+ CPPUNIT_CHECK( nUpdateFailed == 0 );
- CPPUNIT_CHECK_EX( nEnsureCreated == nEnsFuncCreated, "Ensure created=" << nEnsureCreated << " functor=" << nEnsFuncCreated );
- CPPUNIT_CHECK_EX( nEnsureModified == nEnsFuncModified, "Ensure modified=" << nEnsureModified << " functor=" << nEnsFuncModified );
+ CPPUNIT_CHECK_EX( nUpdateCreated == nEnsFuncCreated, "Update created=" << nUpdateCreated << " functor=" << nEnsFuncCreated );
+ CPPUNIT_CHECK_EX( nUpdateModified == nEnsFuncModified, "Update modified=" << nUpdateModified << " functor=" << nEnsFuncModified );
// nTestFunctorRef is call count of insert functor
CPPUNIT_CHECK_EX( nTestFunctorRef == nInsertSuccess, "nInsertSuccess=" << nInsertSuccess << " functor nTestFunctorRef=" << nTestFunctorRef );
}
template <class Map>
- void test()
+ void run_test()
{
CPPUNIT_MSG( "Thread count: insert=" << c_nInsertThreadCount
<< " delete=" << c_nDeleteThreadCount
- << " ensure=" << c_nEnsureThreadCount
+ << " update=" << c_nUpdateThreadCount
<< " pass count=" << c_nThreadPassCount
<< " map size=" << c_nMapSize
);
- for ( size_t nLoadFactor = 1; nLoadFactor <= c_nMaxLoadFactor; nLoadFactor *= 2 ) {
- CPPUNIT_MSG( "Load factor=" << nLoadFactor );
- Map testMap( c_nMapSize, nLoadFactor );
+ if ( Map::c_bLoadFactorDepended ) {
+ for ( size_t c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
+ CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
+ Map testMap( *this );
+ do_test( testMap );
+ if ( c_bPrintGCState )
+ print_gc_state();
+ }
+ }
+ else {
+ Map testMap( *this );
do_test( testMap );
if ( c_bPrintGCState )
print_gc_state();
}
-
- }
-
- template <class Map>
- void test_nolf()
- {
- CPPUNIT_MSG( "Thread count: insert=" << c_nInsertThreadCount
- << " delete=" << c_nDeleteThreadCount
- << " ensure=" << c_nEnsureThreadCount
- << " pass count=" << c_nThreadPassCount
- << " map size=" << c_nMapSize
- );
-
- Map testMap;
- do_test( testMap );
- if ( c_bPrintGCState )
- print_gc_state();
}
typedef CppUnitMini::TestCase Base;
void setUpParams( const CppUnitMini::TestCfg& cfg );
- void run_MichaelMap(const char *in_name, bool invert = false);
- void run_SplitList(const char *in_name, bool invert = false);
- void run_StripedMap(const char *in_name, bool invert = false);
- void run_RefinableMap(const char *in_name, bool invert = false);
- void run_CuckooMap(const char *in_name, bool invert = false);
- void run_SkipListMap(const char *in_name, bool invert = false);
- void run_EllenBinTreeMap(const char *in_name, bool invert = false);
- void run_BronsonAVLTreeMap(const char *in_name, bool invert = false);
-
- virtual void myRun(const char *in_name, bool invert = false);
-
# include "map2/map_defs.h"
- CDSUNIT_DECLARE_MichaelMap
- CDSUNIT_DECLARE_SplitList
- CDSUNIT_DECLARE_SkipListMap
- CDSUNIT_DECLARE_EllenBinTreeMap
- CDSUNIT_DECLARE_BronsonAVLTreeMap
- CDSUNIT_DECLARE_StripedMap
- CDSUNIT_DECLARE_RefinableMap
- CDSUNIT_DECLARE_CuckooMap
+ CDSUNIT_DECLARE_MichaelMap
+ CDSUNIT_DECLARE_SplitList
+ CDSUNIT_DECLARE_SkipListMap
+ CDSUNIT_DECLARE_EllenBinTreeMap
+ CDSUNIT_DECLARE_BronsonAVLTreeMap
+ CDSUNIT_DECLARE_MultiLevelHashMap
+ CDSUNIT_DECLARE_StripedMap
+ CDSUNIT_DECLARE_RefinableMap
+ CDSUNIT_DECLARE_CuckooMap
+
+ CPPUNIT_TEST_SUITE(Map_InsDel_func)
+ CDSUNIT_TEST_MichaelMap
+ CDSUNIT_TEST_SplitList
+ CDSUNIT_TEST_SkipListMap
+ CDSUNIT_TEST_EllenBinTreeMap
+ CDSUNIT_TEST_BronsonAVLTreeMap
+ CDSUNIT_TEST_MultiLevelHashMap
+ CDSUNIT_TEST_CuckooMap
+ CDSUNIT_TEST_StripedMap
+ CDSUNIT_TEST_RefinableMap
+ CPPUNIT_TEST_SUITE_END();
+
};
} // namespace map2
#include "map2/map_insdel_func.h"
#include "map2/map_type_bronson_avltree.h"
-namespace map2 {
- CDSUNIT_DEFINE_BronsonAVLTreeMap( cc::bronson_avltree::implementation_tag, Map_InsDel_func)
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_BronsonAVLTreeMap )
- CDSUNIT_TEST_BronsonAVLTreeMap
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_BronsonAVLTreeMap
} // namespace map2
#include "map2/map_insdel_func.h"
#include "map2/map_type_cuckoo.h"
-namespace map2 {
- CDSUNIT_DEFINE_CuckooMap(cds::intrusive::cuckoo::implementation_tag, Map_InsDel_func)
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_CuckooMap )
- CDSUNIT_TEST_CuckooMap
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_CuckooMap
} // namespace map2
#include "map2/map_insdel_func.h"
#include "map2/map_type_ellen_bintree.h"
-namespace map2 {
- CDSUNIT_DEFINE_EllenBinTreeMap( cc::ellen_bintree::implementation_tag, Map_InsDel_func)
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_EllenBinTreeMap )
- CDSUNIT_TEST_EllenBinTreeMap
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_EllenBinTreeMap
} // namespace map2
-
#include "map2/map_insdel_func.h"
#include "map2/map_type_michael.h"
-namespace map2 {
- CDSUNIT_DEFINE_MichaelMap( cc::michael_map::implementation_tag, Map_InsDel_func )
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_MichaelMap )
- CDSUNIT_TEST_MichaelMap
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_MichaelMap
} // namespace map2
--- /dev/null
+//$$CDS-header$$
+
+#include "map2/map_insdel_func.h"
+#include "map2/map_type_multilevel_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+ CDSUNIT_DECLARE_MultiLevelHashMap
+} // namespace map2
+++ /dev/null
-//$$CDS-header$$
-
-#include "map2/map_insdel_func.h"
-#include "map2/map_type_striped.h"
-
-namespace map2 {
- CDSUNIT_DEFINE_RefinableMap(cc::striped_set::implementation_tag, Map_InsDel_func)
-
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_RefinableMap )
- CDSUNIT_TEST_RefinableMap
- CPPUNIT_TEST_SUITE_END_PART()
-} // namespace map2
#include "map2/map_insdel_func.h"
#include "map2/map_type_skip_list.h"
-namespace map2 {
- CDSUNIT_DEFINE_SkipListMap( cc::skip_list::implementation_tag, Map_InsDel_func)
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_SkipListMap )
- CDSUNIT_TEST_SkipListMap
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_SkipListMap
} // namespace map2
-
#include "map2/map_insdel_func.h"
#include "map2/map_type_split_list.h"
-namespace map2 {
- CDSUNIT_DEFINE_SplitList( cc::split_list::implementation_tag, Map_InsDel_func )
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_SplitList )
- CDSUNIT_TEST_SplitList
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_SplitList
} // namespace map2
-
#include "map2/map_insdel_func.h"
#include "map2/map_type_striped.h"
-namespace map2 {
- CDSUNIT_DEFINE_StripedMap(cc::striped_set::implementation_tag, Map_InsDel_func)
+#undef TEST_CASE
+#define TEST_CASE(TAG, X) void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
- CPPUNIT_TEST_SUITE_PART( Map_InsDel_func, run_StripedMap )
- CDSUNIT_TEST_StripedMap
- CPPUNIT_TEST_SUITE_END_PART()
+namespace map2 {
+ CDSUNIT_DECLARE_StripedMap
+ CDSUNIT_DECLARE_RefinableMap
} // namespace map2