// Thinning publication list
publication_record * pPrev = nullptr;
for ( publication_record * p = m_pHead; p; ) {
- if ( p->nState.load( memory_model::memory_order_acquire ) == active
- && p->nAge.load( memory_model::memory_order_acquire ) + m_nCompactFactor < nCurAge )
+ if ( p->nState.load( memory_model::memory_order_acquire ) == active
+ && p->nAge.load( memory_model::memory_order_acquire ) + m_nCompactFactor < nCurAge )
{
if ( pPrev ) {
publication_record * pNext = p->pNext.load( memory_model::memory_order_acquire );
#include <cds/algo/base.h>
-namespace cds { namespace algo {
+namespace cds { namespace algo {
/// Cuts a bit sequence from fixed-size bit-string
/**
// C++11 thread_local keyword
#if !(CDS_OS_TYPE == CDS_OS_OSX && CDS_COMPILER_VERSION < 30600)
- // OS X error?
+ // OS X error?
// See http://stackoverflow.com/questions/23791060/c-thread-local-storage-clang-503-0-40-mac-osx
// http://stackoverflow.com/questions/28094794/why-does-apple-clang-disallow-c11-thread-local-when-official-clang-supports
// clang 3.6 ok?..
//@cond
#ifdef CDS_THREAD_SANITIZER_ENABLED
-# define CDS_TSAN_ANNOTATE_HAPPENS_BEFORE(addr) AnnotateHappensBefore(__FILE__, __LINE__, reinterpret_cast<void*>(addr))\r
-# define CDS_TSAN_ANNOTATE_HAPPENS_AFTER(addr) AnnotateHappensAfter(__FILE__, __LINE__, reinterpret_cast<void*>(addr))\r
-\r
-# define CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN AnnotateIgnoreReadsBegin(__FILE__, __LINE__)\r
-# define CDS_TSAN_ANNOTATE_IGNORE_READS_END AnnotateIgnoreReadsEnd(__FILE__, __LINE__)\r
-# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN AnnotateIgnoreWritesBegin(__FILE__, __LINE__)\r
-# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_END AnnotateIgnoreWritesEnd(__FILE__, __LINE__)\r
-# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN \\r
- CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN; \\r
- CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN\r
-# define CDS_TSAN_ANNOTATE_IGNORE_RW_END \\r
- CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;\\r
- CDS_TSAN_ANNOTATE_IGNORE_READS_END\r
-# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz ) AnnotateNewMemory( (char *) __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )\r
-\r
- // provided by TSan\r
- extern "C" {\r
- void AnnotateHappensBefore(const char *f, int l, void *addr);\r
- void AnnotateHappensAfter(const char *f, int l, void *addr);\r
-\r
- void AnnotateIgnoreReadsBegin(const char *f, int l);\r
- void AnnotateIgnoreReadsEnd(const char *f, int l);\r
- void AnnotateIgnoreWritesBegin(const char *f, int l);\r
- void AnnotateIgnoreWritesEnd(const char *f, int l);\r
-\r
+# define CDS_TSAN_ANNOTATE_HAPPENS_BEFORE(addr) AnnotateHappensBefore(__FILE__, __LINE__, reinterpret_cast<void*>(addr))
+# define CDS_TSAN_ANNOTATE_HAPPENS_AFTER(addr) AnnotateHappensAfter(__FILE__, __LINE__, reinterpret_cast<void*>(addr))
+
+# define CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+# define CDS_TSAN_ANNOTATE_IGNORE_READS_END AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_END AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN \
+ CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN; \
+ CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN
+# define CDS_TSAN_ANNOTATE_IGNORE_RW_END \
+ CDS_TSAN_ANNOTATE_IGNORE_WRITES_END;\
+ CDS_TSAN_ANNOTATE_IGNORE_READS_END
+# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz ) AnnotateNewMemory( (char *) __FILE__, __LINE__, reinterpret_cast<void *>(addr), sz )
+
+ // provided by TSan
+ extern "C" {
+ void AnnotateHappensBefore(const char *f, int l, void *addr);
+ void AnnotateHappensAfter(const char *f, int l, void *addr);
+
+ void AnnotateIgnoreReadsBegin(const char *f, int l);
+ void AnnotateIgnoreReadsEnd(const char *f, int l);
+ void AnnotateIgnoreWritesBegin(const char *f, int l);
+ void AnnotateIgnoreWritesEnd(const char *f, int l);
+
void AnnotateNewMemory(char *f, int l, void * mem, size_t size);
-\r
- }\r
-\r
-#else // CDS_THREAD_SANITIZER_ENABLED\r
-\r
-# define CDS_TSAN_ANNOTATE_HAPPENS_BEFORE(addr)\r
+
+ }
+
+#else // CDS_THREAD_SANITIZER_ENABLED
+
+# define CDS_TSAN_ANNOTATE_HAPPENS_BEFORE(addr)
# define CDS_TSAN_ANNOTATE_HAPPENS_AFTER(addr)
-# define CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN\r
-# define CDS_TSAN_ANNOTATE_IGNORE_READS_END\r
-# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN\r
-# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_END\r
-# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN\r
-# define CDS_TSAN_ANNOTATE_IGNORE_RW_END\r
-\r
-# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz )\r
-\r
+# define CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN
+# define CDS_TSAN_ANNOTATE_IGNORE_READS_END
+# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN
+# define CDS_TSAN_ANNOTATE_IGNORE_WRITES_END
+# define CDS_TSAN_ANNOTATE_IGNORE_RW_BEGIN
+# define CDS_TSAN_ANNOTATE_IGNORE_RW_END
+
+# define CDS_TSAN_ANNOTATE_NEW_MEMORY( addr, sz )
+
#endif
//@endcond
void onDisposeNode() { ++m_nDisposedNode; }
void onDisposeValue() { ++m_nDisposedValue; }
void onExtractValue() { ++m_nExtractedValue; }
- void onRemove(bool bSuccess)
- {
- if ( bSuccess )
- ++m_nRemoveSuccess;
- else
- ++m_nRemoveFailed;
+ void onRemove(bool bSuccess)
+ {
+ if ( bSuccess )
+ ++m_nRemoveSuccess;
+ else
+ ++m_nRemoveFailed;
}
void onExtract( bool bSuccess )
{
typename equal_to_wrapper< typename original_type_traits::equal_to >::type
>::type equal_to;
- typedef typename std::conditional<
+ typedef typename std::conditional<
original_type_traits::sort
|| !std::is_same< typename original_type_traits::compare, cds::opt::none >::value
|| !std::is_same< typename original_type_traits::less, cds::opt::none >::value,
- cds::details::compare_wrapper<
+ cds::details::compare_wrapper<
node_type,
typename opt::details::make_comparator< value_type, original_type_traits >::type,
key_field_accessor
typename equal_to_wrapper< typename original_type_traits::equal_to >::type
>::type equal_to;
- typedef typename std::conditional<
- original_type_traits::sort
+ typedef typename std::conditional<
+ original_type_traits::sort
|| !std::is_same<typename original_type_traits::compare, cds::opt::none>::value
|| !std::is_same<typename original_type_traits::less, cds::opt::none>::value,
cds::details::compare_wrapper<
/// Hash functor, default is \p std::hash
/**
\p MultiLevelHashMap may use any hash functor converting a key to
- fixed-sized bit-string, for example, <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,\r
- <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>,\r
- <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>\r
+ fixed-sized bit-string, for example, <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+ <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>,
+ <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a>.
*/
typedef opt::none hash;
@copydetails traits::node_allocator
- \p opt::compare - hash comparison functor. No default functor is provided.
If the option is not specified, the \p opt::less is used.
- - \p opt::less - specifies binary predicate used for hash comparison.
+ - \p opt::less - specifies binary predicate used for hash comparison.
@copydetails cds::container::multilevel_hashmap::traits::less
- \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
- \p opt::item_counter - the type of item counting feature.
@copydetails cds::container::multilevel_hashmap::traits::item_counter
- - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
or \p opt::v::sequential_consistent (sequentially consisnent memory model).
- \p opt::stat - internal statistics. By default, it is disabled (\p multilevel_hashmap::empty_stat).
To enable it use \p multilevel_hashmap::stat
typedef Traits original_traits;
typedef typename cds::opt::v::hash_selector< typename original_traits::hash >::type hasher;
- typedef typename std::decay<
+ typedef typename std::decay<
typename std::remove_reference<
decltype( hasher()( std::declval<key_type>()) )
>::type
//typedef typename std::result_of< hasher( std::declval<key_type>()) >::type hash_type;
static_assert( !std::is_pointer<hash_type>::value, "hash functor should return a reference to hash value" );
- struct node_type
+ struct node_type
{
std::pair< key_type const, mapped_type> m_Value;
hash_type const m_hash;
@copydetails traits::node_allocator
- \p opt::compare - hash comparison functor. No default functor is provided.
If the option is not specified, the \p opt::less is used.
- - \p opt::less - specifies binary predicate used for hash comparison.
+ - \p opt::less - specifies binary predicate used for hash comparison.
@copydetails cds::container::multilevel_hashset::traits::less
- \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
- \p opt::item_counter - the type of item counting feature.
@copydetails cds::intrusive::multilevel_hashset::traits::item_counter
- - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
or \p opt::v::sequential_consistent (sequentially consisnent memory model).
- \p opt::stat - internal statistics. By default, it is disabled (\p multilevel_hashset::empty_stat).
To enable it use \p multilevel_hashset::stat
if ( !pNode->is_valued( memory_model::memory_order_acquire ) )
return update_flags::failed;
- if ( child( pNode, left_child, memory_model::memory_order_acquire ) == nullptr
- || child( pNode, right_child, memory_model::memory_order_acquire ) == nullptr )
+ if ( child( pNode, left_child, memory_model::memory_order_acquire ) == nullptr
+ || child( pNode, right_child, memory_model::memory_order_acquire ) == nullptr )
{
// pNode can be replaced with its child
}
}
- assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
+ assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
|| child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
int h = height( pNode, memory_model::memory_order_acquire );
node_type * rebalance_to_right_locked( node_type * pParent, node_type * pNode, node_type * pLeft, int hR )
{
assert( parent( pNode, memory_model::memory_order_relaxed ) == pParent );
- assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
+ assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
|| child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
// pParent and pNode is locked yet
node_type * rebalance_to_left_locked( node_type * pParent, node_type * pNode, node_type * pRight, int hL )
{
assert( parent( pNode, memory_model::memory_order_relaxed ) == pParent );
- assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
+ assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
|| child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
// pParent and pNode is locked yet
\p %MultiLevelHashMap is a multi-level array which has an internal structure similar to a tree:
@image html multilevel_hashset.png
The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
- A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated\r
- with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.\r
- A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)\r
- of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;\r
- any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds\r
- an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark\r
- on the second-least significant bit.\r
-\r
- \p %MultiLevelHashMap multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array\r
- called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;\r
- a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.\r
- The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.\r
- We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which\r
- we need to operate; this is initially one, because of \p head.\r
-\r
- That approach to the structure of the hash map uses an extensible hashing scheme; <b> the hash value is treated as a bit\r
- string</b> and rehash incrementally.\r
-\r
- @note Two important things you should keep in mind when you're using \p %MultiLevelHashMap:\r
- - all keys is converted to fixed-size bit-string by hash functor provided. \r
- You can use variable-length keys, for example, \p std::string as a key for \p %MultiLevelHashMap,\r
- but real key in the map will be fixed-ize hash values of your keys.\r
- For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,\r
- <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a> \r
- or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which\r
- converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %MultiLevelHashMap.\r
- - \p %MultiLevelHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,\r
- have identical hash then you cannot insert both that keys in the map. \p %MultiLevelHashMap does not maintain the key,\r
- it maintains its fixed-size hash value.\r
-\r
- The map supports @ref cds_container_MultilevelHashMap_iterators "bidirectional thread-safe iterators".\r
-\r
- Template parameters:\r
- - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"\r
- - \p Key - a key type to be stored in the map\r
- - \p T - a value type to be stored in the map\r
- - \p Traits - type traits, the structure based on \p multilevel_hashmap::traits or result of \p multilevel_hashmap::make_traits metafunction.\r
-\r
+ A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
+ with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
+ A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
+ of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
+ any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
+ an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
+ on the second-least significant bit.
+
+ \p %MultiLevelHashMap multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
+ called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
+ a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
+ The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
+ We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
+ we need to operate; this is initially one, because of \p head.
+
+ That approach to the structure of the hash map uses an extensible hashing scheme; <b> the hash value is treated as a bit
+ string</b> and rehash incrementally.
+
+ @note Two important things you should keep in mind when you're using \p %MultiLevelHashMap:
+ - all keys is converted to fixed-size bit-string by hash functor provided.
+ You can use variable-length keys, for example, \p std::string as a key for \p %MultiLevelHashMap,
+ but real key in the map will be fixed-ize hash values of your keys.
+ For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+ <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+ or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+ converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %MultiLevelHashMap.
+ - \p %MultiLevelHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+ have identical hash then you cannot insert both that keys in the map. \p %MultiLevelHashMap does not maintain the key,
+ it maintains its fixed-size hash value.
+
+ The map supports @ref cds_container_MultilevelHashMap_iterators "bidirectional thread-safe iterators".
+
+ Template parameters:
+ - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
+ - \p Key - a key type to be stored in the map
+ - \p T - a value type to be stored in the map
+ - \p Traits - type traits, the structure based on \p multilevel_hashmap::traits or result of \p multilevel_hashmap::make_traits metafunction.
+
There are several specializations of \p %MultiLevelHashMap for each \p GC. You should include:
- <tt><cds/container/multilevel_hashmap_hp.h></tt> for \p gc::HP garbage collector
- <tt><cds/container/multilevel_hashmap_dhp.h></tt> for \p gc::DHP garbage collector
- <tt><cds/container/multilevel_hashmap_rcu.h></tt> for \ref cds_intrusive_MultiLevelHashMap_rcu "RCU type". RCU specialization
has a slightly different interface.
*/
- template <
+ template <
class GC
,typename Key
,typename T
#ifdef CDS_DOXYGEN_INVOKED
- ,class Traits = multilevel_hashmap::traits
+ ,class Traits = multilevel_hashmap::traits
#else
,class Traits
#endif
std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
{
scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
- std::pair<bool, bool> result = base_class::do_update( *sp,
- [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
+ std::pair<bool, bool> result = base_class::do_update( *sp,
+ [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
bInsert );
if ( result.first )
sp.release();
//@endcond
/// Extracts the item from the map with specified \p key
- /**
+ /**
The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
unlinks it from the map, and returns a guarded pointer to the item found.
If \p key is not found the function returns an empty guarded pointer.
public:
///@name Thread-safe iterators
/** @anchor cds_container_MultilevelHashMap_iterators
- The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment.\r
- It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:\r
- Hazard Pointer embedded into the iterator object protects the node from physical reclamation.\r
-\r
- @note Since the iterator object contains hazard pointer that is a thread-local resource,\r
- the iterator should not be passed to another thread.\r
-\r
- Each iterator object supports the common interface:\r
- - dereference operators:\r
- @code\r
- value_type [const] * operator ->() noexcept\r
- value_type [const] & operator *() noexcept\r
- @endcode\r
- - pre-increment and pre-decrement. Post-operators is not supported\r
- - equality operators <tt>==</tt> and <tt>!=</tt>.\r
+ The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment.
+ It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
+ Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
+
+ @note Since the iterator object contains hazard pointer that is a thread-local resource,
+ the iterator should not be passed to another thread.
+
+ Each iterator object supports the common interface:
+ - dereference operators:
+ @code
+ value_type [const] * operator ->() noexcept
+ value_type [const] & operator *() noexcept
+ @endcode
+ - pre-increment and pre-decrement. Post-operators is not supported
+ - equality operators <tt>==</tt> and <tt>!=</tt>.
Iterators are equal iff they point to the same cell of the same array node.
- Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
+ Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
does not entail <tt> &(*it1) == &(*it2) </tt>
- - helper member function \p release() that clears internal hazard pointer.\r
+ - helper member function \p release() that clears internal hazard pointer.
After \p release() call the iterator points to \p nullptr but it still remain valid: further iterating is possible.
*/
///@{
return base_class::template init_begin<const_iterator>();
}
- /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
iterator end()
{
return base_class::template init_end<iterator>();
}
- /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
const_iterator end() const
{
return base_class::template init_end<const_iterator>();
}
- /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
const_iterator cend()
{
return base_class::template init_end<const_iterator>();
\p %MultiLevelHashSet is a multi-level array which has an internal structure similar to a tree:
@image html multilevel_hashset.png
The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
- A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated\r
- with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.\r
- A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)\r
- of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;\r
- any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds\r
- an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark\r
- on the second-least significant bit.\r
-\r
- \p %MultiLevelHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array\r
- called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;\r
- a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.\r
- The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.\r
- We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which\r
- we need to operate; this is initially one, because of \p head.\r
-\r
- That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit\r
- string</b> and rehash incrementally.\r
-\r
- @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:\r
- - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.\r
- Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,\r
- <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a> \r
- or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which\r
- converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.\r
- - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,\r
- have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,\r
- it maintains its fixed-size hash value.\r
-\r
- The set supports @ref cds_container_MultilevelHashSet_iterators "bidirectional thread-safe iterators".\r
-\r
- Template parameters:\r
- - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"\r
- - \p T - a value type to be stored in the set\r
- - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.\r
- \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor" \r
- to hash value of \p T. The set algorithm does not calculate that hash value.\r
-\r
+ A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
+ with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
+ A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
+ of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
+ any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
+ an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
+ on the second-least significant bit.
+
+ \p %MultiLevelHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
+ called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
+ a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
+ The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
+ We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
+ we need to operate; this is initially one, because of \p head.
+
+ That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit
+ string</b> and rehash incrementally.
+
+ @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:
+ - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.
+ Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+ <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+ or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+ converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.
+ - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+ have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,
+ it maintains its fixed-size hash value.
+
+ The set supports @ref cds_container_MultilevelHashSet_iterators "bidirectional thread-safe iterators".
+
+ Template parameters:
+ - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
+ - \p T - a value type to be stored in the set
+ - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.
+ \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor"
+ to hash value of \p T. The set algorithm does not calculate that hash value.
+
There are several specializations of \p %MultiLevelHashSet for each \p GC. You should include:
- <tt><cds/container/multilevel_hashset_hp.h></tt> for \p gc::HP garbage collector
- <tt><cds/container/multilevel_hashset_dhp.h></tt> for \p gc::DHP garbage collector
}
/// Deletes the item from the set
- /**
+ /**
The function searches \p hash in the set,
deletes the item found, and returns \p true.
If that item is not found the function returns \p false.
//@endcond
/// Extracts the item with specified \p hash
- /**
+ /**
The function searches \p hash in the set,
unlinks it from the set, and returns an guarded pointer to the item extracted.
If \p hash is not found the function returns an empty guarded pointer.
- The item returned is reclaimed by garbage collector \p GC
+ The item returned is reclaimed by garbage collector \p GC
when returned \ref guarded_ptr object to be destroyed or released.
@note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
public:
///@name Thread-safe iterators
/** @anchor cds_container_MultilevelHashSet_iterators
- The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.\r
- It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:\r
- Hazard Pointer embedded into the iterator object protects the node from physical reclamation.\r
-\r
- @note Since the iterator object contains hazard pointer that is a thread-local resource,\r
- the iterator should not be passed to another thread.\r
-\r
- Each iterator object supports the common interface:\r
- - dereference operators:\r
- @code\r
- value_type [const] * operator ->() noexcept\r
- value_type [const] & operator *() noexcept\r
- @endcode\r
- - pre-increment and pre-decrement. Post-operators is not supported\r
- - equality operators <tt>==</tt> and <tt>!=</tt>.\r
+ The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.
+ It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
+ Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
+
+ @note Since the iterator object contains hazard pointer that is a thread-local resource,
+ the iterator should not be passed to another thread.
+
+ Each iterator object supports the common interface:
+ - dereference operators:
+ @code
+ value_type [const] * operator ->() noexcept
+ value_type [const] & operator *() noexcept
+ @endcode
+ - pre-increment and pre-decrement. Post-operators is not supported
+ - equality operators <tt>==</tt> and <tt>!=</tt>.
Iterators are equal iff they point to the same cell of the same array node.
- Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
+ Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
does not entail <tt> &(*it1) == &(*it2) </tt>
- - helper member function \p release() that clears internal hazard pointer.\r
+ - helper member function \p release() that clears internal hazard pointer.
After \p release() call the iterator points to \p nullptr but it still remain valid: further iterating is possible.
*/
///@{
return base_class::cbegin();
}
- /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
iterator end()
{
return base_class::end();
}
- /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
const_iterator end() const
{
return base_class::end();
}
- /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
const_iterator cend()
{
return base_class::cend();
/// Returns a reverse iterator to the element following the last element of the reversed set
/**
- It corresponds to the element preceding the first element of the non-reversed container.
- This element acts as a placeholder, attempting to access it results in undefined behavior.
+ It corresponds to the element preceding the first element of the non-reversed container.
+ This element acts as a placeholder, attempting to access it results in undefined behavior.
*/
reverse_iterator rend()
{
/// Returns a const reverse iterator to the element following the last element of the reversed set
/**
- It corresponds to the element preceding the first element of the non-reversed container.
- This element acts as a placeholder, attempting to access it results in undefined behavior.
+ It corresponds to the element preceding the first element of the non-reversed container.
+ This element acts as a placeholder, attempting to access it results in undefined behavior.
*/
const_reverse_iterator rend() const
{
/// Returns a const reverse iterator to the element following the last element of the reversed set
/**
- It corresponds to the element preceding the first element of the non-reversed container.
- This element acts as a placeholder, attempting to access it results in undefined behavior.
+ It corresponds to the element preceding the first element of the non-reversed container.
+ This element acts as a placeholder, attempting to access it results in undefined behavior.
*/
const_reverse_iterator crend()
{
The operation performs inserting or changing data with lock-free manner.
If the \p val key not found in the set, then the new item created from \p val
- will be inserted into the set iff \p bInsert is \p true.
+ will be inserted into the set iff \p bInsert is \p true.
Otherwise, if \p val is found, the functor \p func will be called with the item found.
The functor \p Func signature:
{
scoped_node_ptr sp( node_allocator().New( random_level(), val ));
std::pair<bool, bool> bRes = base_class::update( *sp,
- [&func, &val](bool bNew, node_type& node, node_type&){ func( bNew, node.m_Value, val ); },
+ [&func, &val](bool bNew, node_type& node, node_type&){ func( bNew, node.m_Value, val ); },
bInsert );
if ( bRes.first && bRes.second )
sp.release();
unlinks it from the list, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
If \p key is not found the function returns an empty \p exempt_ptr.
- @note The function does NOT dispose the item found.
+ @note The function does NOT dispose the item found.
It just excludes the item from the list and returns a pointer to item found.
You shouldn't lock RCU before calling this function.
// The RCU should NOT be locked when extract() is called!
assert( !rcu::is_locked() );
-
+
// extract() call
p = theList.extract( 10 )
if ( p ) {
Otherwise, if \p key is found, the function returns an iterator that points to item found.
Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
- item found or inserted or \p end() if \p key is not found and insertion is not allowed (\p bInsert is \p false),
+ item found or inserted or \p end() if \p key is not found and insertion is not allowed (\p bInsert is \p false),
\p second is \p true if new item has been added or \p false if the item already exists.
*/
template <typename K>
/// Enqueues data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
template <typename... Args>
bool emplace( Args&&... args )
- {
+ {
#if (CDS_COMPILER == CDS_COMPILER_GCC) && (CDS_COMPILER_VERSION < 40900)
- //work around unsupported feature in g++ 4.8 for forwarding parameter packs to lambda.
- return enqueue_with ( std::bind([]( value_type& dest,Args ... args ){ new ( &dest ) value_type( std::forward<Args>(args)... );}, std::placeholders::_1 ,args...));
-#else
- return enqueue_with( [&args ...]( value_type& dest ){ new ( &dest ) value_type( std::forward<Args>(args)... ); });
-#endif
+ //work around unsupported feature in g++ 4.8 for forwarding parameter packs to lambda.
+ return enqueue_with ( std::bind([]( value_type& dest,Args ... args ){ new ( &dest ) value_type( std::forward<Args>(args)... );}, std::placeholders::_1 ,args...));
+#else
+ return enqueue_with( [&args ...]( value_type& dest ){ new ( &dest ) value_type( std::forward<Args>(args)... ); });
+#endif
}
/// Dequeues a value using a functor
The main namespace for the library is \ref cds.
To see the full list of container's class go to <a href="modules.html">modules</a> tab.
-
+
Supported processor architectures and operating systems (OS) are:
- x86 [32bit] Linux, Windows, FreeBSD, MinGW
- amd64 (x86-64) [64bit] Linux, Windows, FreeBSD, MinGW
Supported compilers:
- GCC 4.8+
- - Clang 3.3+
+ - Clang 3.3+
- MS Visual C++ 2013 Update 4 and above
- Intel C++ Compiler 15
schema used. However, any implementation supports common interface for the type of data structure.
To use any lock-free data structure, the following are needed:
- - atomic operation library conforming with C++11 memory model.
- The <b>libcds</b> can be built with \p std::atomic, \p boost::atomic or its own
+ - atomic operation library conforming with C++11 memory model.
+ The <b>libcds</b> can be built with \p std::atomic, \p boost::atomic or its own
@ref cds_cxx11_atomic "atomic implementation"
- - safe memory reclamation (SMR) or garbage collecting (GC) algorithm.
-
+ - safe memory reclamation (SMR) or garbage collecting (GC) algorithm.
+
SMR is the main part of lock-free data structs. The SMR solves the problem of safe
memory reclamation that is one of the main problem for lock-free programming.
The library contains the implementations of several light-weight \ref cds_garbage_collector "memory reclamation schemes":
}
\endcode
-
+
\par How to build
The <b>cds</b> is mostly header-only library. Only small part of library related to GC core functionality
- should be compiled.
-
+ should be compiled.
+
The test projects depends on the following static library from \p boost:
- \p boost.thread
- \p boost.date_time
pItem = m_pEpochFree[ nEpoch = current_epoch() ].load(atomics::memory_order_acquire);
if ( !pItem )
goto retry;
- if ( m_pEpochFree[nEpoch].compare_exchange_weak( pItem,
- pItem->m_pNextFree.load(atomics::memory_order_acquire),
+ if ( m_pEpochFree[nEpoch].compare_exchange_weak( pItem,
+ pItem->m_pNextFree.load(atomics::memory_order_acquire),
atomics::memory_order_acquire, atomics::memory_order_relaxed ))
- {
+ {
goto success;
}
}
goto retry;
}
// pItem is changed by compare_exchange_weak
- } while ( !m_pGlobalFreeHead.compare_exchange_weak( pItem,
- pItem->m_pNextFree.load(atomics::memory_order_acquire),
+ } while ( !m_pGlobalFreeHead.compare_exchange_weak( pItem,
+ pItem->m_pNextFree.load(atomics::memory_order_acquire),
atomics::memory_order_acquire, atomics::memory_order_relaxed ));
success:
\par Parameters
- \p nLiberateThreshold - \p scan() threshold. When count of retired pointers reaches this value,
the \p scan() member function would be called for freeing retired pointers.
- - \p nInitialThreadGuardCount - initial count of guard allocated for each thread.
+ - \p nInitialThreadGuardCount - initial count of guard allocated for each thread.
When a thread is initialized the GC allocates local guard pool for the thread from common guard pool.
By perforce the local thread's guard pool is grown automatically from common pool.
When the thread terminated its guard pool is backed to common GC's pool.
/// Terminates GC singleton
/**
The destructor destroys %HP global object. After calling of this function you may \b NOT
- use CDS data structures based on \p %cds::gc::HP.
+ use CDS data structures based on \p %cds::gc::HP.
Usually, %HP object is destroyed at the end of your \p main().
*/
~HP()
by calling \p %Initialize() function, see \ref cds_how_to_use "how to use the library".
You can call \p Initialize several times, only first call is significant others will be ignored.
- To terminate the \p CDS library correctly, each call to \p %Initialize() must be balanced
+ To terminate the \p CDS library correctly, each call to \p %Initialize() must be balanced
by a corresponding \p Terminate() call.
Note, that this function does not initialize garbage collectors. To use GC you need you should call
- GC-specific constructor function to initialize internal structures of GC.
+ GC-specific constructor function to initialize internal structures of GC.
See \p cds::gc for details.
*/
static inline void Initialize(
/// Specifies list ordering policy
/**
- If \p sort is \p true, than list maintains items in sorted order, otherwise the list is unordered.
+ If \p sort is \p true, than list maintains items in sorted order, otherwise the list is unordered.
Default is \p true.
Note that if \p sort is \p false, than lookup operations scan entire list.
*/
};
/// \p MultiLevelHashSet traits
- struct traits
+ struct traits
{
/// Mandatory functor to get hash value from data node
/**
@copydetails traits::node_allocator
- \p opt::compare - hash comparison functor. No default functor is provided.
If the option is not specified, the \p opt::less is used.
- - \p opt::less - specifies binary predicate used for hash comparison.
+ - \p opt::less - specifies binary predicate used for hash comparison.
If the option is not specified, \p memcmp() -like bit-wise hash comparator is used
because the hash value is treated as fixed-sized bit-string.
- \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
pNext = nullptr;
pCur = pos.guards.protect( position::guard_current_item, *pPrev,
- [](marked_node_ptr p) -> value_type *
+ [](marked_node_ptr p) -> value_type *
{
return node_traits::to_value_ptr( p.ptr() );
});
return false;
}
- pNext = pos.guards.protect( position::guard_next_item, pCur->m_pNext,
- [](marked_node_ptr p ) -> value_type *
+ pNext = pos.guards.protect( position::guard_next_item, pCur->m_pNext,
+ [](marked_node_ptr p ) -> value_type *
{
return node_traits::to_value_ptr( p.ptr() );
});
\p %MultiLevelHashSet is a multi-level array which has a structure similar to a tree:
@image html multilevel_hashset.png
The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
- A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated\r
- with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.\r
- A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)\r
- of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;\r
- any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds\r
- an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark\r
- on the second-least significant bit.\r
-\r
- \p %MultiLevelHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array\r
- called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;\r
- a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.\r
- The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.\r
- We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which\r
- we need to operate; this is initially one, because of \p head.\r
-\r
- That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit\r
- string</b> and rehash incrementally.\r
-\r
- @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:\r
- - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.\r
- Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,\r
- <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a> \r
- or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which\r
- converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.\r
- - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,\r
- have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,\r
- it maintains its fixed-size hash value.\r
-\r
- The set supports @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional thread-safe iterators".\r
-\r
- Template parameters:\r
- - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"\r
- - \p T - a value type to be stored in the set\r
- - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.\r
- \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor" \r
- to hash value of \p T. The set algorithm does not calculate that hash value.\r
-\r
+ A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
+ with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
+ A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
+ of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
+ any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
+ an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
+ on the second-least significant bit.
+
+ \p %MultiLevelHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
+ called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
+ a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
+ The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
+ We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
+ we need to operate; this is initially one, because of \p head.
+
+ That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit
+ string</b> and rehash incrementally.
+
+ @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:
+ - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.
+ Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+ <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+ or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+ converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.
+ - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+ have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,
+ it maintains its fixed-size hash value.
+
+ The set supports @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional thread-safe iterators".
+
+ Template parameters:
+ - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
+ - \p T - a value type to be stored in the set
+ - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.
+ \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor"
+ to hash value of \p T. The set algorithm does not calculate that hash value.
+
There are several specializations of \p %MultiLevelHashSet for each \p GC. You should include:
- <tt><cds/intrusive/multilevel_hashset_hp.h></tt> for \p gc::HP garbage collector
- <tt><cds/intrusive/multilevel_hashset_dhp.h></tt> for \p gc::DHP garbage collector
static_assert(!std::is_same< hash_accessor, cds::opt::none >::value, "hash_accessor functor must be specified" );
/// Hash type deduced from \p hash_accessor return type
- typedef typename std::decay<
+ typedef typename std::decay<
typename std::remove_reference<
decltype( hash_accessor()( std::declval<T>()) )
>::type
# ifdef CDS_DOXYGEN_INVOKED
typedef implementation_defined hash_comparator ; ///< hash compare functor based on opt::compare and opt::less option setter
# else
- typedef typename cds::opt::details::make_comparator_from<
+ typedef typename cds::opt::details::make_comparator_from<
hash_type,
traits,
multilevel_hashset::bitwise_compare< hash_type >
size_t m_idx; ///< current position in m_pNode
typename gc::Guard m_guard; ///< HP guard
MultiLevelHashSet const* m_set; ///< Hash set
-
+
public:
iterator_base() CDS_NOEXCEPT
: m_pNode( nullptr )
/// Inserts new node
/**
- The function inserts \p val in the set if it does not contain
+ The function inserts \p val in the set if it does not contain
an item with that hash.
Returns \p true if \p val is placed into the set, \p false otherwise.
}
/// Deletes the item from the set
- /**
+ /**
The function searches \p hash in the set,
unlinks the item found, and returns \p true.
If that item is not found the function returns \p false.
//@endcond
/// Extracts the item with specified \p hash
- /**
+ /**
The function searches \p hash in the set,
unlinks it from the set, and returns an guarded pointer to the item extracted.
If \p hash is not found the function returns an empty guarded pointer.
public:
///@name Thread-safe iterators
/** @anchor cds_intrusive_MultilevelHashSet_iterators
- The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.\r
- It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:\r
- Hazard Pointer embedded into the iterator object protects the node from physical reclamation.\r
-\r
- @note Since the iterator object contains hazard pointer that is a thread-local resource,\r
- the iterator should not be passed to another thread.\r
-\r
- Each iterator object supports the common interface:\r
- - dereference operators:\r
- @code\r
- value_type [const] * operator ->() noexcept\r
- value_type [const] & operator *() noexcept\r
- @endcode\r
- - pre-increment and pre-decrement. Post-operators is not supported\r
- - equality operators <tt>==</tt> and <tt>!=</tt>.\r
+ The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.
+ It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
+ Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
+
+ @note Since the iterator object contains hazard pointer that is a thread-local resource,
+ the iterator should not be passed to another thread.
+
+ Each iterator object supports the common interface:
+ - dereference operators:
+ @code
+ value_type [const] * operator ->() noexcept
+ value_type [const] & operator *() noexcept
+ @endcode
+ - pre-increment and pre-decrement. Post-operators is not supported
+ - equality operators <tt>==</tt> and <tt>!=</tt>.
Iterators are equal iff they point to the same cell of the same array node.
- Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
+ Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
- - helper member function \p release() that clears internal hazard pointer.\r
+ - helper member function \p release() that clears internal hazard pointer.
After \p release() call the iterator points to \p nullptr but it still remain valid: further iterating is possible.
*/
///@{
return const_iterator( *this, m_Head, size_t(0) - 1 );
}
- /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
iterator end()
{
return iterator( *this, m_Head, head_size(), false );
}
- /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
const_iterator end() const
{
return const_iterator( *this, m_Head, head_size(), false );
}
- /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+ /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
const_iterator cend()
{
return const_iterator( *this, m_Head, head_size(), false );
/// Returns a reverse iterator to the element following the last element of the reversed set
/**
- It corresponds to the element preceding the first element of the non-reversed container.
- This element acts as a placeholder, attempting to access it results in undefined behavior.
+ It corresponds to the element preceding the first element of the non-reversed container.
+ This element acts as a placeholder, attempting to access it results in undefined behavior.
*/
reverse_iterator rend()
{
/// Returns a const reverse iterator to the element following the last element of the reversed set
/**
- It corresponds to the element preceding the first element of the non-reversed container.
- This element acts as a placeholder, attempting to access it results in undefined behavior.
+ It corresponds to the element preceding the first element of the non-reversed container.
+ This element acts as a placeholder, attempting to access it results in undefined behavior.
*/
const_reverse_iterator rend() const
{
/// Returns a const reverse iterator to the element following the last element of the reversed set
/**
- It corresponds to the element preceding the first element of the non-reversed container.
- This element acts as a placeholder, attempting to access it results in undefined behavior.
+ It corresponds to the element preceding the first element of the non-reversed container.
+ This element acts as a placeholder, attempting to access it results in undefined behavior.
*/
const_reverse_iterator crend()
{
node_ptr cur(current.ptr());
atomic_node_ptr& slot = pParent->nodes[idxParent];
- if ( !slot.compare_exchange_strong( cur, cur | flag_array_converting, memory_model::memory_order_release, atomics::memory_order_relaxed ))
+ if ( !slot.compare_exchange_strong( cur, cur | flag_array_converting, memory_model::memory_order_release, atomics::memory_order_relaxed ))
{
m_Stat.onExpandNodeFailed();
free_array_node( pArr );
pArr->nodes[idx].store( current, memory_model::memory_order_release );
cur = cur | flag_array_converting;
- CDS_VERIFY(
+ CDS_VERIFY(
slot.compare_exchange_strong( cur, node_ptr( to_node( pArr ), flag_array_node ), memory_model::memory_order_release, atomics::memory_order_relaxed )
);
no item has been added.
Otherwise, the function inserts the pointer to \p val into the heap
and returns \p true.
-
+
The function does not make a copy of \p val.
*/
bool push( value_type& val )
if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
return; // someone already have updated m_nBucketCountLog2, so stop here
- m_nMaxItemCount.compare_exchange_strong( nMaxCount, max_item_count( nBucketCount << 1, nLoadFactor ),
+ m_nMaxItemCount.compare_exchange_strong( nMaxCount, max_item_count( nBucketCount << 1, nLoadFactor ),
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 );
}
if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
return; // someone already have updated m_nBucketCountLog2, so stop here
- m_nMaxItemCount.compare_exchange_strong( nMaxCount, max_item_count( nBucketCount << 1, nLoadFactor ),
+ m_nMaxItemCount.compare_exchange_strong( nMaxCount, max_item_count( nBucketCount << 1, nLoadFactor ),
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 );
}
if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
return; // someone already have updated m_nBucketCountLog2, so stop here
- m_nMaxItemCount.compare_exchange_strong( nMaxCount, max_item_count( nBucketCount << 1, nLoadFactor ),
+ m_nMaxItemCount.compare_exchange_strong( nMaxCount, max_item_count( nBucketCount << 1, nLoadFactor ),
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 );
}
}
while ( true ) {
- node_type * t = guard.protect( m_Top,
+ node_type * t = guard.protect( m_Top,
[]( node_type * p ) -> value_type * {
return node_traits::to_value_ptr( p );
});
if ( p ) {
if ( from_pool(p) ) {
// The queue can notify about false fullness state
- // so we push in loop
+ // so we push in loop
back_off bkoff;
while ( !m_Queue.push( *p ))
bkoff();
template <typename T, typename Traits, bool Forced = true >
- using make_comparator = make_comparator_from< T, Traits,
- typename std::conditional<
- Forced,
- make_comparator_from_less< std::less<T>>,
- opt::none
+ using make_comparator = make_comparator_from< T, Traits,
+ typename std::conditional<
+ Forced,
+ make_comparator_from_less< std::less<T>>,
+ opt::none
>::type >;
template <typename T, typename... Options>
opt::none >::type,
make_equal_to_from_less< less > >::type,
make_equal_to_from_compare< compare > >::type,
- equal_to
+ equal_to
>::type type;
};
}
sizeof(T) % nAlign == 0
\endcode
- The function, like operator \p new does not return \p nullptr.
+ The function, like operator \p new does not return \p nullptr.
In no memory situation the function throws \p std::bad_alloc exception.
*/
pointer allocate( size_type nAlign, size_type nCount )
/// @ref cds_sync_monitor "Monitor" that injects the lock into each node
/**
- This simple monitor injects the lock object of type \p Lock into each node.
+ This simple monitor injects the lock object of type \p Lock into each node.
The monitor is designed for user-space locking primitives like \ref sync::spin_lock "spin-lock".
Template arguments:
/// Scoped lock
template <typename Node>
- using scoped_lock = monitor_scoped_lock< injecting_monitor, Node > ;
+ using scoped_lock = monitor_scoped_lock< injecting_monitor, Node >;
};
}} // namespace cds::sync
//@cond
void onLock()
- {
+ {
++m_nLockCount;
int nDiff = static_cast<int>( m_nLockCount.get() - m_nUnlockCount.get());
if ( nDiff > 0 && m_nMaxLocked.get() < static_cast<typename event_counter::value_type>( nDiff ))
void onLockContention() { ++m_nLockContention; }
void onUnlockContention() { ++m_nUnlockContention;}
void onLockAllocation()
- {
- ++m_nLockAllocation;
+ {
+ ++m_nLockAllocation;
int nDiff = static_cast<int>( m_nLockAllocation.get() - m_nLockDeallocation.get());
if ( nDiff > 0 && m_nMaxAllocated.get() < static_cast<typename event_counter::value_type>( nDiff ) )
m_nMaxAllocated = static_cast<typename event_counter::value_type>( nDiff );
The monitor is intended for reducing the number of system mutexes for
huge containers like a tree. The monitor allocates the mutex from the pool \p LockPool
only when container's node should be locked. Lifetime of node's mutex is managed by
- reference counter. When the reference counter to node's mutex becomes zero,
+ reference counter. When the reference counter to node's mutex becomes zero,
the mutex is given back to the pool.
The monitor is blocked: the access to node's mutex is performed under the spin-lock.
public:
typedef LockPool pool_type; ///< Pool type
typedef typename pool_type::value_type lock_type; ///< node lock type
- typedef typename std::conditional<
- std::is_same< BackOff, cds::opt::none >::value,
+ typedef typename std::conditional<
+ std::is_same< BackOff, cds::opt::none >::value,
cds::backoff::yield,
BackOff
>::type back_off; ///< back-off strategy for spinning
typedef uint32_t refspin_type; ///< Reference counter + spin-lock bit
/// Internal statistics
- typedef typename std::conditional<
- Stat,
- typename pool_monitor_traits::stat<>,
- typename pool_monitor_traits::empty_stat
+ typedef typename std::conditional<
+ Stat,
+ typename pool_monitor_traits::stat<>,
+ typename pool_monitor_traits::empty_stat
>::type internal_stat;
/// Pool's default capacity
// try lock spin and increment reference counter
refspin_type cur = p.m_SyncMonitorInjection.m_RefSpin.load( atomics::memory_order_relaxed ) & ~c_nSpinBit;
if ( !p.m_SyncMonitorInjection.m_RefSpin.compare_exchange_weak( cur, cur + c_nRefIncrement + c_nSpinBit,
- atomics::memory_order_acquire, atomics::memory_order_relaxed ) )
+ atomics::memory_order_acquire, atomics::memory_order_relaxed ) )
{
back_off bkoff;
do {
// try lock spin
refspin_type cur = p.m_SyncMonitorInjection.m_RefSpin.load( atomics::memory_order_relaxed ) & ~c_nSpinBit;
if ( !p.m_SyncMonitorInjection.m_RefSpin.compare_exchange_weak( cur, cur | c_nSpinBit,
- atomics::memory_order_acquire, atomics::memory_order_relaxed ) )
+ atomics::memory_order_acquire, atomics::memory_order_relaxed ) )
{
back_off bkoff;
do {
/**
If class' template argument \p Stat is \p false,
the function returns \ref pool_monitor_traits::empty_stat "dummy statistics".
- Otherwise, it returns the reference to monitor's internal statistics
+ Otherwise, it returns the reference to monitor's internal statistics
of type \ref pool_monitor_traits::stat.
*/
internal_stat const& statistics() const
// TSan can issue a warning here:
// read src.m_nSize in src.end()
- // write src.m_nSize in src.clear()
+ // write src.m_nSize in src.clear()
// This is false positive since we own hprec
CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN;
details::retired_vector::iterator itRetiredEnd = src.end();
unsigned int getUInt( const char * pszParamName, unsigned int nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
long getLong( const char * pszParamName, long nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
unsigned long getULong( const char * pszParamName, unsigned long nDefVal = 0 ) const { return get( pszParamName, nDefVal ) ; }
- size_t getSizeT( const char * pszParamName, size_t nDefVal = 0 ) const
+ size_t getSizeT( const char * pszParamName, size_t nDefVal = 0 ) const
{
return static_cast<size_t>( getULong( pszParamName, static_cast<unsigned long>(nDefVal)));
}
}
bool TestCase::shouldRunThis(const char *in_desiredTest, const char *in_className, const char *in_functionName,
- bool invert, bool explicit_test, bool &do_progress)
+ bool invert, bool explicit_test, bool &do_progress)
{
if ((in_desiredTest) && (in_desiredTest[0] != '\0')) {
do_progress = false;
void IntrusiveMichaelListHeaderTest::RCU_GPI_member_cmp()
{
typedef member_int_item< RCU > item;
- struct traits: public
+ struct traits: public
ci::michael_list::make_traits<
ci::opt::hook< ci::michael_list::member_hook<
offsetof( item, hMember ),
void IntrusiveMichaelListHeaderTest::RCU_GPI_member_less()
{
typedef member_int_item< RCU > item;
- struct traits: public
+ struct traits: public
ci::michael_list::make_traits<
ci::opt::hook< ci::michael_list::member_hook<
offsetof( item, hMember ),
void IntrusiveMichaelListHeaderTest::RCU_GPI_member_cmpmix()
{
typedef member_int_item< RCU > item;
- struct traits: public
+ struct traits: public
ci::michael_list::make_traits<
ci::opt::hook< ci::michael_list::member_hook<
offsetof( item, hMember ),
void IntrusiveMichaelListHeaderTest::RCU_GPI_member_ic()
{
typedef member_int_item< RCU > item;
- struct traits: public
+ struct traits: public
ci::michael_list::make_traits<
ci::opt::hook< ci::michael_list::member_hook<
offsetof( item, hMember ),
} // namespace ordlist
-#endif // #ifndef CDSTEST_HDR_LAZY_H
\ No newline at end of file
+#endif // #ifndef CDSTEST_HDR_LAZY_H
} // namespace ordlist
-#endif // #ifndef CDSTEST_HDR_LAZY_KV_H
\ No newline at end of file
+#endif // #ifndef CDSTEST_HDR_LAZY_KV_H
#include "cppunit/cppunit_proxy.h"
// forward declaration
-namespace cds {
+namespace cds {
namespace container {}
namespace opt {}
}
CPPUNIT_ASSERT(m.contains( key ));
CPPUNIT_ASSERT(m.size() == i + 1);
- auto ret = m.update(key, [] ( value_type& v, value_type * old ) {
+ auto ret = m.update(key, [] ( value_type& v, value_type * old ) {
CPPUNIT_ASSERT_CURRENT( old != nullptr );
- ++v.second.nInsertCall;
+ ++v.second.nInsertCall;
}, false );
CPPUNIT_ASSERT( ret.first );
CPPUNIT_ASSERT( !ret.second );
++nCount;
}
CPPUNIT_ASSERT( nCount == capacity );
-
+
nCount = 0;
for ( auto it = m.cbegin(), itEnd = m.cend(); it != itEnd; ++it ) {
CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
#include "cppunit/cppunit_proxy.h"
// forward declaration
-namespace cds {
+namespace cds {
namespace intrusive {}
namespace opt {}
}
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash128!!!" );
test_hp<set_type, hash128::make>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash128::make >(4, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash128!!!" );
test_hp<set_type, hash128::make>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 2);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash128::make >(4, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 3);
- typedef ci::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef ci::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename ci::multilevel_hashset::make_traits<
ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, ci::opt::disposer< item_disposer >
} // namespace set
-#endif // #ifndef CDSTEST_HDR_INTRUSIVE_SET_H
\ No newline at end of file
+#endif // #ifndef CDSTEST_HDR_INTRUSIVE_SET_H
#include "cppunit/cppunit_proxy.h"
// forward declaration
-namespace cds {
+namespace cds {
namespace container {}
namespace opt {}
}
for ( size_t i = 0; i < capacity; ++i ) {
hash_type h = hasher(i);
CPPUNIT_ASSERT( s.contains( h ));
- std::pair<bool, bool> ret = s.update( arg_type( i, h ),
- [](value_type& i, value_type * prev ) {
+ std::pair<bool, bool> ret = s.update( arg_type( i, h ),
+ [](value_type& i, value_type * prev ) {
CPPUNIT_ASSERT_CURRENT( prev != nullptr );
CPPUNIT_ASSERT_CURRENT( i.key == prev->key );
CPPUNIT_ASSERT_CURRENT( i.hash == prev->hash );
size_t nSum = 0;
for ( size_t i = 1; i <= capacity; ++i ) {
CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
- CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum]( value_type const& val ) {
+ CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum]( value_type const& val ) {
CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
CPPUNIT_ASSERT_CURRENT( val.nFindCall == 4 );
CPPUNIT_ASSERT_CURRENT( val.nIteratorCall == 2 );
- nSum += val.key;
+ nSum += val.key;
} ))
CPPUNIT_ASSERT( s.size() == capacity - i );
CPPUNIT_ASSERT( !s.erase(hasher(i), [&nSum]( value_type const& val ) { nSum += val.key; } ))
CPPUNIT_ASSERT( !s.contains( h ));
guarded_ptr gp(s.get( h ));
CPPUNIT_ASSERT( !gp );
- std::pair<bool, bool> ret = s.update( arg_type( i, h ),
- [](value_type& i, value_type * prev ) {
+ std::pair<bool, bool> ret = s.update( arg_type( i, h ),
+ [](value_type& i, value_type * prev ) {
CPPUNIT_ASSERT_CURRENT( prev == nullptr );
i.nInsertCall += 1;
});
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
>::type
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash128!!!" );
test_hp<set_type, hash128::make>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, co::less< hash_type::less >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
>::type
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash128::make >(4, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::memory_model< co::v::sequential_consistent >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
>::type
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash128!!!" );
test_hp<set_type, hash128::make>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, co::less< hash_type::less >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 2);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
>::type
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash128::make >(4, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::memory_model< co::v::sequential_consistent >
static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
test_hp<set_type, std::hash<hash_type>>(5, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
,co::stat< cc::multilevel_hashset::stat<>>
static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
test_hp<set_type, hash_type::make>(4, 3);
- typedef cc::MultiLevelHashSet<
- gc_type,
- Item<hash_type>,
+ typedef cc::MultiLevelHashSet<
+ gc_type,
+ Item<hash_type>,
typename cc::multilevel_hashset::make_traits<
cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
, co::stat< cc::multilevel_hashset::stat<>>
CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 0 );
}
- ensureResult = s.update( 13, []( bool /*bNew*/, key_type key, value_type& v )
- {
- v.nVal = key * 1000;
- ++v.stat.nEnsureNewFuncCall;
+ ensureResult = s.update( 13, []( bool /*bNew*/, key_type key, value_type& v )
+ {
+ v.nVal = key * 1000;
+ ++v.stat.nEnsureNewFuncCall;
});
CPPUNIT_ASSERT( ensureResult.first && ensureResult.second );
CPPUNIT_ASSERT( !s.empty() );
xp = s.extract_max();
CPPUNIT_ASSERT( xp );
nPrev = xp->nVal;
- CPPUNIT_CHECK_EX( nPrev == c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1),
+ CPPUNIT_CHECK_EX( nPrev == c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1),
"Expected=" << c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1) << " real=" << nPrev );
while ( !s.empty() ) {
xp = s.extract_max();
xp = s.extract_max( [&keyPrev]( key_type k ){ keyPrev = k; });
CPPUNIT_ASSERT( xp );
nPrev = xp->nVal;
- CPPUNIT_CHECK_EX( keyPrev == sizeof(keys) / sizeof(keys[0]) - 1,
+ CPPUNIT_CHECK_EX( keyPrev == sizeof(keys) / sizeof(keys[0]) - 1,
"Expected=" << sizeof(keys) / sizeof(keys[0]) - 1 << " real=" << keyPrev );
- CPPUNIT_CHECK_EX( nPrev == c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1),
+ CPPUNIT_CHECK_EX( nPrev == c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1),
"Expected=" << c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1) << " real=" << nPrev );
while ( !s.empty() ) {
xp = s.extract_max( [&key](key_type k){ key = k; });
xp = s.extract_max_key( keyPrev );
CPPUNIT_ASSERT( xp );
nPrev = xp->nVal;
- CPPUNIT_CHECK_EX( keyPrev == sizeof(keys) / sizeof(keys[0]) - 1,
+ CPPUNIT_CHECK_EX( keyPrev == sizeof(keys) / sizeof(keys[0]) - 1,
"Expected=" << sizeof(keys) / sizeof(keys[0]) - 1 << " real=" << keyPrev );
- CPPUNIT_CHECK_EX( nPrev == c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1),
+ CPPUNIT_CHECK_EX( nPrev == c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1),
"Expected=" << c_nStep * (sizeof(keys) / sizeof(keys[0]) - 1) << " real=" << nPrev );
while ( !s.empty() ) {
xp = s.extract_max_key( key );
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< false >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_cmp()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
>::type
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_cmp_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_cmpless()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::less< std::less<key_type> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less_ic()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_cmp_ic()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_cmp_ic_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_cmp_ic_stat_yield()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less_relaxed_insert()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less_relaxed_insert_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_pool_monitor_less()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::sync_monitor< cds::sync::pool_monitor<simple_pool> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_pool_monitor_less_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_pool_monitor_cmp_ic_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_pool_monitor_cmp_ic_stat_yield()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_pool_monitor_less_relaxed_insert()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_pool_monitor_less_relaxed_insert_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_less()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< false >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_less_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_cmp()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
>::type
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_cmp_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_cmpless()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::less< std::less<key_type> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_less_ic()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_cmp_ic()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_cmp_ic_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_cmp_ic_stat_yield()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_less_relaxed_insert()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_less_relaxed_insert_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_pool_monitor_less()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::sync_monitor< cds::sync::pool_monitor<simple_pool> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_pool_monitor_less_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_pool_monitor_cmp_ic_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_pool_monitor_cmp_ic_stat_yield()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_pool_monitor_less_relaxed_insert()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpi_pool_monitor_less_relaxed_insert_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_less()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< false >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_less_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_cmp()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
>::type
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_cmp_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_cmpless()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::less< std::less<key_type> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_less_ic()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_cmp_ic()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_cmp_ic_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_cmp_ic_stat_yield()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_less_relaxed_insert()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_less_relaxed_insert_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_pool_monitor_less()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::sync_monitor< cds::sync::pool_monitor<simple_pool> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_pool_monitor_less_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_pool_monitor_cmp_ic_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_pool_monitor_cmp_ic_stat_yield()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_pool_monitor_less_relaxed_insert()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpt_pool_monitor_less_relaxed_insert_stat()
{
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_less()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< false >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_less_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_cmp()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
>::type
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_cmp_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_cmpless()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::less< std::less<key_type> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_less_ic()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_cmp_ic()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_cmp_ic_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_cmp_ic_stat_yield()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_less_relaxed_insert()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_less_relaxed_insert_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_pool_monitor_less()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::sync_monitor< cds::sync::pool_monitor<simple_pool> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_pool_monitor_less_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_pool_monitor_cmp_ic_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_pool_monitor_cmp_ic_stat_yield()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_pool_monitor_less_relaxed_insert()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_shb_pool_monitor_less_relaxed_insert_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_less()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< false >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_less_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_cmp()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
>::type
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_cmp_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_cmpless()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::less< std::less<key_type> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_less_ic()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_cmp_ic()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_cmp_ic_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_cmp_ic_stat_yield()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_less_relaxed_insert()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_less_relaxed_insert_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_pool_monitor_less()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::sync_monitor< cds::sync::pool_monitor<simple_pool> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_pool_monitor_less_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_pool_monitor_cmp_ic_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_pool_monitor_cmp_ic_stat_yield()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,co::item_counter< cds::atomicity::item_counter >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_pool_monitor_less_relaxed_insert()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,cc::bronson_avltree::relaxed_insert< true >
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_sht_pool_monitor_less_relaxed_insert_stat()
{
#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
- struct traits: public
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
,co::stat< cc::bronson_avltree::stat<> >
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 )
+ void Map_InsDel_func::setUpParams( const CppUnitMini::TestCfg& cfg )
{
c_nInsertThreadCount = cfg.getULong("InsertThreadCount", def_nInsertThreadCount );
c_nDeleteThreadCount = cfg.getULong("DeleteThreadCount", def_nDeleteThreadCount );
size_t Map_InsDel_string::c_nMaxLoadFactor = 8;
bool Map_InsDel_string::c_bPrintGCState = true;
- void Map_InsDel_string::setUpParams( const CppUnitMini::TestCfg& cfg )
+ void Map_InsDel_string::setUpParams( const CppUnitMini::TestCfg& cfg )
{
c_nInsertThreadCount = cfg.getSizeT("InsertThreadCount", c_nInsertThreadCount );
c_nDeleteThreadCount = cfg.getSizeT("DeleteThreadCount", c_nDeleteThreadCount );
typedef cds::memory::lazy_vyukov_queue_pool< std::mutex > BronsonAVLTreeMap_lazy_pool;
typedef cds::memory::bounded_vyukov_queue_pool< std::mutex > BronsonAVLTreeMap_bounded_pool;
- struct BronsonAVLTreeMap_less: public
+ struct BronsonAVLTreeMap_less: public
cc::bronson_avltree::make_traits<
co::less< less >
,cc::bronson_avltree::relaxed_insert< false >
typedef cc::BronsonAVLTreeMap< rcu_shb, Key, Value, BronsonAVLTreeMap_less > BronsonAVLTreeMap_rcu_shb_less;
typedef cc::BronsonAVLTreeMap< rcu_sht, Key, Value, BronsonAVLTreeMap_less > BronsonAVLTreeMap_rcu_sht_less;
#endif
- struct BronsonAVLTreeMap_cmp_stat: public
+ struct BronsonAVLTreeMap_cmp_stat: public
cc::bronson_avltree::make_traits<
co::compare< compare >
,cc::bronson_avltree::relaxed_insert< false >
{
CPPUNIT_MSG( " Check internal consistency (single-threaded)..." );
bool bOk = m.check_consistency([]( size_t nLevel, size_t hLeft, size_t hRight )
- {
- CPPUNIT_MSG( "Tree violation on level=" << nLevel << ": hLeft=" << hLeft << ", hRight=" << hRight )
+ {
+ CPPUNIT_MSG( "Tree violation on level=" << nLevel << ": hLeft=" << hLeft << ", hRight=" << hRight )
});
CPPUNIT_CHECK_CURRENT_EX( bOk, "check_consistency failed");
}
nTotalFailed += pThread->m_nPopFailed;
}
- CPPUNIT_MSG( " Total: popped=" << nTotalPopped << ", empty pop=" << nTotalFailed
+ CPPUNIT_MSG( " Total: popped=" << nTotalPopped << ", empty pop=" << nTotalFailed
<< "\n Errors: pop equal=" << nTotalErrorEq << ", priority violation=" << nTotalError
);
CPPUNIT_CHECK( nTotalPopped == nThreadItemCount * s_nThreadCount );
`git clone -b $GitBranch $GitRepo $DistrDir` or die "Error cloning branch $GitBranch to $DistrDir\n";\r
print "Remove $DistrDir/.git directory\n";\r
`rm -fr $DistrDir/.git`;\r
-`rm -f $DistrDir/.gitignore $DistrDir/tools/brush_cds.pl $DistrDir/tools/make_distrib.pl $DistrDir/tools/make_distrib.bat`;\r
+`rm -f $DistrDir/.gitignore $DistrDir/tools/brush_cds.pl $DistrDir/tools/make_distrib.pl $DistrDir/tools/make_distrib.bat $DistrDir/doxygen/images.odp`;\r
\r
print "make copyright...\n" ;\r
makeCopyright($DistrDir);\r