SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_LAZY_LIST_NOGC_H
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< node traits
typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
- typedef typename traits::item_counter item_counter; ///< Item counting policy used
- typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see lazy_list::traits::memory_model)
+ typedef typename traits::item_counter item_counter; ///< Item counting policy used
+ typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+ typedef typename traits::stat stat; ///< Internal statistics
//@cond
+ static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
// Rebind traits (split-list support)
template <typename... Options>
struct rebind_traits {
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
//@endcond
protected:
node_type m_Head; ///< List head (dummy node)
node_type m_Tail; ///< List tail (dummy node)
item_counter m_ItemCounter; ///< Item counter
+ mutable stat m_Stat; ///< Internal statistics
//@cond
/// Default constructor initializes empty list
LazyList()
{
- static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
m_Head.m_pNext.store( &m_Tail, memory_model::memory_order_relaxed );
}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : m_Stat( st )
+ {
+ m_Head.m_pNext.store( &m_Tail, memory_model::memory_order_relaxed );
+ }
+ //@endcond
+
/// Destroys the list object
~LazyList()
{
The functor may change non-key fields of the \p item.
While the functor \p f is calling the item \p item is locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
*/
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
// split-list support
if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) ) {
// failed: key already in list
+ m_Stat.onInsertFailed();
return false;
}
else {
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
- ++m_ItemCounter;
- return true;
+ break;
}
}
}
+
+ m_Stat.onInsertRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
}
iterator insert_at_( node_type * pHead, value_type& val )
// key already in the list
func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+ m_Stat.onUpdateExisting();
return std::make_pair( iterator( pos.pCur ), false );
}
else {
// new key
- if ( !bAllowInsert )
+ if ( !bAllowInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( end(), false );
+ }
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
func( true, val, val );
- ++m_ItemCounter;
- return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+ break;
}
}
+
+ m_Stat.onUpdateRetry();
}
}
+
+ ++m_ItemCounter;
+ m_Stat.onUpdateNew();
+ return std::make_pair( iterator( node_traits::to_node_ptr( val ) ), true );
}
template <typename Func>
if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) )
{
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
}
+
+ m_Stat.onFindFailed();
return false;
}
search( pHead, val, pos, pred );
if ( pos.pCur != &m_Tail ) {
- if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ))
+ if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred )) {
+ m_Stat.onFindSuccess();
return iterator( pos.pCur );
+ }
}
+
+ m_Stat.onFindFailed();
return end();
}
return cmp(l, r) == 0;
}
- static bool validate( node_type * pPred, node_type * pCur )
+ bool validate( node_type * pPred, node_type * pCur )
{
- return pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur;
+ if ( pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur ) {
+ m_Stat.onValidationSuccess();
+ return true;
+ }
+
+ m_Stat.onValidationFailed();
+ return false;
}
+ // for split-list
+ template <typename Predicate>
+ void erase_for( Predicate pred )
+ {
+ node_type * pPred = nullptr;
+ node_type * pHead = m_Head.m_pNext.load( memory_model::memory_order_relaxed );
+
+ while ( pHead != &m_Tail ) {
+ node_type * p = pHead->m_pNext.load( memory_model::memory_order_relaxed );
+ if ( pred( *node_traits::to_value_ptr( pHead ))) {
+ assert( pPred != nullptr );
+ pPred->m_pNext.store( p, memory_model::memory_order_relaxed );
+ dispose_node( pHead, disposer() );
+ }
+ else
+ pPred = pHead;
+ pHead = p;
+ }
+ }
//@endcond
};