Added erase_at( iterator ) function to MichaelHashSet/Map and SplitListSet/Map based...
authorkhizmax <libcds.dev@gmail.com>
Mon, 13 Mar 2017 20:26:18 +0000 (23:26 +0300)
committerkhizmax <libcds.dev@gmail.com>
Mon, 13 Mar 2017 20:26:18 +0000 (23:26 +0300)
35 files changed:
cds/container/impl/iterable_kvlist.h
cds/container/impl/iterable_list.h
cds/container/michael_map.h
cds/container/michael_set.h
cds/container/split_list_map.h
cds/container/split_list_set.h
cds/intrusive/details/michael_set_base.h
cds/intrusive/details/split_list_base.h
cds/intrusive/impl/iterable_list.h
cds/intrusive/michael_set.h
cds/intrusive/split_list.h
projects/Win/vc141/gtest-iset-michael-iterable.vcxproj
projects/Win/vc141/gtest-iset-split-iterable.vcxproj
projects/Win/vc141/gtest-list-iterable.vcxproj
projects/Win/vc141/gtest-map-split-iterable.vcxproj
projects/Win/vc141/gtest-set-split-iterable.vcxproj
test/stress/map/iter_erase/map_iter_erase_michael.cpp
test/stress/map/iter_erase/map_iter_erase_split.cpp
test/stress/map/map_type_feldman_hashmap.h
test/stress/map/map_type_michael.h
test/stress/map/map_type_split_list.h
test/stress/set/iter_erase/set_iter_erase_michael.cpp
test/stress/set/iter_erase/set_iter_erase_split.cpp
test/stress/set/set_type_michael.h
test/stress/set/set_type_split_list.h
test/unit/intrusive-list/test_intrusive_iterable_list.h
test/unit/intrusive-set/test_intrusive_michael_iterable_hp.h
test/unit/intrusive-set/test_intrusive_split_iterable_set.h
test/unit/list/test_iterable_list.h
test/unit/list/test_kv_iterable_list.h
test/unit/map/split_iterable_dhp.cpp
test/unit/map/split_iterable_hp.cpp
test/unit/map/test_michael_iterable_hp.h
test/unit/set/test_michael_iterable_hp.h
test/unit/set/test_split_iterable_hp.h

index 4a5e44bf72a823ac953f330e8c14c81502d78e90..296e0e6ca4f1a81c94a63402bc2ed1fcb424f012 100644 (file)
@@ -445,6 +445,19 @@ namespace cds { namespace container {
             return base_class::erase_with( key, less_wrapper<Less>(), f );
         }
 
+        /// Deletes the item pointed by iterator \p iter
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+        */
+        bool erase_at( iterator const& iter )
+        {
+            return base_class::erase_at( iter );
+        }
+
         /// Extracts the item from the list with specified \p key
         /**
             The function searches an item with key equal to \p key,
index 64e5de416b4cce89d044f41841ab7f671fec6acc..061476b34fa4ecd5e9547e463855cdaafb53098b 100644 (file)
@@ -524,6 +524,19 @@ namespace cds { namespace container {
             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
         }
 
+        /// Deletes the item pointed by iterator \p iter
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+        */
+        bool erase_at( iterator const& iter )
+        {
+            return base_class::erase_at( iter );
+        }
+
         /// Extracts the item from the list with specified \p key
         /**
             The function searches an item with key equal to \p key,
index 799407ac63546144d584b7e84856ca9340508569..22b2dccf8ed6898c650b04dc3da83192edab55a6 100644 (file)
@@ -203,7 +203,7 @@ namespace cds { namespace container {
         //@cond
         /// Forward iterator
         template <bool IsConst>
-        class iterator_type: private cds::intrusive::michael_set::details::iterator< internal_bucket_type, IsConst >
+        class iterator_type: protected cds::intrusive::michael_set::details::iterator< internal_bucket_type, IsConst >
         {
             typedef cds::intrusive::michael_set::details::iterator< internal_bucket_type, IsConst >  base_class;
             friend class MichaelHashMap;
@@ -275,13 +275,13 @@ namespace cds { namespace container {
 
             /// Equality operator
             template <bool C>
-            bool operator ==(iterator_type<C> const& i )
+            bool operator ==(iterator_type<C> const& i ) const
             {
                 return base_class::operator ==( i );
             }
             /// Equality operator
             template <bool C>
-            bool operator !=(iterator_type<C> const& i )
+            bool operator !=(iterator_type<C> const& i ) const
             {
                 return !( *this == i );
             }
@@ -674,6 +674,34 @@ namespace cds { namespace container {
             return bRet;
         }
 
+        /// Deletes the item pointed by iterator \p iter (only for \p IterableList based map)
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+
+            @note \p %erase_at() is supported only for \p %MichaelHashMap based on \p IterableList.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        bool erase_at( iterator const& iter )
+#else
+        template <typename Iterator>
+        typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
+        erase_at( Iterator const& iter )
+#endif
+        {
+            assert( iter != end() );
+            assert( iter.bucket() != nullptr );
+
+            if ( iter.bucket()->erase_at( iter.underlying_iterator())) {
+                --m_ItemCounter;
+                return true;
+            }
+            return false;
+        }
+
         /// Extracts the item with specified \p key
         /** \anchor cds_nonintrusive_MichaelHashMap_hp_extract
             The function searches an item with key equal to \p key,
index 92bbbe05622d3c1b62515af4c95245396c4c87a8..cdd383f4694d1831f40945a5288fb903632a3036 100644 (file)
@@ -570,6 +570,34 @@ namespace cds { namespace container {
             return bRet;
         }
 
+        /// Deletes the item pointed by iterator \p iter (only for \p IterableList based set)
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+
+            @note \p %erase_at() is supported only for \p %MichaelHashSet based on \p IterableList.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        bool erase_at( iterator const& iter )
+#else
+        template <typename Iterator>
+        typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
+        erase_at( Iterator const& iter )
+#endif
+        {
+            assert( iter != end() );
+            assert( iter.bucket() != nullptr );
+
+            if ( iter.bucket()->erase_at( iter.underlying_iterator())) {
+                --m_ItemCounter;
+                return true;
+            }
+            return false;
+        }
+
         /// Extracts the item with specified \p key
         /** \anchor cds_nonintrusive_MichaelHashSet_hp_extract
             The function searches an item with key equal to \p key,
index 56eccfa31fed5b518a5b4cbb442af5bc60eaf1a1..59cc52812816caf9346fb7d1b2efe6009152429f 100644 (file)
@@ -542,6 +542,27 @@ namespace cds { namespace container {
             return base_class::erase_with( key, cds::details::predicate_wrapper<value_type, Less, key_accessor>(), f );
         }
 
+        /// Deletes the item pointed by iterator \p iter (only for \p IterableList based map)
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+
+            @note \p %erase_at() is supported only for \p %SplitListMap based on \p IterableList.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        bool erase_at( iterator const& iter )
+#else
+        template <typename Iterator>
+        typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
+        erase_at( Iterator const& iter )
+#endif
+        {
+            return base_class::erase_at( iter );
+        }
+
         /// Extracts the item with specified \p key
         /** \anchor cds_nonintrusive_SplitListMap_hp_extract
             The function searches an item with key equal to \p key,
index 21d0b3534529fdcc6c6f2ad8bdf749601125cc7c..f6a7831e993213c766dad735530c01debd6dd514 100644 (file)
@@ -626,6 +626,28 @@ namespace cds { namespace container {
                 [&f](node_type& node) { f( node.m_Value ); } );
         }
 
+        /// Deletes the item pointed by iterator \p iter (only for \p IterableList based set)
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+
+            @note \p %erase_at() is supported only for \p %SplitListSet based on \p IterableList.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        bool erase_at( iterator const& iter )
+#else
+        template <typename Iterator>
+        typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
+        erase_at( Iterator const& iter )
+#endif
+        {
+            return base_class::erase_at( static_cast<iterator::iterator_base_class const&>( iter ));
+        }
+
+
         /// Extracts the item with specified \p key
         /** \anchor cds_nonintrusive_SplitListSet_hp_extract
             The function searches an item with key equal to \p key,
index 070ee0fb2e959af03a7591fa720b897e0d659cb4..9bf2cd7368f2601a1a176f0216ecda3e95a75c0b 100644 (file)
@@ -204,6 +204,11 @@ namespace cds { namespace intrusive {
                     return m_pCurBucket != m_pEndBucket ? m_pCurBucket : nullptr;
                 }
 
+                list_iterator const& underlying_iterator() const
+                {
+                    return m_itList;
+                }
+
                 template <bool C>
                 bool operator ==(iterator<bucket_type, C> const& i) const
                 {
@@ -214,7 +219,6 @@ namespace cds { namespace intrusive {
                 {
                     return !( *this == i );
                 }
-
             };
         }
         //@endcond
index 65420bd50f092b78c50e29520c92488789e43a44..d7f868b8db06db9679ff0ca9a136f34e0cb85d1a 100644 (file)
@@ -1232,6 +1232,12 @@ namespace cds { namespace intrusive {
                 {
                     return m_itCur != i.m_itCur;
                 }
+
+            protected:
+                list_iterator const& underlying_iterator() const
+                {
+                    return m_itCur;
+                }
             };
         }   // namespace details
         //@endcond
index d34264be35aa3b6d3d0a6bcabaef25174f77e0be..f9f5b2a399376f5f2b72c37614300cd5cf58946c 100644 (file)
@@ -204,7 +204,7 @@ namespace cds { namespace intrusive {
             friend class IterableList;
 
         protected:
-            node_type const*          m_pNode;
+            node_type*    m_pNode;
             typename gc::Guard  m_Guard; // data guard
 
             void next()
@@ -218,14 +218,14 @@ namespace cds { namespace intrusive {
                 m_Guard.clear();
             }
 
-            explicit iterator_type( node_type const* pNode )
+            explicit iterator_type( node_type* pNode )
                 : m_pNode( pNode )
             {
                 if ( !m_Guard.protect( pNode->data, []( marked_data_ptr p ) { return p.ptr(); }).ptr())
                     next();
             }
 
-            iterator_type( node_type const* pNode, value_type* pVal )
+            iterator_type( node_type* pNode, value_type* pVal )
                 : m_pNode( pNode )
             {
                 if ( m_pNode ) {
@@ -234,6 +234,11 @@ namespace cds { namespace intrusive {
                 }
             }
 
+            value_type* data() const
+            {
+                return m_Guard.template get<value_type>();
+            }
+
         public:
             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
@@ -250,13 +255,15 @@ namespace cds { namespace intrusive {
 
             value_ptr operator ->() const
             {
-                return m_Guard.template get<value_type>();
+                return data();
+                //return m_Guard.template get<value_type>();
             }
 
             value_ref operator *() const
             {
                 assert( m_Guard.get_native() != nullptr );
-                return *m_Guard.template get<value_type>();
+                return *data();
+                //return *m_Guard.template get<value_type>();
             }
 
             /// Pre-increment
@@ -335,8 +342,8 @@ namespace cds { namespace intrusive {
                     assert( &(*it1) == &(*it2));
             \endcode
             can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
-            The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
-            Other iterator can observe modified value of the element.
+            The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after changing.
+            Other iterator may observe modified value of the element.
         */
         typedef iterator_type<false>    iterator;
         /// Const forward iterator
@@ -370,25 +377,25 @@ namespace cds { namespace intrusive {
         /// Returns a forward const iterator addressing the first element in a list
         const_iterator cbegin() const
         {
-            return const_iterator( &m_Head );
+            return const_iterator( const_cast<node_type*>( &m_Head ));
         }
 
         /// Returns a forward const iterator addressing the first element in a list
         const_iterator begin() const
         {
-            return const_iterator( &m_Head );
+            return const_iterator( const_cast<node_type*>( &m_Head ));
         }
 
         /// Returns an const iterator that addresses the location succeeding the last element in a list
         const_iterator end() const
         {
-            return const_iterator( &m_Tail );
+            return const_iterator( const_cast<node_type*>( &m_Tail ));
         }
 
         /// Returns an const iterator that addresses the location succeeding the last element in a list
         const_iterator cend() const
         {
-            return const_iterator( &m_Tail );
+            return const_iterator( const_cast<node_type*>( &m_Tail ));
         }
     //@}
 
@@ -580,6 +587,28 @@ namespace cds { namespace intrusive {
             return erase_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>(), f );
         }
 
+        /// Deletes the item pointed by iterator \p iter
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+        */
+        bool erase_at( iterator const& iter )
+        {
+            assert( iter != end() );
+
+            marked_data_ptr val( iter.data() );
+            if ( iter.m_pNode->data.compare_exchange_strong( val, marked_data_ptr(), memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+                --m_ItemCounter;
+                retire_data( val.ptr() );
+                m_Stat.onEraseSuccess();
+                return true;
+            }
+            return false;
+        }
+
         /// Extracts the item from the list with specified \p key
         /** \anchor cds_intrusive_IterableList_hp_extract
             The function searches an item with key equal to \p key,
@@ -981,7 +1010,7 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q, typename Compare, typename Func>
-        bool erase_at( node_type* pHead, const Q& val, Compare cmp, Func f, position& pos )
+        bool erase_at( node_type* pHead, Q const& val, Compare cmp, Func f, position& pos )
         {
             back_off bkoff;
             while ( search( pHead, val, pos, cmp )) {
@@ -1002,7 +1031,7 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q, typename Compare, typename Func>
-        bool erase_at( node_type* pHead, const Q& val, Compare cmp, Func f )
+        bool erase_at( node_type* pHead, Q const& val, Compare cmp, Func f )
         {
             position pos;
             return erase_at( pHead, val, cmp, f, pos );
@@ -1077,7 +1106,7 @@ namespace cds { namespace intrusive {
             }
 
             m_Stat.onFindFailed();
-            return iterator( &m_Tail );
+            return iterator( const_cast<node_type*>( &m_Tail ));
         }
 
         template <typename Q, typename Compare>
index a2aac0b46f4e124b6252cc9e0a3d2bb88b195d5c..8e21f85f7fe5213fdd4845810d3cbbf8534b88cd 100644 (file)
@@ -626,6 +626,34 @@ namespace cds { namespace intrusive {
             return false;
         }
 
+        /// Deletes the item pointed by iterator \p iter (only for \p IterableList based set)
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+
+            @note \p %erase_at() is supported only for \p %MichaelHashSet based on \p IterableList.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        bool erase_at( iterator const& iter )
+#else
+        template <typename Iterator>
+        typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
+        erase_at( Iterator const& iter )
+#endif
+        {
+            assert( iter != end() );
+            assert( iter.bucket() != nullptr );
+
+            if ( iter.bucket()->erase_at( iter.underlying_iterator())) {
+                --m_ItemCounter;
+                return true;
+            }
+            return false;
+        }
+
         /// Extracts the item with specified \p key
         /** \anchor cds_intrusive_MichaelHashSet_hp_extract
             The function searches an item with key equal to \p key,
index b4e31dfb39dae2e66b4c3fe4962e8bfd59ba74fb..d28e205044d7c62dcbddd381e083049e1751a46d 100644 (file)
@@ -351,6 +351,16 @@ namespace cds { namespace intrusive {
                 return base_class::unlink_at( h, val );
             }
 
+            template <typename Iterator>
+            typename std::enable_if<
+                std::is_same< Iterator, typename ordered_list::iterator>::value && is_iterable_list< ordered_list >::value,
+                bool
+            >::type
+            erase_at( Iterator iter )
+            {
+                return base_class::erase_at( iter );
+            }
+
             template <typename Q, typename Compare, typename Func>
             bool erase_at( aux_node_type * pHead, split_list::details::search_value_type<Q> const& val, Compare cmp, Func f )
             {
@@ -433,10 +443,13 @@ namespace cds { namespace intrusive {
         //@cond
         template <bool IsConst>
         class iterator_type
-            :public split_list::details::iterator_type<node_traits, ordered_list, IsConst>
+            : public split_list::details::iterator_type<node_traits, ordered_list, IsConst>
         {
             typedef split_list::details::iterator_type<node_traits, ordered_list, IsConst> iterator_base_class;
             typedef typename iterator_base_class::list_iterator list_iterator;
+
+            friend class SplitListSet;
+
         public:
             iterator_type()
                 : iterator_base_class()
@@ -830,6 +843,34 @@ namespace cds { namespace intrusive {
             return erase_( key, typename ordered_list_adapter::template make_compare_from_less<Less>(), f );
         }
 
+        /// Deletes the item pointed by iterator \p iter (only for \p IterableList based set)
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+            The function can return \p false if the node the iterator points to has already been deleted
+            by other thread.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+
+            @note \p %erase_at() is supported only for \p %SplitListSet based on \p IterableList.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        bool erase_at( iterator const& iter )
+#else
+        template <typename Iterator>
+        typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
+        erase_at( Iterator const& iter )
+#endif
+        {
+            assert( iter != end() );
+
+            if ( m_List.erase_at( iter.underlying_iterator())) {
+                --m_ItemCounter;
+                m_Stat.onEraseSuccess();
+                return true;
+            }
+            return false;
+        }
+
         /// Extracts the item with specified \p key
         /** \anchor cds_intrusive_SplitListSet_hp_extract
             The function searches an item with key equal to \p key,
index be0c52e6fc0efb62acc235c5892f6dce1d1aa064..1d1073ab5fe8a763415c5577fffb9176ec8d21b9 100644 (file)
@@ -36,8 +36,6 @@
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable_hp.h" />
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set.h" />
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set_nogc.h" />
-    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set_rcu.h" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{2A3D25FA-16AB-4105-9585-EF5266979989}</ProjectGuid>
index 4ddbc6815d8e4e8d512ec73c0d900a7b9ada4ce1..b3236b4b12bdd21ce2f4b9ca0101764b403dcca2 100644 (file)
@@ -34,8 +34,6 @@
   <ItemGroup>
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set.h" />
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set_nogc.h" />
-    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set_rcu.h" />
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_split_iterable_set.h" />
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_split_iterable_set_hp.h" />
   </ItemGroup>
index 46d0cd174d1201729ccad63618530f5b89e49c68..fbd33a0acf47d1f377b3e49c388e01dbc235d477 100644 (file)
     <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list_hp.h" />
     <ClInclude Include="..\..\..\test\unit\list\test_kv_list.h" />
     <ClInclude Include="..\..\..\test\unit\list\test_kv_list_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\list\test_kv_list_rcu.h" />
     <ClInclude Include="..\..\..\test\unit\list\test_list.h" />
     <ClInclude Include="..\..\..\test\unit\list\test_list_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\list\test_list_rcu.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\..\test\unit\list\iterable_dhp.cpp" />
index 4216fb2343919e2e39af8ff486c62a785f99b242..d86db63e99037331baf2764a18a3127c86696aa1 100644 (file)
     <ClCompile Include="..\..\..\test\unit\map\split_iterable_hp.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\..\..\test\unit\map\test_map.h" />
     <ClInclude Include="..\..\..\test\unit\map\test_map_data.h" />
-    <ClInclude Include="..\..\..\test\unit\map\test_map_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\map\test_map_nogc.h" />
-    <ClInclude Include="..\..\..\test\unit\map\test_map_rcu.h" />
+    <ClInclude Include="..\..\..\test\unit\map\test_michael_iterable.h" />
+    <ClInclude Include="..\..\..\test\unit\map\test_michael_iterable_hp.h" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{B7C62D31-ED28-4D85-AA01-D1071E870080}</ProjectGuid>
index 3a03aa36ced7cc49d19c6a465b975ae4bd848e44..709c92eae45472e17e8429a676680aa5225980cd 100644 (file)
     <ClCompile Include="..\..\..\test\unit\set\split_iterable_hp.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\..\..\test\unit\set\test_ordered_set_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\set\test_set.h" />
     <ClInclude Include="..\..\..\test\unit\set\test_set_data.h" />
-    <ClInclude Include="..\..\..\test\unit\set\test_set_hp.h" />
-    <ClInclude Include="..\..\..\test\unit\set\test_set_nogc.h" />
-    <ClInclude Include="..\..\..\test\unit\set\test_set_rcu.h" />
     <ClInclude Include="..\..\..\test\unit\set\test_split_iterable.h" />
     <ClInclude Include="..\..\..\test\unit\set\test_split_iterable_hp.h" />
   </ItemGroup>
index d933d8eab4c3c46eb690204f0b871280e8eb1494..ee147abb1b1ffe7a2a645e9e61fd5060fe51bbb9 100644 (file)
@@ -32,9 +32,7 @@
 #include "map_type_michael.h"
 
 namespace map {
-    //TODO add erase_at() to MichaelHashMap based on IterableList
-#if 0
-    CDSSTRESS_MichaelMap( Map_Iter_Del3_LF, run_test_extract, key_thread, size_t )
-#endif
+
+    CDSSTRESS_MichaelMap_Iterable( Map_Iter_Del3_LF, run_test_extract, key_thread, size_t )
 
 } // namespace map
index 4ffdb6bbdb72e32cc5b22fb8f8991d1d31d442bf..b56d9ce79a9cefcc5477f5599aa2bbc8edbd9c5c 100644 (file)
@@ -32,8 +32,7 @@
 #include "map_type_split_list.h"
 
 namespace map {
-    //TODO: add erase_at() to SplitList based on IterableList
-#if 0
+
     CDSSTRESS_SplitListIterableMap( Map_Iter_Del3_LF, run_test_extract, key_thread, size_t )
-#endif
+
 } // namespace map
index 1c5907aa0351ad03c01371cc2c58821d12905d1f..1b242f542194c81cbc6363e9f7d86bff0d93b0b9 100644 (file)
@@ -60,14 +60,14 @@ namespace map {
 
         template <typename Iterator>
         typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
-            get_begin()
+        get_begin()
         {
             return base_class::begin();
         }
 
         template <typename Iterator>
         typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
-            get_end()
+        get_end()
         {
             return base_class::end();
         }
index 98873ea5d72bcf99366b64e59078201406cc514d..7e23eca933d7274854a10a67a14060aef48cfbde 100644 (file)
@@ -51,6 +51,20 @@ namespace map {
             : base_class( cfg.s_nMapSize, cfg.s_nLoadFactor )
         {}
 
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_begin()
+        {
+            return base_class::begin();
+        }
+
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_end()
+        {
+            return base_class::end();
+        }
+
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
@@ -328,7 +342,14 @@ namespace map {
 #endif
 
 #if defined(CDS_STRESS_TEST_LEVEL) && CDS_STRESS_TEST_LEVEL == 1
-#   define  CDSSTRESS_MichaelMap_HP_1( fixture, test_case, key_type, value_type ) \
+
+#   define CDSSTRESS_MichaelMap_Iterable_1( fixture, test_case, key_type, value_type ) \
+        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_cmp,            key_type, value_type ) \
+        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_cmp_stat,        key_type, value_type ) \
+        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_less,            key_type, value_type ) \
+        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_less_stat,      key_type, value_type ) \
+
+#   define CDSSTRESS_MichaelMap_HP_1( fixture, test_case, key_type, value_type ) \
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_DHP_cmp,                     key_type, value_type ) \
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_HP_cmp_stat,                 key_type, value_type ) \
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_HP_less,                     key_type, value_type ) \
@@ -338,11 +359,6 @@ namespace map {
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Lazy_HP_cmp_stat,            key_type, value_type ) \
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Lazy_HP_less,                key_type, value_type ) \
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Lazy_DHP_less_stat,          key_type, value_type ) \
-        \
-        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_cmp,            key_type, value_type ) \
-        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_cmp_stat,        key_type, value_type ) \
-        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_less,            key_type, value_type ) \
-        CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_less_stat,      key_type, value_type ) \
 
 #   define  CDSSTRESS_MichaelMap_RCU_1( fixture, test_case, key_type, value_type ) \
         CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_RCU_GPB_cmp,                 key_type, value_type ) \
@@ -360,11 +376,18 @@ namespace map {
         CDSSTRESS_MichaelMap_RCU_1( fixture, test_case, key_type, value_type ) \
 
 #else
+#   define CDSSTRESS_MichaelMap_Iterable_1( fixture, test_case, key_type, value_type )
 #   define  CDSSTRESS_MichaelMap_HP_1( fixture, test_case, key_type, value_type )
 #   define  CDSSTRESS_MichaelMap_RCU_1( fixture, test_case, key_type, value_type )
 #   define  CDSSTRESS_MichaelMap_1( fixture, test_case, key_type, value_type )
 #endif
 
+#define CDSSTRESS_MichaelMap_Iterable( fixture, test_case, key_type, value_type ) \
+    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_cmp,             key_type, value_type ) \
+    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_cmp_stat,       key_type, value_type ) \
+    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_less,           key_type, value_type ) \
+    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_less_stat,       key_type, value_type ) \
+    CDSSTRESS_MichaelMap_Iterable_1( fixture, test_case, key_type, value_type ) \
 
 #define CDSSTRESS_MichaelMap_HP( fixture, test_case, key_type, value_type ) \
     CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_HP_cmp,                      key_type, value_type ) \
@@ -377,11 +400,7 @@ namespace map {
     CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Lazy_DHP_less,               key_type, value_type ) \
     CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Lazy_HP_less_stat,           key_type, value_type ) \
     \
-    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_cmp,             key_type, value_type ) \
-    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_cmp_stat,       key_type, value_type ) \
-    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_DHP_less,           key_type, value_type ) \
-    CDSSTRESS_MichaelMap_case( fixture, test_case, MichaelMap_Iterable_HP_less_stat,       key_type, value_type ) \
-    \
+    CDSSTRESS_MichaelMap_Iterable( fixture, test_case, key_type, value_type ) \
     CDSSTRESS_MichaelMap_HP_1( fixture, test_case, key_type, value_type ) \
     CDSSTRESS_MichaelMap_HP_2( fixture, test_case, key_type, value_type ) \
 
index c2fe83b7a371b542d4bab5504961bb1179092178..b26d6748971d92dbe7ad64f4cf0c559b0acb8c49 100644 (file)
@@ -67,6 +67,20 @@ namespace map {
             : base_class( cfg.s_nMapSize, cfg.s_nLoadFactor )
         {}
 
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_begin()
+        {
+            return base_class::begin();
+        }
+
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_end()
+        {
+            return base_class::end();
+        }
+
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
index e0e88033bda8c60e333854fd3353f0412753988e..2c997bcf3dab40bc1dfe265c2ac2de5c9ed54689 100644 (file)
@@ -32,9 +32,7 @@
 #include "set_type_michael.h"
 
 namespace set {
-    //TODO: add erase_at() to IterableList and MichaelHashSet
-#if 0
+
     CDSSTRESS_MichaelIterableSet( Set_Iter_Del3_LF, run_test_extract, key_thread, size_t )
-#endif
 
 } // namespace set
index d67b7b502629b4b1a0ba373e7648164731f0d496..c34f5d42efe8548451c821632169096490f82206 100644 (file)
@@ -32,8 +32,7 @@
 #include "set_type_split_list.h"
 
 namespace set {
-    //TODO: Add erase_at to IterableList and SplitList based on it
-#if 0
+
     CDSSTRESS_SplitListIterableSet( Set_Iter_Del3_LF, run_test_extract, key_thread, size_t )
-#endif
+
 } // namespace set
index fafe4b8d193b54279ac047cfa45e030fee5956e8..24bf5f0b1282d07ccaec132d75c321fa0e47826a 100644 (file)
@@ -54,6 +54,20 @@ namespace set {
             : base_class( cfg.s_nSetSize, cfg.s_nLoadFactor )
         {}
 
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_begin()
+        {
+            return base_class::begin();
+        }
+
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_end()
+        {
+            return base_class::end();
+        }
+
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
index 42f76a4fa70af3bce6dd5fe978d17d394d192caf..aa12be451c958fe78e7d2f93a2b0c87717e3821a 100644 (file)
@@ -62,6 +62,20 @@ namespace set {
             : base_class( cfg.s_nSetSize, cfg.s_nLoadFactor )
         {}
 
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_begin()
+        {
+            return base_class::begin();
+        }
+
+        template <typename Iterator>
+        typename std::enable_if< std::is_same< Iterator, typename base_class::iterator>::value, Iterator>::type
+        get_end()
+        {
+            return base_class::end();
+        }
+
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
index 2dc2380593e4ce29d9647c468e6f39c7ed1a6cdd..4cf8ab762148bed90b66a7425f401876fa8d2098 100644 (file)
@@ -529,7 +529,23 @@ namespace cds_test {
                 ++key;
             }
 
-            l.clear();
+            // Erase by iterator
+            key = 0;
+            for ( auto it = l.begin(); it != l.end(); ++it ) {
+                EXPECT_EQ( it->nKey, key );
+                EXPECT_EQ( ( *it ).nKey, key );
+
+                EXPECT_TRUE( l.erase_at( it ) );
+
+                EXPECT_EQ( it->nKey, key );
+                EXPECT_EQ( ( *it ).nKey, key );
+
+                EXPECT_FALSE( l.erase_at( it ) );
+                ++key;
+            }
+            EXPECT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
             List::gc::force_dispose();
             for ( auto const& i : arr ) {
                 EXPECT_EQ( i.s.nDisposeCount, 1 );
index c8b83aae0561b01fc4270411c78ef63f407f8979..0a892cb5d9c945db065f138b31317bc34cb29a7d 100644 (file)
@@ -152,6 +152,24 @@ namespace cds_test {
                 EXPECT_EQ( i.nDisposeCount, 1u );
             }
 
+            // erase_at() test
+            for ( auto& i : data ) {
+                i.nDisposeCount = 0;
+                ASSERT_TRUE( s.insert( i ) );
+            }
+
+            for ( auto it = s.begin(); it != s.end(); ++it ) {
+                EXPECT_TRUE( s.erase_at( it ));
+                EXPECT_FALSE( s.erase_at( it ));
+            }
+            ASSERT_TRUE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, 0 );
+
+            // Force retiring cycle
+            Set::gc::force_dispose();
+            for ( auto& i : data ) {
+                EXPECT_EQ( i.nDisposeCount, 1u );
+            }
         }
     };
 
index 91bfbb58cc76b7ddcb202b59f8f53857550ba775..4cfcda90511f85608702c9af1706d4d8608fa700 100644 (file)
@@ -396,8 +396,11 @@ namespace cds_test {
                 EXPECT_EQ( i.nFindCount, 1u );
             }
 
-            // clear test
-            s.clear();
+            // erase_at() test
+            for ( auto it = s.begin(); it != s.end(); ++it ) {
+                EXPECT_TRUE( s.erase_at( it ));
+                EXPECT_FALSE( s.erase_at( it ));
+            }
 
             ASSERT_TRUE( s.empty());
             ASSERT_CONTAINER_SIZE( s, 0u );
index 9233a842f1f52c5899f56b4ab41cf0f58073469d..5dd9ef1959c80c668f6490eb161ec41dfc3add55 100644 (file)
@@ -394,7 +394,12 @@ namespace cds_test {
             }
             EXPECT_EQ( static_cast<size_t>(key), nSize );
 
-            l.clear();
+            // erase_at()
+            for ( auto it = l.begin(); it != l.end(); ++it ) {
+                EXPECT_TRUE( l.erase_at( it ));
+                EXPECT_FALSE( l.erase_at( it ));
+            }
+
             ASSERT_TRUE( l.empty());
             EXPECT_CONTAINER_SIZE( l, 0 );
         }
index 9fcefda7fd5bd0cfb7a8b6b8b9f6289f253e9840..8c6cdc8d8052f3ab89ed4b6e3b38fa7e6bf24656 100644 (file)
@@ -438,7 +438,12 @@ namespace cds_test {
             }
             EXPECT_EQ( static_cast<size_t>(key), nSize );
 
-            l.clear();
+            // erase_at()
+            for ( auto it = l.begin(); it != l.end(); ++it ) {
+                EXPECT_TRUE( l.erase_at( it ));
+                EXPECT_FALSE( l.erase_at( it ));
+            }
+
             ASSERT_TRUE( l.empty());
             EXPECT_CONTAINER_SIZE( l, 0 );
         }
index 27f6d5ae9107455daa88acdba244d1e22092877e..d95c228585cbddb74a56524c6d78d4633f951660 100644 (file)
@@ -38,7 +38,7 @@ namespace {
     namespace cc = cds::container;
     typedef cds::gc::DHP gc_type;
 
-    class SplitListIterableMap_DHP : public cds_test::michael_iterable_map
+    class SplitListIterableMap_DHP : public cds_test::michael_iterable_hp
     {
     protected:
         typedef cds_test::michael_iterable_map base_class;
index d93c38431fc670c197ca697fb84a10fce84caa37..f2753f68947c5e6c5bf83278c1f7fd05455246ce 100644 (file)
@@ -38,7 +38,7 @@ namespace {
     namespace cc = cds::container;
     typedef cds::gc::HP gc_type;
 
-    class SplitListIterableMap_HP : public cds_test::michael_iterable_map
+    class SplitListIterableMap_HP : public cds_test::michael_iterable_hp
     {
     protected:
         typedef cds_test::michael_iterable_map base_class;
index 6e940b8f59df2e9403bf8601f6a240128f6ca3ae..36b93af0289a678a286555c4032ff1aa867a117f 100644 (file)
@@ -133,6 +133,19 @@ namespace cds_test {
             }
             EXPECT_TRUE( m.empty());
             EXPECT_CONTAINER_SIZE( m, 0u );
+
+            // erase_at()
+            for ( auto const& i : arrKeys )
+                EXPECT_TRUE( m.insert( i ) );
+            EXPECT_FALSE( m.empty() );
+            EXPECT_CONTAINER_SIZE( m, kkSize );
+
+            for ( auto it = m.begin(); it != m.end(); ++it ) {
+                EXPECT_TRUE( m.erase_at( it ));
+                EXPECT_FALSE( m.erase_at( it ));
+            }
+            EXPECT_TRUE( m.empty() );
+            EXPECT_CONTAINER_SIZE( m, 0u );
         }
     };
 
index 1ab9a1341499d1aa3c3ca81820549de9b35a2777..08cfbf5b9d6aae3218c0ceef9728e92f76ef7be2 100644 (file)
@@ -145,6 +145,21 @@ namespace cds_test {
 
             EXPECT_TRUE( s.empty());
             EXPECT_CONTAINER_SIZE( s, 0 );
+
+            // erase_at()
+            for ( auto& i : data ) {
+                EXPECT_TRUE( s.insert( i ) );
+            }
+            EXPECT_FALSE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+            for ( auto it = s.begin(); it != s.end(); ++it ) {
+                EXPECT_TRUE( s.erase_at( it ));
+                EXPECT_FALSE( s.erase_at( it ));
+            }
+
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
         }
 
     };
index 122c8627eebc87c557786dcb8dd2c0f145aa6b65..2b558fcd75921c3703ffc6d89e56bb70a78f234d 100644 (file)
@@ -145,6 +145,21 @@ namespace cds_test {
 
             EXPECT_TRUE( s.empty());
             EXPECT_CONTAINER_SIZE( s, 0 );
+
+            // erase_at()
+            for ( auto& i : data ) {
+                EXPECT_TRUE( s.insert( i ) );
+            }
+            EXPECT_FALSE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+            for ( auto it = s.begin(); it != s.end(); ++it ) {
+                EXPECT_TRUE( s.erase_at( it ));
+                EXPECT_FALSE( s.erase_at( it ));
+            }
+
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
         }
 
     };