Fixed doc typo
[libcds.git] / cds / container / impl / michael_list.h
index 966da076eb1b7a5761f052ad1fc403df5a942a25..514dbfd8c348f79c135b58e0070844208d802cc0 100644 (file)
@@ -1,7 +1,35 @@
-//$$CDS-header$$
-
-#ifndef __CDS_CONTAINER_IMPL_MICHAEL_LIST_H
-#define __CDS_CONTAINER_IMPL_MICHAEL_LIST_H
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+*/
+
+#ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
+#define CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
 
 #include <memory>
 #include <cds/container/details/guarded_ptr_cast.h>
@@ -109,6 +137,8 @@ namespace cds { namespace container {
         typedef typename maker::key_comparator      key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
 
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+
     protected:
         //@cond
         typedef typename base_class::value_type      node_type;
@@ -121,9 +151,9 @@ namespace cds { namespace container {
 
     public:
         /// Guarded pointer
-        typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+        typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
 
-    private:
+    protected:
         //@cond
         static value_type& node_to_value( node_type& n )
         {
@@ -133,10 +163,7 @@ namespace cds { namespace container {
         {
             return n.m_Value;
         }
-        //@endcond
 
-    protected:
-        //@cond
         template <typename Q>
         static node_type * alloc_node( Q const& v )
         {
@@ -229,6 +256,8 @@ namespace cds { namespace container {
         //@endcond
 
     public:
+    ///@name Forward iterators (only for debugging purpose)
+    //@{
         /// Forward iterator
         /**
             The forward iterator for Michael's list has some features:
@@ -239,9 +268,9 @@ namespace cds { namespace container {
             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
               deleting operations it is no guarantee that you iterate all item in the list.
+              Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
 
-            Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
-            for debug purpose only.
+            @warning Use this iterator on the concurrent container for debugging purpose only.
         */
         typedef iterator_type<false>    iterator;
 
@@ -274,28 +303,29 @@ namespace cds { namespace container {
         }
 
         /// Returns a forward const iterator addressing the first element in a list
-        //@{
         const_iterator begin() const
         {
             return const_iterator( head() );
         }
+
+        /// Returns a forward const iterator addressing the first element in a list
         const_iterator cbegin() const
         {
             return const_iterator( head() );
         }
-        //@}
 
         /// Returns an const iterator that addresses the location succeeding the last element in a list
-        //@{
         const_iterator end() const
         {
             return const_iterator();
         }
+
+        /// Returns an const iterator that addresses the location succeeding the last element in a list
         const_iterator cend() const
         {
             return const_iterator();
         }
-        //@}
+    //@}
 
     public:
         /// Default constructor
@@ -361,42 +391,48 @@ namespace cds { namespace container {
             return insert_at( head(), key, func );
         }
 
-        /// Ensures that the \p key exists in the list
+        /// Updates data by \p key
         /**
-            The operation performs inserting or changing data with lock-free manner.
+            The operation performs inserting or replacing the element with lock-free manner.
 
             If the \p key not found in the list, then the new item created from \p key
-            is inserted into the list. Otherwise, the functor \p func is called with the item found.
-            The functor \p Func should be a function with signature:
-            \code
-                void func( bool bNew, value_type& item, const Q& val );
-            \endcode
-            or a functor:
+            will be inserted iff \p bAllowInsert is \p true.
+            Otherwise, if \p key is found, the functor \p func is called with item found.
+
+            The functor \p Func signature is:
             \code
                 struct my_functor {
-                    void operator()( bool bNew, value_type& item, const Q& val );
+                    void operator()( bool bNew, value_type& item, Q const& val );
                 };
             \endcode
 
             with arguments:
             - \p bNew - \p true if the item has been inserted, \p false otherwise
             - \p item - item of the list
-            - \p val - argument \p key passed into the \p ensure function
+            - \p val - argument \p key passed into the \p %update() function
 
             The functor may change non-key fields of the \p item; however, \p func must guarantee
             that during changing no any other modifications could be made on this item by concurrent threads.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
-            already is in the list.
+            already exists.
 
             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
         */
         template <typename Q, typename Func>
+        std::pair<bool, bool> update( Q const& key, Func func, bool bAllowInsert = true )
+        {
+            return update_at( head(), key, func, bAllowInsert );
+        }
+        //@cond
+        template <typename Q, typename Func>
+        CDS_DEPRECATED("ensure() is deprecated, use update()")
         std::pair<bool, bool> ensure( Q const& key, Func func )
         {
-            return ensure_at( head(), key, func );
+            return update( key, func );
         }
+        //@endcond
 
         /// Inserts data of type \p value_type constructed with <tt>std::forward<Args>(args)...</tt>
         /**
@@ -433,6 +469,7 @@ namespace cds { namespace container {
         template <typename Q, typename Less>
         bool erase_with( Q const& key, Less pred )
         {
+            CDS_UNUSED( pred );
             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
         }
 
@@ -471,14 +508,15 @@ namespace cds { namespace container {
         template <typename Q, typename Less, typename Func>
         bool erase_with( Q const& key, Less pred, Func f )
         {
+            CDS_UNUSED( pred );
             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
         }
 
         /// Extracts the item from the list with specified \p key
         /** \anchor cds_nonintrusive_MichaelList_hp_extract
             The function searches an item with key equal to \p key,
-            unlinks it from the list, and returns it in \p dest parameter.
-            If the item with key equal to \p key is not found the function returns \p false.
+            unlinks it from the list, and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
 
             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
 
@@ -490,24 +528,26 @@ namespace cds { namespace container {
             ord_list theList;
             // ...
             {
-                ord_list::guarded_ptr gp;
-                theList.extract( gp, 5 );
-                // Deal with gp
-                // ...
-
+                ord_list::guarded_ptr gp(theList.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
                 // Destructor of gp releases internal HP guard and frees the item
             }
             \endcode
         */
         template <typename Q>
-        bool extract( guarded_ptr& dest, Q const& key )
+        guarded_ptr extract( Q const& key )
         {
-            return extract_at( head(), dest.guard(), key, intrusive_key_comparator() );
+            guarded_ptr gp;
+            extract_at( head(), gp.guard(), key, intrusive_key_comparator() );
+            return gp;
         }
 
         /// Extracts the item from the list with comparing functor \p pred
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_extract "extract(guarded_ptr&, Q const&)"
+            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_extract "extract(Q const&)"
             but \p pred predicate is used for key comparing.
 
             \p Less functor has the semantics like \p std::less but it should accept arguments of type \p value_type and \p Q
@@ -515,34 +555,53 @@ namespace cds { namespace container {
             \p pred must imply the same element order as the comparator used for building the list.
         */
         template <typename Q, typename Less>
-        bool extract_with( guarded_ptr& dest, Q const& key, Less pred )
+        guarded_ptr extract_with( Q const& key, Less pred )
         {
-            return extract_at( head(), dest.guard(), key, typename maker::template less_wrapper<Less>::type() );
+            CDS_UNUSED( pred );
+            guarded_ptr gp;
+            extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
+            return gp;
         }
 
-        /// Finds \p key
-        /** \anchor cds_nonintrusive_MichaelList_hp_find_val
+        /// Checks whether the list contains \p key
+        /**
             The function searches the item with key equal to \p key
-            and returns \p true if it is found, and \p false otherwise
+            and returns \p true if it is found, and \p false otherwise.
         */
         template <typename Q>
-        bool find( Q const& key )
+        bool contains( Q const& key )
         {
             return find_at( head(), key, intrusive_key_comparator() );
         }
+        //@cond
+        template <typename Q>
+        CDS_DEPRECATED("deprecated, use contains()")
+        bool find( Q const& key )
+        {
+            return contains( key );
+        }
+        //@endcond
 
-        /// Finds \p key using \p pred predicate for searching
+        /// Checks whether the list contains \p key using \p pred predicate for searching
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_find_val "find(Q const&)"
-            but \p pred is used for key comparing.
+            The function is an analog of <tt>contains( key )</tt> 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>
-        bool find_with( Q const& key, Less pred )
+        bool contains( Q const& key, Less pred )
         {
+            CDS_UNUSED( pred );
             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
         }
+        //@cond
+        template <typename Q, typename Less>
+        CDS_DEPRECATED("deprecated, use contains()")
+        bool find_with( Q const& key, Less pred )
+        {
+            return contains( key, pred );
+        }
+        //@endcond
 
         /// Finds \p key and perform an action with it
         /** \anchor cds_nonintrusive_MichaelList_hp_find_func
@@ -585,12 +644,14 @@ namespace cds { namespace container {
         template <typename Q, typename Less, typename Func>
         bool find_with( Q& key, Less pred, Func f )
         {
+            CDS_UNUSED( pred );
             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
         }
         //@cond
         template <typename Q, typename Less, typename Func>
         bool find_with( Q const& key, Less pred, Func f )
         {
+            CDS_UNUSED( pred );
             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
         }
         //@endcond
@@ -598,9 +659,8 @@ namespace cds { namespace container {
         /// Finds \p key and return the item found
         /** \anchor cds_nonintrusive_MichaelList_hp_get
             The function searches the item with key equal to \p key
-            and assigns the item found to guarded pointer \p ptr.
-            The function returns \p true if \p key is found, and \p false otherwise.
-            If \p key is not found the \p ptr parameter is not changed.
+            and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
 
             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
 
@@ -610,8 +670,8 @@ namespace cds { namespace container {
             ord_list theList;
             // ...
             {
-                ord_list::guarded_ptr gp;
-                if ( theList.get( gp, 5 )) {
+                ord_list::guarded_ptr gp(theList.get( 5 ));
+                if ( gp ) {
                     // Deal with gp
                     //...
                 }
@@ -623,14 +683,16 @@ namespace cds { namespace container {
             should accept a parameter of type \p Q that can be not the same as \p value_type.
         */
         template <typename Q>
-        bool get( guarded_ptr& ptr, Q const& key )
+        guarded_ptr get( Q const& key )
         {
-            return get_at( head(), ptr.guard(), key, intrusive_key_comparator() );
+            guarded_ptr gp;
+            get_at( head(), gp.guard(), key, intrusive_key_comparator() );
+            return gp;
         }
 
         /// Finds \p key and return the item found
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( guarded_ptr& ptr, Q const&)"
+            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
             but \p pred is used for comparing the keys.
 
             \p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
@@ -638,9 +700,12 @@ namespace cds { namespace container {
             \p pred must imply the same element order as the comparator used for building the list.
         */
         template <typename Q, typename Less>
-        bool get_with( guarded_ptr& ptr, Q const& key, Less pred )
+        guarded_ptr get_with( Q const& key, Less pred )
         {
-            return get_at( head(), ptr.guard(), key, typename maker::template less_wrapper<Less>::type() );
+            CDS_UNUSED( pred );
+            guarded_ptr gp;
+            get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
+            return gp;
         }
 
         /// Check if the list is empty
@@ -670,6 +735,11 @@ namespace cds { namespace container {
 
     protected:
         //@cond
+        bool insert_node( node_type * pNode )
+        {
+            return insert_node_at( head(), pNode );
+        }
+
         bool insert_node_at( head_type& refHead, node_type * pNode )
         {
             assert( pNode );
@@ -713,18 +783,19 @@ namespace cds { namespace container {
         }
 
         template <typename Q, typename Compare>
-        bool extract_at( head_type& refHead, typename gc::Guard& dest, Q const& key, Compare cmp )
+        bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
         {
-            return base_class::extract_at( refHead, dest, key, cmp );
+            return base_class::extract_at( refHead, guard, key, cmp );
         }
 
         template <typename Q, typename Func>
-        std::pair<bool, bool> ensure_at( head_type& refHead, Q const& key, Func f )
+        std::pair<bool, bool> update_at( head_type& refHead, Q const& key, Func f, bool bAllowInsert )
         {
             scoped_node_ptr pNode( alloc_node( key ));
 
-            std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
-                [&f, &key](bool bNew, node_type& node, node_type&){ f( bNew, node_to_value(node), key ); });
+            std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
+                [&f, &key](bool bNew, node_type& node, node_type&){ f( bNew, node_to_value(node), key );},
+                bAllowInsert );
             if ( ret.first && ret.second )
                 pNode.release();
 
@@ -744,7 +815,7 @@ namespace cds { namespace container {
         }
 
         template <typename Q, typename Compare>
-        bool get_at( head_type& refHead, typename gc::Guard& guard, Q const& key, Compare cmp )
+        bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
         {
             return base_class::get_at( refHead, guard, key, cmp );
         }
@@ -754,4 +825,4 @@ namespace cds { namespace container {
 
 }}  // namespace cds::container
 
-#endif  // #ifndef __CDS_CONTAINER_IMPL_MICHAEL_LIST_H
+#endif  // #ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H