/// Count of hazard pointers required
static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
+ /// Level statistics
+ typedef feldman_hashmap::level_statistics level_statistics;
+
protected:
//@cond
typedef typename maker::node_type node_type;
: iterator_base( rhs )
{}
- bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+ bidirectional_iterator& operator=( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
{
iterator_base::operator=( rhs );
return *this;
}
template <bool IsConst2>
- bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+ bool operator ==( bidirectional_iterator<IsConst2> const& rhs ) const CDS_NOEXCEPT
{
return iterator_base::operator==( rhs );
}
template <bool IsConst2>
- bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+ bool operator !=( bidirectional_iterator<IsConst2> const& rhs ) const CDS_NOEXCEPT
{
return !( *this == rhs );
}
}
template <bool IsConst2>
- bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
+ bool operator ==( reverse_bidirectional_iterator<IsConst2> const& rhs ) const
{
return iterator_base::operator==( rhs );
}
template <bool IsConst2>
- bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
+ bool operator !=( reverse_bidirectional_iterator<IsConst2> const& rhs )
{
return !( *this == rhs );
}
Equation for \p head_bits and \p array_bits:
\code
- sizeof(hash_type) * 8 == head_bits + N * array_bits
+ sizeof( hash_type ) * 8 == head_bits + N * array_bits
\endcode
where \p N is multi-level array depth.
*/
template <typename K>
bool insert( K&& key )
{
- scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
+ scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>( key ) ));
if ( base_class::insert( *sp )) {
sp.release();
return true;
template <typename K, typename V>
bool insert( K&& key, V&& val )
{
- scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
+ scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>( key ), std::forward<V>( val )));
if ( base_class::insert( *sp )) {
sp.release();
return true;
template <typename K, typename Func>
bool insert_with( K&& key, Func func )
{
- scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
+ scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>( key )));
if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
sp.release();
return true;
template <typename K, typename... Args>
bool emplace( K&& key, Args&&... args )
{
- scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
+ scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>( key ), std::forward<Args>( args )... ));
if ( base_class::insert( *sp )) {
sp.release();
return true;
template <typename K, typename Func>
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)));
+ 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 );},
bInsert );
The functor \p Func interface:
\code
struct extractor {
- void operator()(value_type& item) { ... }
+ void operator()( value_type& item ) { ... }
};
\endcode
where \p item is the element found.
template <typename K, typename Func>
bool erase( K const& key, Func f )
{
- return base_class::erase( m_Hasher(key_type(key)), [&f]( node_type& node) { f( node.m_Value ); } );
+ return base_class::erase( m_Hasher( key_type( key )), [&f]( node_type& node) { f( node.m_Value ); } );
}
/// Deletes the element pointed by iterator \p iter
{
return base_class::do_erase_at( iter );
}
+ bool erase_at( const_iterator const& iter )
+ {
+ return base_class::do_erase_at( iter );
+ }
+ bool erase_at( const_reverse_iterator const& iter )
+ {
+ return base_class::do_erase_at( iter );
+ }
//@endcond
/// Extracts the item from the map with specified \p key
template <typename K, typename Func>
bool find( K const& key, Func f )
{
- return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
+ return base_class::find( m_Hasher( key_type( key )), [&f]( node_type& node ) { f( node.m_Value );});
}
/// Finds the key \p key and return the item found
Result can be useful for estimating efficiency of hash functor you use.
*/
- void get_level_statistics(std::vector< feldman_hashmap::level_statistics>& stat) const
+ void get_level_statistics( std::vector< feldman_hashmap::level_statistics>& stat) const
{
base_class::get_level_statistics( stat );
}
m_guard.copy( rhs.m_guard );
}
- iterator_base& operator=(iterator_base const& rhs) CDS_NOEXCEPT
+ iterator_base& operator=( iterator_base const& rhs ) CDS_NOEXCEPT
{
m_pNode = rhs.m_pNode;
m_idx = rhs.m_idx;
m_guard.clear();
}
- bool operator ==(iterator_base const& rhs) const CDS_NOEXCEPT
+ bool operator ==( iterator_base const& rhs ) const CDS_NOEXCEPT
{
return m_pNode == rhs.m_pNode && m_idx == rhs.m_idx && m_set == rhs.m_set;
}
- bool operator !=(iterator_base const& rhs) const CDS_NOEXCEPT
+ bool operator !=( iterator_base const& rhs ) const CDS_NOEXCEPT
{
return !( *this == rhs );
}
else {
if ( slot.ptr()) {
// data node
- if ( m_guard.protect( pNode->nodes[idx], [](node_ptr p) -> value_type * { return p.ptr(); }) == slot ) {
+ if ( m_guard.protect( pNode->nodes[idx], []( node_ptr p ) -> value_type* { return p.ptr(); }) == slot ) {
m_pNode = pNode;
m_idx = idx;
return;
else {
if ( slot.ptr()) {
// data node
- if ( m_guard.protect( pNode->nodes[idx], [](node_ptr p) -> value_type * { return p.ptr(); }) == slot ) {
+ if ( m_guard.protect( pNode->nodes[idx], []( node_ptr p ) -> value_type* { return p.ptr(); }) == slot ) {
m_pNode = pNode;
m_idx = idx;
return;
: iterator_base( rhs )
{}
- bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+ bidirectional_iterator& operator=( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
{
iterator_base::operator=( rhs );
return *this;
}
template <bool IsConst2>
- bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+ bool operator ==( bidirectional_iterator<IsConst2> const& rhs ) const CDS_NOEXCEPT
{
return iterator_base::operator==( rhs );
}
template <bool IsConst2>
- bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+ bool operator !=( bidirectional_iterator<IsConst2> const& rhs ) const CDS_NOEXCEPT
{
return !( *this == rhs );
}
}
template <bool IsConst2>
- bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
+ bool operator ==( reverse_bidirectional_iterator<IsConst2> const& rhs ) const
{
return iterator_base::operator==( rhs );
}
template <bool IsConst2>
- bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
+ bool operator !=( reverse_bidirectional_iterator<IsConst2> const& rhs )
{
return !( *this == rhs );
}
Equation for \p head_bits and \p array_bits:
\code
- sizeof(hash_type) * 8 == head_bits + N * array_bits
+ sizeof( hash_type ) * 8 == head_bits + N * array_bits
\endcode
where \p N is multi-level array depth.
*/
*/
bool insert( value_type& val )
{
- return insert( val, [](value_type&) {} );
+ return insert( val, []( value_type& ) {} );
}
/// Inserts new node
template <typename Func>
bool insert( value_type& val, Func f )
{
- hash_type const& hash = hash_accessor()(val);
+ hash_type const& hash = hash_accessor()( val );
traverse_data pos( hash, *this );
hash_comparator cmp;
typename gc::template GuardArray<2> guards;
assert( slot.bits() == 0 );
// protect data node by hazard pointer
- if (guards.protect( 0, pos.pArr->nodes[pos.nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
+ if ( guards.protect( 0, pos.pArr->nodes[pos.nSlot], []( node_ptr p ) -> value_type* { return p.ptr(); }) != slot ) {
// slot value has been changed - retry
stats().onSlotChanged();
}
- if (slot.ptr()) {
- if ( cmp( hash, hash_accessor()(*slot.ptr())) == 0 ) {
+ if ( slot.ptr()) {
+ if ( cmp( hash, hash_accessor()( *slot.ptr())) == 0 ) {
// the item with that hash value already exists
stats().onInsertFailed();
return false;
else {
// the slot is empty, try to insert data node
node_ptr pNull;
- if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong( pNull, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed ))
+ if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
{
// the new data node has been inserted
- f(val);
+ f( val );
++m_ItemCounter;
stats().onInsertSuccess();
- stats().height(pos.nHeight);
+ stats().height( pos.nHeight );
return true;
}
*/
std::pair<bool, bool> update( value_type& val, bool bInsert = true )
{
- return do_update(val, [](value_type&, value_type *) {}, bInsert );
+ return do_update( val, []( value_type&, value_type* ) {}, bInsert );
}
/// Unlinks the item \p val from the set
bool unlink( value_type const& val )
{
typename gc::Guard guard;
- auto pred = [&val](value_type const& item) -> bool { return &item == &val; };
+ auto pred = [&val]( value_type const& item ) -> bool { return &item == &val; };
value_type * p = do_erase( hash_accessor()( val ), guard, std::ref( pred ));
return p != nullptr;
}
*/
bool erase( hash_type const& hash )
{
- return erase(hash, [](value_type const&) {} );
+ return erase( hash, []( value_type const& ) {} );
}
/// Deletes the item from the set
*/
bool contains( hash_type const& hash )
{
- return find( hash, [](value_type&) {} );
+ return find( hash, []( value_type& ) {} );
}
/// Finds an item by it's \p hash and returns the item found
Result can be useful for estimating efficiency of hash functor you use.
*/
- void get_level_statistics(std::vector< feldman_hashset::level_statistics>& stat) const
+ void get_level_statistics( std::vector< feldman_hashset::level_statistics>& stat ) const
{
base_class::get_level_statistics( stat );
}
}
else if ( slot.bits() == base_class::flag_array_converting ) {
// the slot is converting to array node right now
- while ( (slot = pArr->load(memory_model::memory_order_acquire)).bits() == base_class::flag_array_converting ) {
+ while (( slot = pArr->load( memory_model::memory_order_acquire )).bits() == base_class::flag_array_converting ) {
bkoff();
stats().onSlotConverting();
}
traverse_data pos( hash, *this );
hash_comparator cmp;
- while (true) {
+ while ( true ) {
node_ptr slot = base_class::traverse( pos );
- assert(slot.bits() == 0);
+ assert( slot.bits() == 0 );
// protect data node by hazard pointer
- if (guard.protect( pos.pArr->nodes[pos.nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot) {
+ if ( guard.protect( pos.pArr->nodes[pos.nSlot], []( node_ptr p ) -> value_type* { return p.ptr(); }) != slot) {
// slot value has been changed - retry
stats().onSlotChanged();
continue;
}
- else if (slot.ptr() && cmp(hash, hash_accessor()(*slot.ptr())) == 0) {
+ else if ( slot.ptr() && cmp( hash, hash_accessor()( *slot.ptr())) == 0 ) {
// item found
stats().onFindSuccess();
return slot.ptr();
{
traverse_data pos( hash, *this );
hash_comparator cmp;
- while (true) {
+ while ( true ) {
node_ptr slot = base_class::traverse( pos );
- assert(slot.bits() == 0);
+ assert( slot.bits() == 0 );
// protect data node by hazard pointer
- if (guard.protect( pos.pArr->nodes[pos.nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot) {
+ if ( guard.protect( pos.pArr->nodes[pos.nSlot], []( node_ptr p ) -> value_type* { return p.ptr(); }) != slot ) {
// slot value has been changed - retry
stats().onSlotChanged();
}
- else if (slot.ptr()) {
- if ( cmp(hash, hash_accessor()(*slot.ptr())) == 0 && pred(*slot.ptr())) {
+ else if ( slot.ptr()) {
+ if ( cmp( hash, hash_accessor()( *slot.ptr())) == 0 && pred( *slot.ptr())) {
// item found - replace it with nullptr
- if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
+ if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong( slot, node_ptr( nullptr ), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
// slot is guarded by HP
- gc::template retire<disposer>(slot.ptr());
+ gc::template retire<disposer>( slot.ptr());
--m_ItemCounter;
stats().onEraseSuccess();
for (;;) {
node_ptr slot = iter.m_pNode->nodes[iter.m_idx].load( memory_model::memory_order_acquire );
if ( slot.bits() == 0 && slot.ptr() == iter.pointer()) {
- if ( iter.m_pNode->nodes[iter.m_idx].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
+ if ( iter.m_pNode->nodes[iter.m_idx].compare_exchange_strong( slot, node_ptr( nullptr ), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
// the item is guarded by iterator, so we may retire it safely
gc::template retire<disposer>( slot.ptr());
--m_ItemCounter;
typename gc::template GuardArray<2> guards;
guards.assign( 1, &val );
- while (true) {
+ while ( true ) {
node_ptr slot = base_class::traverse( pos );
- assert(slot.bits() == 0);
+ assert( slot.bits() == 0 );
// protect data node by hazard pointer
- if ( guards.protect( 0, pos.pArr->nodes[pos.nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
+ if ( guards.protect( 0, pos.pArr->nodes[pos.nSlot], []( node_ptr p ) -> value_type* { return p.ptr(); }) != slot ) {
// slot value has been changed - retry
stats().onSlotChanged();
}
else if ( slot.ptr()) {
- if ( cmp( hash, hash_accessor()(*slot.ptr())) == 0 ) {
+ if ( cmp( hash, hash_accessor()( *slot.ptr())) == 0 ) {
// the item with that hash value already exists
// Replace it with val
if ( slot.ptr() == &val ) {
stats().onUpdateExisting();
- return std::make_pair(true, false);
+ return std::make_pair( true, false );
}
- if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong(slot, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed)) {
+ if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong( slot, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
// slot can be disposed
f( val, slot.ptr());
gc::template retire<disposer>( slot.ptr());
stats().onUpdateExisting();
- return std::make_pair(true, false);
+ return std::make_pair( true, false );
}
stats().onUpdateRetry();
}
else {
stats().onUpdateFailed();
- return std::make_pair(false, false);
+ return std::make_pair( false, false );
}
}
else {
// the slot is empty, try to insert data node
if ( bInsert ) {
node_ptr pNull;
- if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong(pNull, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed))
+ if ( pos.pArr->nodes[pos.nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
{
// the new data node has been inserted
- f(val, nullptr);
+ f( val, nullptr );
++m_ItemCounter;
stats().onUpdateNew();
stats().height( pos.nHeight );
- return std::make_pair(true, true);
+ return std::make_pair( true, true );
}
}
else {
stats().onUpdateFailed();
- return std::make_pair(false, false);
+ return std::make_pair( false, false );
}
// insert failed - slot has been changed by another thread