Unordered nogc lazy list implementation.
*/
typedef opt::none less;
+ /// Specifies binary functor used for comparing keys for equality
+ /**
+ No default functor is provided. If \p equal_to option is not spcified, \p compare is used, if \p compare is not
+ specified, \p less is used.
+ */
+ typedef opt::none equal_to;
+
+ /// Specifies list ordering policy.
+ /**
+ If \p sort is \p true, than list maintains items in sorted order, otherwise items are unordered. Default is \p true.
+ Note that if \p sort is \p falsem than lookup operations scan entire list.
+ */
+ static const bool sort = true;
+
/// Lock type used to lock modifying items
/**
Default is cds::sync::spin
- \p opt::compare - key compare 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 key compare. Default is \p std::less<T>.
+ - \p opt::equal_to - specifies binary functor for comparing keys for equality. No default is provided. If \p equal_to is
+ not specified, \p compare is used, if \p compare is not specified, \p less is used.
+ - \p opt::sort - specifies ordering policy. Default value is \p true.
- \p opt::back_off - back-off strategy used. If the option is not specified, \p cds::backoff::Default is used.
- \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
To enable item counting use \p atomicity::item_counter.
};
typedef typename opt::details::make_comparator< key_type, original_type_traits >::type key_comparator;
+ typedef typename opt::details::make_equal_to< key_type, original_type_traits >::type equal_to_comparator;
template <typename Less>
struct less_wrapper {
typedef cds::details::compare_wrapper< node_type, cds::opt::details::make_comparator_from_less<Less>, key_field_accessor > type;
};
+ template <typename Equal>
+ struct equal_to_wrapper {
+ typedef cds::details::predicate_wrapper< node_type, Equal, key_field_accessor > type;
+ };
+
struct intrusive_traits: public original_type_traits
{
typedef intrusive::lazy_list::base_hook< opt::gc<gc> > hook;
typedef node_deallocator disposer;
typedef cds::details::compare_wrapper< node_type, key_comparator, key_field_accessor > compare;
+ typedef cds::details::predicate_wrapper< node_type, equal_to_comparator, key_field_accessor > equal_to;
static const opt::link_check_type link_checker = cds::intrusive::lazy_list::traits::link_checker;
};
};
typedef typename opt::details::make_comparator< value_type, original_type_traits >::type key_comparator;
+ typedef typename opt::details::make_equal_to< value_type, original_type_traits >::type equal_to_comparator;
struct value_accessor {
value_type const & operator()( node_type const & node ) const
typedef cds::details::compare_wrapper< node_type, cds::opt::details::make_comparator_from_less<Less>, value_accessor > type;
};
+ template <typename Equal>
+ struct equal_to_wrapper {
+ typedef cds::details::predicate_wrapper< node_type, Equal, value_accessor > type;
+ };
+
struct intrusive_traits: public original_type_traits
{
typedef intrusive::lazy_list::base_hook< opt::gc<gc> > hook;
static CDS_CONSTEXPR const opt::link_check_type link_checker = cds::intrusive::lazy_list::traits::link_checker;
typedef cds::details::compare_wrapper< node_type, key_comparator, value_accessor > compare;
+ typedef cds::details::predicate_wrapper< node_type, equal_to_comparator, value_accessor > equal_to;
};
typedef intrusive::LazyList<gc, node_type, intrusive_traits> type;
//@endcond
public:
+ typedef Traits traits;
typedef cds::gc::nogc gc; ///< Garbage collector
#ifdef CDS_DOXYGEN_INVOKED
typedef Key key_type ; ///< Key type
protected:
//@cond
- typedef typename base_class::value_type node_type;
- typedef typename maker::cxx_allocator cxx_allocator;
- typedef typename maker::node_deallocator node_deallocator;
- typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
- typedef typename base_class::node_type head_type;
+ typedef typename base_class::value_type node_type;
+ typedef typename maker::cxx_allocator cxx_allocator;
+ typedef typename maker::node_deallocator node_deallocator;
+ typedef typename base_class::predicate_type intrusive_predicate_type;
+ typedef typename base_class::node_type head_type;
//@endcond
protected:
template <typename Q>
iterator find( Q const& key )
{
- return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ) );
+ return node_to_iterator( find_at( head(), key, intrusive_predicate_type() ) );
}
/// Finds the key \p val using \p pred predicate for searching
\p Less functor has the interface like \p std::less.
\p pred must imply the same element order as the comparator used for building the list.
*/
- template <typename Q, typename Less>
- iterator find_with( Q const& key, Less pred )
+ template <typename Q, typename Less, bool Sort = traits::sort>
+ typename std::enable_if<Sort, iterator>::type find_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type() ) );
}
+ /// Finds the key \p val using \p equal predicate for searching
+ /**
+ The function is an analog of \ref cds_nonintrusive_LazyKVList_nogc_find "find(Q const&)"
+ but \p equal is used for key comparing.
+ \p Equal functor has the interface like \p std::equal_to.
+ */
+ template <typename Q, typename Equal, bool Sort = traits::sort>
+ typename std::enable_if<!Sort, iterator>::type find_with( Q const& key, Equal equal )
+ {
+ CDS_UNUSED( equal );
+ return node_to_iterator( find_at( head(), key, typename maker::template equal_to_wrapper<Equal>::type() ) );
+ }
+
/// Check if the list is empty
bool empty() const
{
typedef T value_type; ///< Type of value stored in the list
typedef Traits traits; ///< List traits
- typedef typename base_class::back_off back_off; ///< Back-off strategy used
- typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
- typedef typename base_class::item_counter item_counter; ///< Item counting policy used
- typedef typename maker::key_comparator key_comparator; ///< key comparison functor
- typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::back_off back_off; ///< Back-off strategy used
+ typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
+ typedef typename base_class::item_counter item_counter; ///< Item counting policy used
+ typedef typename maker::key_comparator key_comparator; ///< key comparison functor
+ typedef typename maker::equal_to_comparator equal_to_comparator; ///< key equality comparision functor
+ typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
protected:
//@cond
- typedef typename base_class::value_type node_type;
- typedef typename maker::cxx_allocator cxx_allocator;
- typedef typename maker::node_deallocator node_deallocator;
- typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
+ typedef typename base_class::value_type node_type;
+ typedef typename maker::cxx_allocator cxx_allocator;
+ typedef typename maker::node_deallocator node_deallocator;
+ typedef typename base_class::predicate_type intrusive_predicate_type;
typedef typename base_class::node_type head_type;
//@endcond
template <typename Q>
iterator find( Q const& key )
{
- return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ));
+ return node_to_iterator( find_at( head(), key, intrusive_predicate_type() ));
}
/// Finds the key \p val using \p pred predicate for searching
\p Less functor has the interface like \p std::less.
\p pred must imply the same element order as the comparator used for building the list.
*/
- template <typename Q, typename Less>
- iterator find_with( Q const& key, Less pred )
+ template <typename Q, typename Less, bool Sort = traits::sort>
+ typename std::enable_if<Sort, iterator>::type find_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type() ));
}
+ /// Finds the key \p val using \p equal predicate for searching
+ /**
+ The function is an analog of \ref cds_nonintrusive_LazyList_nogc_find "find(Q const&)"
+ but \p pred is used for key comparing.
+ \p Equal functor has the interface like \p std::equal_to.
+ */
+ template <typename Q, typename Equal, bool Sort = traits::sort>
+ typename std::enable_if<!Sort, iterator>::type find_with( Q const& key, Equal equal )
+ {
+ CDS_UNUSED( equal );
+ return node_to_iterator( find_at( head(), key, typename maker::template equal_to_wrapper<Equal>::type() ));
+ }
+
/// Check if the list is empty
bool empty() const
{
*/
typedef opt::none less;
+ /// Specifies binary functor used for comparing keys for equality
+ /**
+ If \p equal_to option is not specified, \p compare is used, if \p compare is not specified, \p less is used,
+ if \p less is not specified, then \p std::equal_to<T> is used.
+ */
+ typedef opt::none equal_to;
+
+ /// Specifies list ordering policy
+ /**
+ If \p sort is \p true, than list maintains items in sorted order, otherwise items are unordered. Default is \p true.
+ Note that if \p sort is \p false, than lookup operations scan entire list.
+ */
+ static const bool sort = true;
+
/// Back-off strategy
typedef cds::backoff::Default back_off;
- \p opt::compare - key 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 key comparison. Default is \p std::less<T>.
+ - \p opt::equal_to - specifies binary functor for comparing keys for equality. If \p equal_to is not specified, \p compare is
+ used, \p compare is not specified, \p less is used.
+ - \p opt::sort - specifies ordering policy. Default value is \p true.
- \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
- \p opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. Due the nature
of GC schema the disposer may be called asynchronously.
# ifdef CDS_DOXYGEN_INVOKED
typedef implementation_defined key_comparator ; ///< key comparison functor based on opt::compare and opt::less option setter.
+ typedef implementation_defined equal_to_comparator;
+ typedef implementation_defined predicate_type;
# else
typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
+ typedef typename opt::details::make_equal_to< value_type, traits >::type equal_to_comparator;
+ typedef typename std::conditional< traits::sort, key_comparator, equal_to_comparator >::type predicate_type;
# endif
typedef typename traits::back_off back_off; ///< Back-off strategy
typedef typename traits::disposer disposer; ///< disposer
template <typename Q, typename Func>
bool find( Q& key, Func f )
{
- return find_at( &m_Head, key, key_comparator(), f );
+ return find_at( &m_Head, key, predicate_type(), f );
}
//@cond
template <typename Q, typename Func>
bool find( Q const& key, Func f )
{
- return find_at( &m_Head, key, key_comparator(), f );
+ return find_at( &m_Head, key, predicate_type(), f );
}
//@endcond
- /// Finds the key \p key using \p pred predicate for searching
+ /// Finds the key \p key using \p less predicate for searching. Disabled for unordered lists.
/**
The function is an analog of \ref cds_intrusive_LazyList_nogc_find_func "find(Q&, Func)"
but \p pred is used for key comparing.
\p Less functor has the interface like \p std::less.
\p pred must imply the same element order as the comparator used for building the list.
*/
- template <typename Q, typename Less, typename Func>
- bool find_with( Q& key, Less pred, Func f )
+ template <typename Q, typename Less, typename Func, bool Sort = traits::sort>
+ typename std::enable_if<Sort, bool>::type find_with( Q& key, Less less, Func f )
{
- CDS_UNUSED( pred );
+ CDS_UNUSED( less );
return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>(), f );
}
+
+ /// Finds the key \p key using \p equal predicate for searching. Disabled for ordered lists.
+ /**
+ The function is an analog of \ref cds_intrusive_LazyList_nogc_find_func "find(Q&, Func)"
+ but \p equal is used for key comparing.
+ \p Equal functor has the interface like \p std::equal_to.
+ */
+ template <typename Q, typename Equal, typename Func, bool Sort = traits::sort>
+ typename std::enable_if<!Sort, bool>::type find_with( Q& key, Equal equal, Func f )
+ {
+ CDS_UNUSED( equal );
+ return find_at( &m_Head, key, Equal(), f );
+ }
//@cond
- template <typename Q, typename Less, typename Func>
- bool find_with( Q const& key, Less pred, Func f )
+ template <typename Q, typename Less, typename Func, bool Sort = traits::sort>
+ typename std::enable_if<Sort, bool>::type find_with( Q const& key, Less pred, Func f )
{
CDS_UNUSED( pred );
return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>(), f );
}
+
+ template <typename Q, typename Equal, typename Func, bool Sort = traits::sort>
+ typename std::enable_if<!Sort, bool>::type find_with( Q const& key, Equal equal, Func f )
+ {
+ CDS_UNUSED( equal );
+ return find_at( &m_Head, key, Equal(), f );
+ }
//@endcond
/// Finds the key \p key
template <typename Q>
value_type * find( Q const& key )
{
- return find_at( &m_Head, key, key_comparator() );
+ return find_at( &m_Head, key, predicate_type() );
}
- /// Finds the key \p key using \p pred predicate for searching
+ /// Finds the key \p key using \p pred predicate for searching. Disabled for unordered lists.
/**
The function is an analog of \ref cds_intrusive_LazyList_nogc_find_val "find(Q const&)"
but \p pred is used for key comparing.
\p Less functor has the interface like \p std::less.
\p pred must imply the same element order as the comparator used for building the list.
*/
- template <typename Q, typename Less>
- value_type * find_with( Q const& key, Less pred )
+ template <typename Q, typename Less, bool Sort = traits::sort>
+ typename std::enable_if<Sort, value_type *>::type find_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>() );
}
+ /// Finds the key \p key using \p equal predicate for searching. Disabled for ordered lists.
+ /**
+ The function is an analog of \ref cds_intrusive_LazyList_nogc_find_val "find(Q const&)"
+ but \p equal is used for key comparing.
+ \p Equal functor has the interface like \p std::equal_to.
+ */
+ template <typename Q, typename Equal, bool Sort = traits::sort>
+ typename std::enable_if<!Sort, value_type *>::type find_with( Q const& key, Equal equal )
+ {
+ CDS_UNUSED( equal );
+ return find_at( &m_Head, key, equal );
+ }
+
/// Clears the list
/**
The function unlink all items from the list.
{
link_checker::is_empty( node_traits::to_node_ptr( val ) );
position pos;
- key_comparator cmp;
+ predicate_type pred;
while ( true ) {
- search( pHead, val, pos, key_comparator() );
+ search( pHead, val, pos, pred );
{
auto_lock_position alp( pos );
if ( validate( pos.pPred, pos.pCur )) {
- if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
+ if ( pos.pCur != &m_Tail && equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) ) {
// failed: key already in list
return false;
}
std::pair<iterator, bool> ensure_at_( node_type * pHead, value_type& val, Func func )
{
position pos;
- key_comparator cmp;
+ predicate_type pred;
while ( true ) {
- search( pHead, val, pos, key_comparator() );
+ search( pHead, val, pos, pred );
{
auto_lock_position alp( pos );
if ( validate( pos.pPred, pos.pCur )) {
- if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
+ if ( pos.pCur != &m_Tail && equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) ) {
// key already in the list
func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
return std::make_pair( ret.first != end(), ret.second );
}
- template <typename Q, typename Compare, typename Func>
- bool find_at( node_type * pHead, Q& val, Compare cmp, Func f )
+ template <typename Q, typename Pred, typename Func>
+ bool find_at( node_type * pHead, Q& val, Pred pred, Func f )
{
position pos;
- search( pHead, val, pos, cmp );
+ search( pHead, val, pos, pred );
if ( pos.pCur != &m_Tail ) {
std::unique_lock< typename node_type::lock_type> al( pos.pCur->m_Lock );
- if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
+ if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) )
{
f( *node_traits::to_value_ptr( *pos.pCur ), val );
return true;
return false;
}
- template <typename Q, typename Compare>
- value_type * find_at( node_type * pHead, Q& val, Compare cmp)
+ template <typename Q, typename Pred>
+ value_type * find_at( node_type * pHead, Q& val, Pred pred)
{
- iterator it = find_at_( pHead, val, cmp );
+ iterator it = find_at_( pHead, val, pred );
if ( it != end() )
return &*it;
return nullptr;
}
- template <typename Q, typename Compare>
- iterator find_at_( node_type * pHead, Q& val, Compare cmp)
+ template <typename Q, typename Pred>
+ iterator find_at_( node_type * pHead, Q& val, Pred pred)
{
position pos;
- search( pHead, val, pos, cmp );
+ search( pHead, val, pos, pred );
if ( pos.pCur != &m_Tail ) {
- if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
+ if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) )
return iterator( pos.pCur );
}
return end();
protected:
//@cond
- template <typename Q, typename Compare>
- void search( node_type * pHead, const Q& key, position& pos, Compare cmp )
+ template <typename Q, typename Equal, bool Sort = traits::sort>
+ typename std::enable_if<!Sort, void>::type search( node_type * pHead, const Q& key, position& pos, Equal eq )
+ {
+ const node_type * pTail = &m_Tail;
+
+ node_type * pCur = pHead;
+ node_type * pPrev = pHead;
+
+ while ( pCur != pTail && ( pCur == pHead || !equal( *node_traits::to_value_ptr( *pCur ), key, eq ) )) {
+ pPrev = pCur;
+ pCur = pCur->m_pNext.load(memory_model::memory_order_acquire);
+ }
+
+ pos.pCur = pCur;
+ pos.pPred = pPrev;
+ }
+
+ template <typename Q, typename Compare, bool Sort = traits::sort>
+ typename std::enable_if<Sort, void>::type search( node_type * pHead, const Q& key, position& pos, Compare cmp )
{
const node_type * pTail = &m_Tail;
pos.pPred = pPrev;
}
+ template <typename L, typename R, typename Equal, bool Sort = traits::sort>
+ static typename std::enable_if<!Sort, bool>::type equal( L const& l, R const& r, Equal eq )
+ {
+ return eq(l, r);
+ }
+
+ template <typename L, typename R, typename Compare, bool Sort = traits::sort>
+ static typename std::enable_if<Sort, bool>::type equal( L const& l, R const& r, Compare cmp )
+ {
+ return cmp(l, r) == 0;
+ }
+
static bool validate( node_type * pPred, node_type * pCur )
{
return pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur;
//@cond
namespace details {
+ template <typename Compare>
+ struct make_equal_to_from_compare
+ {
+ typedef Compare compare_functor;
+
+ template <typename T, typename Q>
+ bool operator()( T const& t, Q const& q ) const
+ {
+ compare_functor cmp;
+ return cmp(t, q) == 0;
+ }
+ };
+
+ template <typename Less>
+ struct make_equal_to_from_less
+ {
+ typedef Less less_functor;
+
+ template <typename T, typename Q>
+ bool operator()( T const& t, Q const& q ) const
+ {
+ less_functor less;
+ return !less(t, q) && !less(q, t);
+ }
+ };
+
template <typename T, typename Traits, bool Forced = true>
struct make_equal_to
{
typedef typename Traits::equal_to equal_to;
+ typedef typename Traits::compare compare;
+ typedef typename Traits::less less;
typedef typename std::conditional<
std::is_same< equal_to, opt::none >::value,
- typename std::conditional< Forced, std::equal_to<T>, opt::none >::type,
- equal_to
- >::type type;
+ typename std::conditional<
+ std::is_same< compare, opt::none >::value,
+ typename std::conditional<
+ std::is_same< less, opt::none >::value,
+ typename std::conditional<
+ Forced,
+ std::equal_to<T>,
+ opt::none >::type,
+ make_equal_to_from_less< less > >::type,
+ make_equal_to_from_compare< compare > >::type,
+ equal_to >::type type;
};
}
//@endcond
tests/test-hdr/ordered_list/hdr_michael_kv_rcu_shb.cpp \
tests/test-hdr/ordered_list/hdr_michael_kv_rcu_sht.cpp
+CDS_TESTHDR_UNORDLIST := \
+ tests/test-hdr/unordered_list/hdr_lazy_nogc.cpp \
+ tests/test-hdr/unordered_list/hdr_lazy_kv_nogc.cpp
+
CDS_TESTHDR_PQUEUE := \
tests/test-hdr/priority_queue/hdr_intrusive_mspqueue_dyn.cpp \
tests/test-hdr/priority_queue/hdr_intrusive_mspqueue_static.cpp \
$(CDS_TESTHDR_MAP) \
$(CDS_TESTHDR_DEQUE) \
$(CDS_TESTHDR_ORDLIST) \
+ $(CDS_TESTHDR_UNORDLIST) \
$(CDS_TESTHDR_SET) \
$(CDS_TESTHDR_TREE) \
$(CDS_TESTHDR_MISC)
-
\ No newline at end of file
+
tests/test-hdr/ordered_list/hdr_intrusive_michael_list_rcu_shb.cpp \
tests/test-hdr/ordered_list/hdr_intrusive_michael_list_rcu_sht.cpp
+CDS_TESTHDR_OFFSETOF_UNORDLIST := \
+ tests/test-hdr/unordered_list/hdr_intrusive_lazy_nogc.cpp
+
CDS_TESTHDR_OFFSETOF_QUEUE := \
tests/test-hdr/queue/hdr_intrusive_basketqueue_hp.cpp \
tests/test-hdr/queue/hdr_intrusive_basketqueue_dhp.cpp \
$(CDS_TESTHDR_OFFSETOF_MAP) \
$(CDS_TESTHDR_OFFSETOF_SET) \
$(CDS_TESTHDR_OFFSETOF_ORDLIST) \
- $(CDS_TESTHDR_OFFSETOF_TREE)
\ No newline at end of file
+ $(CDS_TESTHDR_OFFSETOF_UNORDLIST) \
+ $(CDS_TESTHDR_OFFSETOF_TREE)
}
}
+ template <class Map>
+ void test_int_nogc_unordered()
+ {
+ typedef typename Map::iterator iterator;
+ typedef typename Map::const_iterator const_iterator;
+
+ {
+ Map m( 52, 4 );
+
+ CPPUNIT_ASSERT( m.empty() );
+ CPPUNIT_ASSERT( check_size( m, 0 ));
+
+ CPPUNIT_ASSERT( m.find(10) == m.end() );
+ iterator it = m.insert( 10 );
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( !m.empty() );
+ CPPUNIT_ASSERT( check_size( m, 1 ));
+ CPPUNIT_ASSERT( m.find(10) == it );
+ CPPUNIT_ASSERT( it->first == 10 );
+ CPPUNIT_ASSERT( it->second.m_val == 0 );
+
+ CPPUNIT_ASSERT( m.find(100) == m.end() );
+ it = m.insert( 100, 200 );
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( !m.empty() );
+ CPPUNIT_ASSERT( check_size( m, 2 ));
+ CPPUNIT_ASSERT( m.find_with(100, equal()) == it );
+ CPPUNIT_ASSERT( it->first == 100 );
+ CPPUNIT_ASSERT( it->second.m_val == 200 );
+
+ CPPUNIT_ASSERT( m.find(55) == m.end() );
+ it = m.insert_with( 55, insert_functor<Map>() );
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( !m.empty() );
+ CPPUNIT_ASSERT( check_size( m, 3 ));
+ CPPUNIT_ASSERT( m.find(55) == it );
+ CPPUNIT_ASSERT( it->first == 55 );
+ CPPUNIT_ASSERT( it->second.m_val == 55 * 3 );
+
+ CPPUNIT_ASSERT( m.insert( 55 ) == m.end() );
+ CPPUNIT_ASSERT( m.insert( 55, 10 ) == m.end() );
+ CPPUNIT_ASSERT( m.insert_with( 55, insert_functor<Map>()) == m.end() );
+
+ CPPUNIT_ASSERT( m.find(10) != m.end() );
+ std::pair<iterator, bool> ensureResult = m.ensure( 10 );
+ CPPUNIT_ASSERT( ensureResult.first != m.end() );
+ CPPUNIT_ASSERT( !ensureResult.second );
+ CPPUNIT_ASSERT( !m.empty() );
+ ensureResult.first->second.m_val = ensureResult.first->first * 5;
+ CPPUNIT_ASSERT( check_size( m, 3 ));
+ CPPUNIT_ASSERT( m.find(10) == ensureResult.first );
+ it = m.find(10);
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->second.m_val == 50 );
+
+ CPPUNIT_ASSERT( m.find(120) == m.end() );
+ ensureResult = m.ensure( 120 );
+ CPPUNIT_ASSERT( ensureResult.first != m.end() );
+ CPPUNIT_ASSERT( ensureResult.second );
+ CPPUNIT_ASSERT( !m.empty() );
+ CPPUNIT_ASSERT( check_size( m, 4 ));
+ ensureResult.first->second.m_val = ensureResult.first->first * 5;
+ CPPUNIT_ASSERT( m.find_with(120, equal()) == ensureResult.first );
+ it = m.find_with(120, equal());
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->second.m_val == 120 * 5 );
+ CPPUNIT_ASSERT( m.find_with(120, equal()) == m.find(120) );
+
+ // emplace test
+ it = m.emplace( 151 ) ; // key = 151, val = 0
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->first == 151 );
+ CPPUNIT_ASSERT( it->second.m_val == 0 );
+
+ it = m.emplace( 174, 471 ) ; // key == 174, val = 471
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->first == 174 );
+ CPPUNIT_ASSERT( it->second.m_val == 471 );
+
+ it = m.emplace( 190, value_type(91)) ; // key == 190, val = 19
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->first == 190 );
+ CPPUNIT_ASSERT( it->second.m_val == 91 );
+
+ it = m.emplace( 151, 1051 );
+ CPPUNIT_ASSERT( it == m.end());
+
+ it = m.find( 174 );
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->first == 174 );
+ CPPUNIT_ASSERT( it->second.m_val == 471 );
+
+ it = m.find( 190 );
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->first == 190 );
+ CPPUNIT_ASSERT( it->second.m_val == 91 );
+
+ it = m.find( 151 );
+ CPPUNIT_ASSERT( it != m.end() );
+ CPPUNIT_ASSERT( it->first == 151 );
+ CPPUNIT_ASSERT( it->second.m_val == 0 );
+ }
+
+ // iterator test
+
+ {
+ Map m( 52, 4 );
+
+ for ( int i = 0; i < 500; ++i ) {
+ CPPUNIT_ASSERT( m.insert( i, i * 2 ) != m.end() );
+ }
+ CPPUNIT_ASSERT( check_size( m, 500 ));
+
+ {
+ typename Map::iterator it( m.begin() );
+ typename Map::const_iterator cit( m.cbegin() );
+ CPPUNIT_CHECK( it == cit );
+ CPPUNIT_CHECK( it != m.end() );
+ CPPUNIT_CHECK( it != m.cend() );
+ CPPUNIT_CHECK( cit != m.end() );
+ CPPUNIT_CHECK( cit != m.cend() );
+ ++it;
+ CPPUNIT_CHECK( it != cit );
+ CPPUNIT_CHECK( it != m.end() );
+ CPPUNIT_CHECK( it != m.cend() );
+ CPPUNIT_CHECK( cit != m.end() );
+ CPPUNIT_CHECK( cit != m.cend() );
+ ++cit;
+ CPPUNIT_CHECK( it == cit );
+ CPPUNIT_CHECK( it != m.end() );
+ CPPUNIT_CHECK( it != m.cend() );
+ CPPUNIT_CHECK( cit != m.end() );
+ CPPUNIT_CHECK( cit != m.cend() );
+ }
+
+
+ for ( iterator it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
+ iterator it2 = it;
+ CPPUNIT_CHECK( it2 == it );
+ CPPUNIT_CHECK( it2 != itEnd );
+ CPPUNIT_ASSERT( it->first * 2 == (*it).second.m_val );
+ it->second = it->first;
+ }
+
+ Map const& refMap = m;
+ for ( const_iterator it = refMap.begin(), itEnd = refMap.end(); it != itEnd; ++it ) {
+ CPPUNIT_ASSERT( it->first == it->second.m_val );
+ CPPUNIT_ASSERT( (*it).first == (*it).second.m_val );
+ }
+ }
+ }
+
template <class Map>
void test_iter()
{
void Lazy_nogc_cmp();
void Lazy_nogc_less();
+ void Lazy_nogc_equal();
void Lazy_nogc_cmpmix();
void Split_HP_cmp();
CPPUNIT_TEST(Lazy_nogc_cmp)
CPPUNIT_TEST(Lazy_nogc_less)
+ CPPUNIT_TEST(Lazy_nogc_equal)
CPPUNIT_TEST(Lazy_nogc_cmpmix)
CPPUNIT_TEST(Split_HP_cmp)
typedef HashMapHdrTest::cmp compare;
typedef HashMapHdrTest::less less;
};
+
+ struct nogc_equal_traits: public cc::lazy_list::traits
+ {
+ typedef HashMapHdrTest::equal equal_to;
+ static const bool sort = false;
+ };
}
void HashMapHdrTest::Lazy_nogc_cmp()
test_int_nogc< opt_map >();
}
+ void HashMapHdrTest::Lazy_nogc_equal()
+ {
+ typedef cc::LazyKVList< cds::gc::nogc, int, HashMapHdrTest::value_type, nogc_equal_traits > list;
+
+ // traits-based version
+ typedef cc::MichaelHashMap< cds::gc::nogc, list, map_traits > map;
+ test_int_nogc_unordered< map >();
+
+ // option-based version
+ typedef cc::MichaelHashMap< cds::gc::nogc, list,
+ cc::michael_map::make_traits<
+ cc::opt::hash< hash_int >
+ ,cc::opt::item_counter< simple_item_counter >
+ >::type
+ > opt_map;
+ test_int_nogc_unordered< opt_map >();
+ }
+
void HashMapHdrTest::Lazy_nogc_cmpmix()
{
typedef cc::LazyKVList< cds::gc::nogc, int, HashMapHdrTest::value_type, nogc_cmpmix_traits > list;
typedef HashSetHdrTest::less<HashSetHdrTest::item> less;
};
+ struct nogc_equal_traits: public cc::lazy_list::traits
+ {
+ typedef HashSetHdrTest::equal<HashSetHdrTest::item> equal_to;
+ static const bool sort = false;
+ };
+
struct nogc_cmpmix_traits: public cc::lazy_list::traits
{
typedef HashSetHdrTest::cmp<HashSetHdrTest::item> compare;
test_int_nogc< opt_set >();
}
+ void HashSetHdrTest::Lazy_nogc_equal()
+ {
+ typedef cc::LazyList< cds::gc::nogc, item, nogc_equal_traits > list;
+
+ // traits-based version
+ typedef cc::MichaelHashSet< cds::gc::nogc, list, set_traits > set;
+ test_int_nogc_unordered< set >();
+
+ // option-based version
+ typedef cc::MichaelHashSet< cds::gc::nogc, list,
+ cc::michael_set::make_traits<
+ cc::opt::hash< hash_int >
+ ,cc::opt::item_counter< simple_item_counter >
+ >::type
+ > opt_set;
+ test_int_nogc_unordered< opt_set >();
+ }
+
void HashSetHdrTest::Lazy_nogc_cmpmix()
{
typedef cc::LazyList< cds::gc::nogc, item, nogc_cmpmix_traits > list;
}
}
+ template <class Set>
+ void test_int_nogc_unordered()
+ {
+ typedef typename Set::value_type value_type;
+ typedef typename Set::iterator iterator;
+ typedef typename Set::const_iterator const_iterator;
+
+ {
+ Set s( 52, 4 );
+ iterator it;
+
+ CPPUNIT_ASSERT( s.empty() );
+ CPPUNIT_ASSERT( check_size( s, 0 ));
+
+ // insert
+ it = s.insert( 10 );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 10 );
+ CPPUNIT_ASSERT( it->val() == 10 );
+ CPPUNIT_ASSERT( !s.empty() );
+ CPPUNIT_ASSERT( check_size( s, 1 ));
+ CPPUNIT_ASSERT( s.insert( 10 ) == s.end() );
+
+ it = s.insert( std::make_pair( 50, 25 ));
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 50 );
+ CPPUNIT_ASSERT( it->val() == 25 );
+ CPPUNIT_ASSERT( !s.empty() );
+ CPPUNIT_ASSERT( check_size( s, 2 ));
+ CPPUNIT_ASSERT( s.insert( 50 ) == s.end() );
+
+ // ensure
+ std::pair< iterator, bool> ensureResult;
+ ensureResult = s.ensure( 20 );
+ CPPUNIT_ASSERT( ensureResult.first != s.end() );
+ CPPUNIT_ASSERT( ensureResult.second );
+ CPPUNIT_ASSERT( ensureResult.first->key() == 20 );
+ CPPUNIT_ASSERT( ensureResult.first->val() == 20 );
+ CPPUNIT_ASSERT( !s.empty() );
+ CPPUNIT_ASSERT( check_size( s, 3 ));
+
+ ensureResult = s.ensure( std::make_pair( 20, 200 ));
+ CPPUNIT_ASSERT( ensureResult.first != s.end() );
+ CPPUNIT_ASSERT( !ensureResult.second );
+ CPPUNIT_ASSERT( ensureResult.first->key() == 20 );
+ CPPUNIT_ASSERT( ensureResult.first->val() == 20 );
+ CPPUNIT_ASSERT( !s.empty() );
+ CPPUNIT_ASSERT( check_size( s, 3 ));
+ ensureResult.first->nVal = 22;
+
+ ensureResult = s.ensure( std::make_pair( 30, 33 ));
+ CPPUNIT_ASSERT( ensureResult.first != s.end() );
+ CPPUNIT_ASSERT( ensureResult.second );
+ CPPUNIT_ASSERT( ensureResult.first->key() == 30 );
+ CPPUNIT_ASSERT( ensureResult.first->val() == 33 );
+ CPPUNIT_ASSERT( !s.empty() );
+ CPPUNIT_ASSERT( check_size( s, 4 ));
+
+ // find
+ it = s.find( 10 );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 10 );
+ CPPUNIT_ASSERT( it->val() == 10 );
+
+ it = s.find_with( 20, equal<value_type>() );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 20 );
+ CPPUNIT_ASSERT( it->val() == 22 );
+
+ it = s.find( 30 );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 30 );
+ CPPUNIT_ASSERT( it->val() == 33 );
+
+ it = s.find( 40 );
+ CPPUNIT_ASSERT( it == s.end() );
+
+ it = s.find( 50 );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 50 );
+ CPPUNIT_ASSERT( it->val() == 25 );
+
+ // emplace test
+ it = s.emplace( 151 ) ; // key = 151, val = 151
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 151 );
+ CPPUNIT_ASSERT( it->val() == 151 );
+
+ it = s.emplace( 174, 471 ) ; // key == 174, val = 471
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 174 );
+ CPPUNIT_ASSERT( it->val() == 471 );
+
+ it = s.emplace( std::make_pair( 190, 91 )) ; // key == 190, val = 91
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 190 );
+ CPPUNIT_ASSERT( it->val() == 91 );
+
+ it = s.find( 174 );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 174 );
+ CPPUNIT_ASSERT( it->val() == 471 );
+
+ it = s.find_with( 190, equal<value_type>() );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 190 );
+ CPPUNIT_ASSERT( it->val() == 91 );
+
+ it = s.find( 151 );
+ CPPUNIT_ASSERT( it != s.end() );
+ CPPUNIT_ASSERT( it->key() == 151 );
+ CPPUNIT_ASSERT( it->val() == 151 );
+
+ //s.clear();
+ //CPPUNIT_ASSERT( s.empty() );
+ //CPPUNIT_ASSERT( check_size( s, 0 ));
+ }
+
+ {
+ Set s( 52, 4 );
+
+ // iterator test
+ for ( int i = 0; i < 500; ++i ) {
+ CPPUNIT_ASSERT( s.insert( std::make_pair( i, i * 2) ) != s.end() );
+ }
+ for ( iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
+ iterator it2 = it;
+ CPPUNIT_CHECK( it2 == it );
+ CPPUNIT_CHECK( it2 != itEnd );
+ CPPUNIT_ASSERT( (*it).nKey * 2 == it->nVal );
+ it->nVal = (*it).nKey;
+ }
+
+ Set const& refSet = s;
+ for ( const_iterator it = refSet.begin(), itEnd = refSet.end(); it != itEnd; ++it ) {
+ CPPUNIT_ASSERT( (*it).nKey == it->nVal );
+ }
+ }
+ }
template <class Set>
void test_iter()
{
void Lazy_nogc_cmp();
void Lazy_nogc_less();
+ void Lazy_nogc_equal();
void Lazy_nogc_cmpmix();
void Split_HP_cmp();
CPPUNIT_TEST(Lazy_nogc_cmp)
CPPUNIT_TEST(Lazy_nogc_less)
+ CPPUNIT_TEST(Lazy_nogc_equal)
CPPUNIT_TEST(Lazy_nogc_cmpmix)
CPPUNIT_TEST(Split_HP_cmp)
--- /dev/null
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_INTRUSIVE_LAZY_H
+#define CDSTEST_HDR_INTRUSIVE_LAZY_H
+
+#include "cppunit/cppunit_proxy.h"
+#include <cds/intrusive/details/lazy_list_base.h>
+
+namespace unordlist {
+ namespace ci = cds::intrusive;
+ namespace co = cds::opt;
+
+ struct stat {
+ int nDisposeCount;
+ int nEnsureExistsCall;
+ int nEnsureNewCall;
+ int nFindCall;
+ int nEraseCall;
+
+ stat()
+ : nDisposeCount(0)
+ , nEnsureExistsCall(0)
+ , nEnsureNewCall(0)
+ , nFindCall(0)
+ , nEraseCall(0)
+ {}
+
+ stat( const stat& s )
+ {
+ *this = s;
+ }
+
+ stat& operator =(const stat& s)
+ {
+ memcpy( this, &s, sizeof(s));
+ return *this;
+ }
+ };
+
+ template <typename GC>
+ struct base_int_item: public ci::lazy_list::node< GC >
+ {
+ int nKey;
+ int nVal;
+
+ mutable stat s;
+
+ base_int_item()
+ {}
+
+ base_int_item(int key, int val)
+ : nKey( key )
+ , nVal(val)
+ , s()
+ {}
+
+ base_int_item(const base_int_item& v )
+ : nKey( v.nKey )
+ , nVal( v.nVal )
+ , s()
+ {}
+
+ const int& key() const
+ {
+ return nKey;
+ }
+
+ operator int() const
+ { return nKey; }
+ };
+
+ template <typename GC>
+ struct member_int_item
+ {
+ int nKey;
+ int nVal;
+
+ ci::lazy_list::node< GC > hMember;
+
+ mutable stat s;
+
+ member_int_item()
+ {}
+
+ member_int_item(int key, int val)
+ : nKey( key )
+ , nVal(val)
+ , s()
+ {}
+
+ member_int_item(const member_int_item& v )
+ : nKey( v.nKey )
+ , nVal( v.nVal )
+ , s()
+ {}
+
+ const int& key() const
+ {
+ return nKey;
+ }
+
+ operator int() const
+ { return nKey; }
+ };
+
+ template <typename T>
+ struct less
+ {
+ bool operator ()(const T& v1, const T& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+
+ template <typename Q>
+ bool operator ()(const T& v1, const Q& v2 ) const
+ {
+ return v1.key() < v2;
+ }
+
+ template <typename Q>
+ bool operator ()(const Q& v1, const T& v2 ) const
+ {
+ return v1 < v2.key();
+ }
+ };
+
+ template <typename T>
+ struct cmp {
+ int operator ()(const T& v1, const T& v2 ) const
+ {
+ if ( v1.key() < v2.key() )
+ return -1;
+ return v1.key() > v2.key() ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()(const T& v1, const Q& v2 ) const
+ {
+ if ( v1.key() < v2 )
+ return -1;
+ return v1.key() > v2 ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()(const Q& v1, const T& v2 ) const
+ {
+ if ( v1 < v2.key() )
+ return -1;
+ return v1 > v2.key() ? 1 : 0;
+ }
+ };
+
+ template <typename T>
+ struct equal_to {
+ bool operator()( T const& l, T const& r ) const
+ {
+ return l.key() == r.key();
+ }
+
+ template <typename Q>
+ bool operator()( Q const& l, T const& r ) const
+ {
+ return l == r.key();
+ }
+
+ template <typename Q>
+ bool operator()( T const& l, Q const& r ) const
+ {
+ return l.key() == r;
+ }
+ };
+
+ struct faked_disposer
+ {
+ template <typename T>
+ void operator ()( T * p )
+ {
+ ++p->s.nDisposeCount;
+ }
+ };
+
+ struct ensure_functor
+ {
+ template <typename T>
+ void operator ()(bool bNew, T& item, T& /*val*/ )
+ {
+ if ( bNew )
+ ++item.s.nEnsureNewCall;
+ else
+ ++item.s.nEnsureExistsCall;
+ }
+ };
+
+ struct find_functor
+ {
+ template <typename T, typename Q>
+ void operator ()( T& item, Q& /*val*/ )
+ {
+ ++item.s.nFindCall;
+ }
+ };
+
+ class UnorderedIntrusiveLazyListHeaderTest: public CppUnitMini::TestCase
+ {
+ public:
+ template <class UnordList>
+ void test_nogc_int()
+ {
+ typedef typename UnordList::value_type value_type;
+ {
+ value_type v1( 10, 50 );
+ value_type v2( 5, 25 );
+ value_type v3( 20, 100 );
+ {
+ UnordList l;
+ CPPUNIT_ASSERT( l.empty() );
+
+ CPPUNIT_ASSERT( l.insert( v1 )); // true
+ CPPUNIT_ASSERT( l.find( v1.key() ) == &v1 );
+
+ CPPUNIT_ASSERT( v1.s.nFindCall == 0 );
+ CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
+ CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
+
+ CPPUNIT_ASSERT( l.find_with( v2.key(), equal_to<value_type>() ) == nullptr );
+ CPPUNIT_ASSERT( l.find( v3.key() ) == nullptr );
+ CPPUNIT_ASSERT( !l.empty() );
+
+ //CPPUNIT_ASSERT( !l.insert( v1 )) ; // assertion "is_empty" is raised
+
+ {
+ value_type v( v1 );
+ CPPUNIT_ASSERT( !l.insert( v )) ; // false
+ }
+
+ std::pair<bool, bool> ret = l.ensure( v2, ensure_functor() );
+ CPPUNIT_ASSERT( ret.first );
+ CPPUNIT_ASSERT( ret.second );
+ CPPUNIT_ASSERT( v2.s.nEnsureNewCall == 1 );
+ CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 0 );
+
+ //CPPUNIT_ASSERT( !l.insert( v2 )) ; // assertion "is_empty"
+
+ CPPUNIT_ASSERT( l.find( v1.key() ) == &v1 ) ; // true
+
+ CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
+ CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
+ CPPUNIT_ASSERT( v1.s.nFindCall == 2 );
+
+ CPPUNIT_ASSERT( l.find_with( v2.key(), equal_to<value_type>() ) == &v2 );
+
+ CPPUNIT_ASSERT( v2.s.nFindCall == 0 );
+ CPPUNIT_ASSERT( l.find_with( v2.key(), equal_to<value_type>(), find_functor() ));
+ CPPUNIT_ASSERT( v2.s.nFindCall == 1 );
+
+ CPPUNIT_ASSERT( !l.find( v3.key() ));
+
+ {
+ value_type v( v2 );
+ ret = l.ensure( v, ensure_functor() );
+
+ CPPUNIT_ASSERT( ret.first );
+ CPPUNIT_ASSERT( !ret.second );
+ CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 1 );
+ CPPUNIT_ASSERT( v.s.nEnsureExistsCall == 0 && v.s.nEnsureNewCall == 0 );
+ }
+
+ CPPUNIT_ASSERT( !l.empty() );
+
+ CPPUNIT_ASSERT( l.insert( v3 )) ; // true
+ CPPUNIT_ASSERT( l.find( v3.key() ) == &v3 );
+
+ CPPUNIT_ASSERT( v3.s.nFindCall == 0 );
+ CPPUNIT_ASSERT( l.find( v3.key(), find_functor() ));
+ CPPUNIT_ASSERT( v3.s.nFindCall == 1 );
+
+ {
+ typename UnordList::iterator it = l.begin();
+ typename UnordList::const_iterator cit = l.cbegin();
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it != l.cend() );
+ CPPUNIT_ASSERT( cit != l.end() );
+ CPPUNIT_ASSERT( cit != l.cend() );
+ CPPUNIT_ASSERT( cit == it );
+
+ CPPUNIT_ASSERT( it->nKey == v1.nKey );
+ CPPUNIT_ASSERT( it->nVal == v1.nVal );
+ CPPUNIT_ASSERT( ++it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == v2.nKey );
+ CPPUNIT_ASSERT( it->nVal == v2.nVal );
+ CPPUNIT_ASSERT( it++ != l.end() );
+ CPPUNIT_ASSERT( it->nKey == v3.nKey );
+ CPPUNIT_ASSERT( it->nVal == v3.nVal );
+ CPPUNIT_ASSERT( it++ != l.end() );
+ CPPUNIT_ASSERT( it == l.end() );
+ }
+
+ {
+ UnordList const & lref = l;
+ typename UnordList::const_iterator it = lref.begin();
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == v1.nKey );
+ CPPUNIT_ASSERT( it->nVal == v1.nVal );
+ CPPUNIT_ASSERT( ++it != lref.end() );
+ CPPUNIT_ASSERT( it->nKey == v2.nKey );
+ CPPUNIT_ASSERT( it->nVal == v2.nVal );
+ CPPUNIT_ASSERT( it++ != l.end() );
+ CPPUNIT_ASSERT( it->nKey == v3.nKey );
+ CPPUNIT_ASSERT( it->nVal == v3.nVal );
+ CPPUNIT_ASSERT( it++ != lref.end() );
+ CPPUNIT_ASSERT( it == l.end() );
+ }
+ }
+
+ // Disposer called on list destruction
+ CPPUNIT_ASSERT( v1.s.nDisposeCount == 1 );
+ CPPUNIT_ASSERT( v2.s.nDisposeCount == 1 );
+ CPPUNIT_ASSERT( v3.s.nDisposeCount == 1 );
+ }
+ }
+
+ void nogc_base_cmp();
+ void nogc_base_less();
+ void nogc_base_equal_to();
+ void nogc_base_cmpmix();
+ void nogc_base_equal_to_mix();
+ void nogc_base_ic();
+ void nogc_member_cmp();
+ void nogc_member_less();
+ void nogc_member_equal_to();
+ void nogc_member_cmpmix();
+ void nogc_member_equal_to_mix();
+ void nogc_member_ic();
+
+ CPPUNIT_TEST_SUITE(UnorderedIntrusiveLazyListHeaderTest)
+
+ CPPUNIT_TEST(nogc_base_cmp)
+ CPPUNIT_TEST(nogc_base_less)
+ CPPUNIT_TEST(nogc_base_equal_to)
+ CPPUNIT_TEST(nogc_base_cmpmix)
+ CPPUNIT_TEST(nogc_base_equal_to_mix)
+ CPPUNIT_TEST(nogc_base_ic)
+ CPPUNIT_TEST(nogc_member_cmp)
+ CPPUNIT_TEST(nogc_member_less)
+ CPPUNIT_TEST(nogc_member_equal_to)
+ CPPUNIT_TEST(nogc_member_cmpmix)
+ CPPUNIT_TEST(nogc_member_equal_to_mix)
+ CPPUNIT_TEST(nogc_member_ic)
+
+ CPPUNIT_TEST_SUITE_END()
+ };
+} // namespace unordlist
+
+#endif // #ifndef CDSTEST_HDR_INTRUSIVE_LAZY_H
--- /dev/null
+//$$CDS-header$$
+
+#include "unordered_list/hdr_intrusive_lazy.h"
+#include <cds/intrusive/lazy_list_nogc.h>
+
+namespace unordlist {
+ namespace {
+ typedef base_int_item< cds::gc::nogc > base_item;
+ typedef member_int_item< cds::gc::nogc > member_item;
+
+ struct cmp_traits : public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< co::gc<cds::gc::nogc> > hook;
+ typedef unordlist::cmp<base_item> compare;
+ typedef faked_disposer disposer;
+ static const bool sort = false;
+ };
+
+ struct less_traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< co::gc<cds::gc::nogc> > hook;
+ typedef unordlist::less<base_item> less;
+ typedef faked_disposer disposer;
+ static const bool sort = false;
+ };
+
+ struct equal_to_traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< co::gc<cds::gc::nogc> > hook;
+ typedef unordlist::equal_to<base_item> equal_to;
+ typedef faked_disposer disposer;
+ static const bool sort = false;
+ };
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::base_hook< co::gc<cds::gc::nogc> > >
+ ,co::less< less<base_item> >
+ ,co::compare< cmp<base_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type cmpmix_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::base_hook< co::gc<cds::gc::nogc> > >
+ ,co::compare< cmp<base_item> >
+ ,co::equal_to< equal_to<base_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type equal_to_mix_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::base_hook< co::gc<cds::gc::nogc> > >
+ ,co::equal_to< equal_to<base_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::item_counter< cds::atomicity::item_counter >
+ ,co::sort< false > >::type ic_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::member_hook<
+ offsetof( member_item, hMember )
+ ,co::gc<cds::gc::nogc> > >
+ ,co::compare< cmp<member_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type member_cmp_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::member_hook<
+ offsetof( member_item, hMember )
+ ,co::gc<cds::gc::nogc> > >
+ ,co::less< less<member_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type member_less_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::member_hook<
+ offsetof( member_item, hMember )
+ ,co::gc<cds::gc::nogc> > >
+ ,co::equal_to< equal_to<member_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type member_equal_to_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::member_hook<
+ offsetof( member_item, hMember )
+ ,co::gc<cds::gc::nogc> > >
+ ,co::less< less<member_item> >
+ ,co::compare< cmp<member_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type member_cmpmix_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::member_hook<
+ offsetof( member_item, hMember )
+ ,co::gc<cds::gc::nogc> > >
+ ,co::compare< cmp<member_item> >
+ ,co::equal_to< equal_to<member_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::sort< false > >::type member_equal_to_mix_traits;
+
+ typedef typename ci::lazy_list::make_traits<
+ ci::opt::hook< ci::lazy_list::member_hook<
+ offsetof( member_item, hMember ),
+ co::gc<cds::gc::nogc> > >
+ ,co::equal_to< equal_to<member_item> >
+ ,ci::opt::disposer< faked_disposer >
+ ,co::item_counter< cds::atomicity::item_counter >
+ ,co::sort< false > >::type member_ic_traits;
+
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_base_cmp()
+ {
+ typedef ci::LazyList< cds::gc::nogc, base_item, cmp_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_base_less()
+ {
+ typedef ci::LazyList< cds::gc::nogc, base_item, less_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_base_equal_to()
+ {
+ typedef ci::LazyList< cds::gc::nogc, base_item, equal_to_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_base_cmpmix()
+ {
+ typedef ci::LazyList< cds::gc::nogc, base_item, cmpmix_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_base_equal_to_mix()
+ {
+ typedef ci::LazyList< cds::gc::nogc, base_item, equal_to_mix_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_base_ic()
+ {
+ typedef ci::LazyList< cds::gc::nogc, base_item, ic_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_member_cmp()
+ {
+ typedef ci::LazyList< cds::gc::nogc, member_item, member_cmp_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_member_less()
+ {
+ typedef ci::LazyList< cds::gc::nogc, member_item, member_less_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_member_equal_to()
+ {
+ typedef ci::LazyList< cds::gc::nogc, member_item, member_equal_to_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_member_cmpmix()
+ {
+ typedef ci::LazyList< cds::gc::nogc, member_item, member_cmpmix_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_member_equal_to_mix()
+ {
+ typedef ci::LazyList< cds::gc::nogc, member_item, member_equal_to_mix_traits > list;
+ test_nogc_int<list>();
+ }
+ void UnorderedIntrusiveLazyListHeaderTest::nogc_member_ic()
+ {
+ typedef ci::LazyList< cds::gc::nogc, member_item, member_ic_traits > list;
+ test_nogc_int<list>();
+ }
+
+} // namespace unordlist
+
+CPPUNIT_TEST_SUITE_REGISTRATION(unordlist::UnorderedIntrusiveLazyListHeaderTest);
--- /dev/null
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_LAZY_H
+#define CDSTEST_HDR_LAZY_H
+
+#include "cppunit/cppunit_proxy.h"
+#include <cds/container/details/lazy_list_base.h>
+
+namespace unordlist {
+ namespace cc = cds::container;
+ namespace co = cds::container::opt;
+
+ class UnorderedLazyListTestHeader: public CppUnitMini::TestCase
+ {
+ public:
+ struct stat {
+ int nEnsureExistsCall;
+ int nEnsureNewCall;
+
+ stat()
+ {
+ nEnsureExistsCall
+ = nEnsureNewCall
+ = 0;
+ }
+ };
+
+ struct item {
+ int nKey;
+ int nVal;
+
+ stat s;
+
+ item(int key)
+ : nKey( key )
+ , nVal( key * 2 )
+ , s()
+ {}
+
+ item(int key, int val)
+ : nKey( key )
+ , nVal(val)
+ , s()
+ {}
+
+ item( item const& v )
+ : nKey( v.nKey )
+ , nVal( v.nVal )
+ , s()
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ template <typename T>
+ struct lt
+ {
+ bool operator ()(const T& v1, const T& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+
+ template <typename Q>
+ bool operator ()(const T& v1, const Q& v2 ) const
+ {
+ return v1.key() < v2;
+ }
+
+ template <typename Q>
+ bool operator ()(const Q& v1, const T& v2 ) const
+ {
+ return v1 < v2.key();
+ }
+ };
+
+ template <typename T>
+ struct cmp {
+ int operator ()(const T& v1, const T& v2 ) const
+ {
+ if ( v1.key() < v2.key() )
+ return -1;
+ return v1.key() > v2.key() ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()(const T& v1, const Q& v2 ) const
+ {
+ if ( v1.key() < v2 )
+ return -1;
+ return v1.key() > v2 ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()(const Q& v1, const T& v2 ) const
+ {
+ if ( v1 < v2.key() )
+ return -1;
+ return v1 > v2.key() ? 1 : 0;
+ }
+ };
+
+ template <typename T>
+ struct equal_to {
+ int operator ()(const T& v1, const T& v2 ) const
+ {
+ return v1.key() == v2.key();
+ }
+
+ template <typename Q>
+ int operator ()(const T& v1, const Q& v2 ) const
+ {
+ return v1.key() == v2;
+ }
+
+ template <typename Q>
+ int operator ()(const Q& v1, const T& v2 ) const
+ {
+ return v1 == v2.key();
+ }
+ };
+
+ protected:
+ template <class UnordList>
+ void nogc_test()
+ {
+ typedef UnordList list;
+ typedef typename list::value_type value_type;
+ typedef std::pair<typename list::iterator, bool> ensure_result;
+
+ typename list::iterator it;
+
+ list l;
+ CPPUNIT_ASSERT( l.empty() );
+ CPPUNIT_ASSERT( l.insert(50) != l.end() );
+ CPPUNIT_ASSERT( !l.empty() );
+
+ ensure_result eres = l.ensure( item(100, 33) );
+ CPPUNIT_ASSERT( eres.second );
+ CPPUNIT_ASSERT( eres.first != l.end() );
+ CPPUNIT_ASSERT( l.insert( item(150) ) != l.end() );
+
+ CPPUNIT_ASSERT( l.insert(100) == l.end() );
+ eres = l.ensure( item(50, 33) );
+ CPPUNIT_ASSERT( !eres.second );
+ CPPUNIT_ASSERT( eres.first->nVal == eres.first->nKey * 2 );
+ eres.first->nVal = 63;
+
+ it = l.find( 33 );
+ CPPUNIT_ASSERT( it == l.end() );
+
+ it = l.find( 50 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == 50 );
+ CPPUNIT_ASSERT( it->nVal == 63 );
+
+ it = l.find( 100 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == 100 );
+ CPPUNIT_ASSERT( it->nVal == 33 );
+
+ it = l.find_with( 150, equal_to<value_type>() );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == 150 );
+ CPPUNIT_ASSERT( it->nVal == it->nKey * 2 );
+
+ CPPUNIT_ASSERT( !l.empty() );
+ l.clear();
+ CPPUNIT_ASSERT( l.empty() );
+
+ // insert test
+ CPPUNIT_ASSERT( l.emplace( 501 ) != l.end());
+ CPPUNIT_ASSERT( l.emplace( 251, 152 ) != l.end());
+ CPPUNIT_ASSERT( l.emplace( item( 1001 )) != l.end());
+
+ // insert failed - such key exists
+ CPPUNIT_ASSERT( l.emplace( 501, 2 ) == l.end());
+ CPPUNIT_ASSERT( l.emplace( 251, 10) == l.end());
+
+ it = l.find( 501 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == 501 );
+ CPPUNIT_ASSERT( it->nVal == 501 * 2 );
+
+ it = l.find( 1001 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it->nKey == 1001 );
+ CPPUNIT_ASSERT( it->nVal == 1001 * 2 );
+
+ {
+ typename UnordList::iterator it( l.begin() );
+ typename UnordList::const_iterator cit( l.cbegin() );
+ CPPUNIT_CHECK( it == cit );
+ CPPUNIT_CHECK( it != l.end() );
+ CPPUNIT_CHECK( it != l.cend() );
+ CPPUNIT_CHECK( cit != l.end() );
+ CPPUNIT_CHECK( cit != l.cend() );
+ ++it;
+ CPPUNIT_CHECK( it != cit );
+ CPPUNIT_CHECK( it != l.end() );
+ CPPUNIT_CHECK( it != l.cend() );
+ CPPUNIT_CHECK( cit != l.end() );
+ CPPUNIT_CHECK( cit != l.cend() );
+ ++cit;
+ CPPUNIT_CHECK( it == cit );
+ CPPUNIT_CHECK( it != l.end() );
+ CPPUNIT_CHECK( it != l.cend() );
+ CPPUNIT_CHECK( cit != l.end() );
+ CPPUNIT_CHECK( cit != l.cend() );
+ }
+
+
+ l.clear();
+ CPPUNIT_ASSERT( l.empty() );
+ }
+
+ void NOGC_cmp();
+ void NOGC_less();
+ void NOGC_equal_to();
+ void NOGC_cmpmix();
+ void NOGC_equal_to_mix();
+ void NOGC_ic();
+
+ CPPUNIT_TEST_SUITE(UnorderedLazyListTestHeader)
+ CPPUNIT_TEST(NOGC_cmp)
+ CPPUNIT_TEST(NOGC_less)
+ CPPUNIT_TEST(NOGC_equal_to)
+ CPPUNIT_TEST(NOGC_cmpmix)
+ CPPUNIT_TEST(NOGC_equal_to_mix)
+ CPPUNIT_TEST(NOGC_ic)
+ CPPUNIT_TEST_SUITE_END()
+ };
+
+} // namespace unordlist
+
+#endif // #ifndef CDSTEST_HDR_LAZY_H
--- /dev/null
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_LAZY_KV_H
+#define CDSTEST_HDR_LAZY_KV_H
+
+#include "cppunit/cppunit_proxy.h"
+#include <cds/container/details/lazy_list_base.h>
+
+namespace unordlist {
+ namespace cc = cds::container;
+ namespace co = cds::container::opt;
+
+ class UnorderedLazyKVListTestHeader: public CppUnitMini::TestCase
+ {
+ public:
+ typedef int key_type;
+ struct value_type {
+ int m_val;
+
+ value_type()
+ : m_val(0)
+ {}
+
+ value_type( int n )
+ : m_val( n )
+ {}
+ };
+
+ template <typename T>
+ struct lt
+ {
+ bool operator ()(const T& v1, const T& v2 ) const
+ {
+ return v1 < v2;
+ }
+ };
+
+ template <typename T>
+ struct cmp {
+ int operator ()(const T& v1, const T& v2 ) const
+ {
+ if ( v1 < v2 )
+ return -1;
+ return v1 > v2 ? 1 : 0;
+ }
+ };
+
+ template <typename T>
+ struct eq {
+ bool operator ()(const T& v1, const T& v2 ) const
+ {
+ return v1 == v2;
+ }
+ };
+
+ struct insert_functor {
+ template <typename T>
+ void operator()( T& pair )
+ {
+ pair.second.m_val = pair.first * 10;
+ }
+ };
+
+ protected:
+ template <class UnordList>
+ void nogc_test()
+ {
+ typedef typename UnordList::value_type value_type;
+ typedef typename UnordList::iterator iterator;
+
+ {
+ UnordList l;
+ iterator it;
+
+ CPPUNIT_ASSERT( l.empty() );
+
+ // insert / find test
+ CPPUNIT_ASSERT( l.find( 100 ) == l.end() );
+ CPPUNIT_ASSERT( l.insert( 100 ) != l.end() );
+ CPPUNIT_ASSERT( !l.empty() );
+ it = l.find( 100 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 100 );
+ CPPUNIT_ASSERT( it.val().m_val == 0 );
+
+ CPPUNIT_ASSERT( l.find_with( 50, eq<key_type>() ) == l.end() );
+ CPPUNIT_ASSERT( l.insert( 50, 500 ) != l.end());
+ it = l.find( 50 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 50 );
+ CPPUNIT_ASSERT( it.val().m_val == 500 );
+
+ CPPUNIT_ASSERT( l.insert( 50, 5 ) == l.end() );
+ it = l.find( 50 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 50 );
+ CPPUNIT_ASSERT( it.val().m_val == 500 );
+ CPPUNIT_ASSERT( !l.empty() );
+
+ CPPUNIT_ASSERT( l.find( 150 ) == l.end() );
+ CPPUNIT_ASSERT( l.insert_with( 150, insert_functor() ) != l.end() );
+ it = l.find( 150 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 150 );
+ CPPUNIT_ASSERT( it.val().m_val == 1500 );
+ it = l.find( 100 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 100 );
+ CPPUNIT_ASSERT( it.val().m_val == 0 );
+ it = l.find( 50 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 50 );
+ CPPUNIT_ASSERT( it.val().m_val == 500 );
+ it.val().m_val = 25;
+ it = l.find( 50 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 50 );
+ CPPUNIT_ASSERT( it.val().m_val == 25 );
+ CPPUNIT_ASSERT( !l.empty() );
+
+ // ensure existing item
+ std::pair<iterator, bool> ensureResult;
+ ensureResult = l.ensure( 100 );
+ CPPUNIT_ASSERT( !ensureResult.second );
+ CPPUNIT_ASSERT( ensureResult.first.key() == 100 );
+ CPPUNIT_ASSERT( ensureResult.first.val().m_val == 0 );
+ ensureResult.first.val().m_val = 5;
+ it = l.find( 100 );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 100 );
+ CPPUNIT_ASSERT( it.val().m_val == 5 );
+
+ CPPUNIT_ASSERT( !l.empty() );
+
+ // ensure new item
+ ensureResult = l.ensure( 1000 );
+ CPPUNIT_ASSERT( ensureResult.second );
+ CPPUNIT_ASSERT( ensureResult.first.key() == 1000 );
+ CPPUNIT_ASSERT( ensureResult.first.val().m_val == 0 );
+ ensureResult.first.val().m_val = 33;
+ ensureResult = l.ensure( 1000 );
+ CPPUNIT_ASSERT( !ensureResult.second );
+ CPPUNIT_ASSERT( ensureResult.first.key() == 1000 );
+ CPPUNIT_ASSERT( ensureResult.first.val().m_val == 33 );
+
+ // clear test
+ l.clear();
+ CPPUNIT_ASSERT( l.empty() );
+
+ // insert test
+ CPPUNIT_ASSERT( l.emplace( 501 ) != l.end());
+ CPPUNIT_ASSERT( l.emplace( 251, 152 ) != l.end());
+
+ // insert failed - such key exists
+ CPPUNIT_ASSERT( l.emplace( 501, 2 ) == l.end());
+ CPPUNIT_ASSERT( l.emplace( 251, 10) == l.end());
+
+ it = l.find(501);
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 501 );
+ CPPUNIT_ASSERT( it.val().m_val == 0 );
+
+ it = l.find(251);
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == 251 );
+ CPPUNIT_ASSERT( it.val().m_val == 152 );
+
+ l.clear();
+ CPPUNIT_ASSERT( l.empty() );
+
+ // Iterator test
+ {
+ int nCount = 100;
+ for ( int i = 0; i < nCount; ++i )
+ CPPUNIT_ASSERT( l.insert(i, i * 2 ) != l.end() );
+
+ {
+ typename UnordList::iterator it( l.begin() );
+ typename UnordList::const_iterator cit( l.cbegin() );
+ CPPUNIT_CHECK( it == cit );
+ CPPUNIT_CHECK( it != l.end() );
+ CPPUNIT_CHECK( it != l.cend() );
+ CPPUNIT_CHECK( cit != l.end() );
+ CPPUNIT_CHECK( cit != l.cend() );
+ ++it;
+ CPPUNIT_CHECK( it != cit );
+ CPPUNIT_CHECK( it != l.end() );
+ CPPUNIT_CHECK( it != l.cend() );
+ CPPUNIT_CHECK( cit != l.end() );
+ CPPUNIT_CHECK( cit != l.cend() );
+ ++cit;
+ CPPUNIT_CHECK( it == cit );
+ CPPUNIT_CHECK( it != l.end() );
+ CPPUNIT_CHECK( it != l.cend() );
+ CPPUNIT_CHECK( cit != l.end() );
+ CPPUNIT_CHECK( cit != l.cend() );
+ }
+
+ int i = 0;
+ for ( typename UnordList::iterator iter = l.begin(), itEnd = l.end(); iter != itEnd; ++iter, ++i ) {
+ CPPUNIT_ASSERT( iter.key() == i );
+ CPPUNIT_ASSERT( iter->first == i );
+ CPPUNIT_ASSERT( (*iter).first == i );
+
+ CPPUNIT_ASSERT( iter.val().m_val == i * 2 );
+ CPPUNIT_ASSERT( iter->second.m_val == i * 2 );
+ CPPUNIT_ASSERT( (*iter).second.m_val == i * 2 );
+
+ iter.val().m_val = i * 3;
+ }
+
+ // Check that we have visited all items
+ for ( int i = 0; i < nCount; ++i ) {
+ it = l.find( i );
+ CPPUNIT_ASSERT( it != l.end() );
+ CPPUNIT_ASSERT( it.key() == i );
+ CPPUNIT_ASSERT( it.val().m_val == i * 3 );
+ }
+
+ l.clear();
+ CPPUNIT_ASSERT( l.empty() );
+
+ // Const iterator
+ for ( int i = 0; i < nCount; ++i )
+ CPPUNIT_ASSERT( l.insert(i, i * 7) != l.end() );
+
+ i = 0;
+ const UnordList& rl = l;
+ for ( typename UnordList::const_iterator iter = rl.begin(), itEnd = rl.end(); iter != itEnd; ++iter, ++i ) {
+ CPPUNIT_ASSERT( iter.key() == i );
+ CPPUNIT_ASSERT( iter->first == i );
+ CPPUNIT_ASSERT( (*iter).first == i );
+
+ CPPUNIT_ASSERT( iter.val().m_val == i * 7 );
+ CPPUNIT_ASSERT( iter->second.m_val == i * 7 );
+ CPPUNIT_ASSERT( (*iter).second.m_val == i * 7 );
+ // it.val().m_val = i * 3 ; // error: const-iterator
+ }
+
+ l.clear();
+ CPPUNIT_ASSERT( l.empty() );
+ }
+
+ }
+ }
+
+ void NOGC_cmp();
+ void NOGC_less();
+ void NOGC_equal_to();
+ void NOGC_cmpmix();
+ void NOGC_ic();
+
+ CPPUNIT_TEST_SUITE(UnorderedLazyKVListTestHeader)
+ CPPUNIT_TEST(NOGC_cmp)
+ CPPUNIT_TEST(NOGC_less)
+ CPPUNIT_TEST(NOGC_equal_to)
+ CPPUNIT_TEST(NOGC_cmpmix)
+ CPPUNIT_TEST(NOGC_ic)
+ CPPUNIT_TEST_SUITE_END()
+ };
+
+} // namespace unordlist
+
+#endif // #ifndef CDSTEST_HDR_LAZY_KV_H
--- /dev/null
+//$$CDS-header$$
+
+#include "unordered_list/hdr_lazy_kv.h"
+#include <cds/container/lazy_kvlist_nogc.h>
+
+namespace unordlist {
+ namespace {
+ struct NOGC_cmp_traits: public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyKVListTestHeader::cmp<UnorderedLazyKVListTestHeader::key_type> compare;
+ static const bool sort = false;
+ };
+
+ }
+ void UnorderedLazyKVListTestHeader::NOGC_cmp()
+ {
+ // traits-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type, NOGC_cmp_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyKVList< cds::gc::nogc,
+ key_type,
+ value_type,
+ cc::lazy_list::make_traits<
+ cc::opt::compare< cmp<key_type> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_less_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyKVListTestHeader::lt<UnorderedLazyKVListTestHeader::key_type> less;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyKVListTestHeader::NOGC_less()
+ {
+ // traits-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type, NOGC_less_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type,
+ cc::lazy_list::make_traits<
+ cc::opt::less< lt<key_type> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_equal_to_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyKVListTestHeader::eq<UnorderedLazyKVListTestHeader::key_type> equal_to;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyKVListTestHeader::NOGC_equal_to()
+ {
+ // traits-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type, NOGC_equal_to_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type,
+ cc::lazy_list::make_traits<
+ cc::opt::equal_to< eq<key_type> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_cmpmix_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyKVListTestHeader::cmp<UnorderedLazyKVListTestHeader::key_type> compare;
+ typedef UnorderedLazyKVListTestHeader::lt<UnorderedLazyKVListTestHeader::key_type> less;
+ typedef UnorderedLazyKVListTestHeader::eq<UnorderedLazyKVListTestHeader::key_type> equal_to;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyKVListTestHeader::NOGC_cmpmix()
+ {
+ // traits-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type, NOGC_cmpmix_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type,
+ cc::lazy_list::make_traits<
+ cc::opt::compare< cmp<key_type> >
+ ,cc::opt::less< lt<key_type> >
+ ,cc::opt::equal_to< eq<key_type> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_ic_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyKVListTestHeader::eq<UnorderedLazyKVListTestHeader::key_type> equal_to;
+ typedef cds::atomicity::item_counter item_counter;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyKVListTestHeader::NOGC_ic()
+ {
+ // traits-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type, NOGC_ic_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyKVList< cds::gc::nogc, key_type, value_type,
+ cc::lazy_list::make_traits<
+ cc::opt::equal_to< eq<key_type> >
+ ,cc::opt::item_counter< cds::atomicity::item_counter >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+} // namespace unordlist
+CPPUNIT_TEST_SUITE_REGISTRATION(unordlist::UnorderedLazyKVListTestHeader);
--- /dev/null
+//$$CDS-header$$
+
+#include "unordered_list/hdr_lazy.h"
+#include <cds/container/lazy_list_nogc.h>
+
+namespace unordlist {
+ namespace {
+ struct NOGC_cmp_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyListTestHeader::cmp<UnorderedLazyListTestHeader::item> compare;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyListTestHeader::NOGC_cmp()
+ {
+ // traits-based version
+ typedef cc::LazyList< cds::gc::nogc, item, NOGC_cmp_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyList< cds::gc::nogc, item,
+ cc::lazy_list::make_traits<
+ cc::opt::compare< cmp<item> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_less_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyListTestHeader::lt<UnorderedLazyListTestHeader::item> less;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyListTestHeader::NOGC_less()
+ {
+ // traits-based version
+ typedef cc::LazyList< cds::gc::nogc, item, NOGC_less_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyList< cds::gc::nogc, item,
+ cc::lazy_list::make_traits<
+ cc::opt::less< lt<item> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_equal_to_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyListTestHeader::equal_to<UnorderedLazyListTestHeader::item> equal_to;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyListTestHeader::NOGC_equal_to()
+ {
+ // traits-based version
+ typedef cc::LazyList< cds::gc::nogc, item, NOGC_equal_to_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyList< cds::gc::nogc, item,
+ cc::lazy_list::make_traits<
+ cc::opt::equal_to< equal_to<item> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_cmpmix_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyListTestHeader::cmp<UnorderedLazyListTestHeader::item> compare;
+ typedef UnorderedLazyListTestHeader::lt<UnorderedLazyListTestHeader::item> less;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyListTestHeader::NOGC_cmpmix()
+ {
+ // traits-based version
+ typedef cc::LazyList< cds::gc::nogc, item, NOGC_cmpmix_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyList< cds::gc::nogc, item,
+ cc::lazy_list::make_traits<
+ cc::opt::compare< cmp<item> >
+ ,cc::opt::less< lt<item> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+ namespace {
+ struct NOGC_equal_to_mix_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyListTestHeader::cmp<UnorderedLazyListTestHeader::item> compare;
+ typedef UnorderedLazyListTestHeader::lt<UnorderedLazyListTestHeader::item> less;
+ typedef UnorderedLazyListTestHeader::equal_to<UnorderedLazyListTestHeader::item> equal_to;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyListTestHeader::NOGC_equal_to_mix()
+ {
+ // traits-based version
+ typedef cc::LazyList< cds::gc::nogc, item, NOGC_equal_to_mix_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyList< cds::gc::nogc, item,
+ cc::lazy_list::make_traits<
+ cc::opt::compare< cmp<item> >
+ ,cc::opt::less< lt<item> >
+ ,cc::opt::equal_to< equal_to<item> >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+ namespace {
+ struct NOGC_ic_traits : public cc::lazy_list::traits
+ {
+ typedef UnorderedLazyListTestHeader::equal_to<UnorderedLazyListTestHeader::item> equal_to;
+ typedef cds::atomicity::item_counter item_counter;
+ static const bool sort = false;
+ };
+ }
+ void UnorderedLazyListTestHeader::NOGC_ic()
+ {
+ // traits-based version
+ typedef cc::LazyList< cds::gc::nogc, item, NOGC_ic_traits > list;
+ nogc_test< list >();
+
+ // option-based version
+ typedef cc::LazyList< cds::gc::nogc, item,
+ cc::lazy_list::make_traits<
+ cc::opt::equal_to< equal_to<item> >
+ ,cc::opt::item_counter< cds::atomicity::item_counter >
+ ,cc::opt::sort<false>
+ >::type
+ > opt_list;
+ nogc_test< opt_list >();
+ }
+
+} // namespace unordlist
+CPPUNIT_TEST_SUITE_REGISTRATION(unordlist::UnorderedLazyListTestHeader);