Bugfix
[libcds.git] / cds / container / lazy_list_nogc.h
index 642931abba0e0a9afb48e49ddad500a98eccc5e7..c4d8a2ea1df0512e2f75db576412849c99e2f39e 100644 (file)
 //$$CDS-header$$
 
-#ifndef __CDS_CONTAINER_LAZY_LIST_NOGC_H
-#define __CDS_CONTAINER_LAZY_LIST_NOGC_H
+#ifndef CDSLIB_CONTAINER_LAZY_LIST_NOGC_H
+#define CDSLIB_CONTAINER_LAZY_LIST_NOGC_H
 
-#include <cds/container/lazy_list_base.h>
+#include <memory>
+#include <cds/container/details/lazy_list_base.h>
 #include <cds/intrusive/lazy_list_nogc.h>
 #include <cds/container/details/make_lazy_list.h>
-#include <cds/details/std/memory.h>
 
 namespace cds { namespace container {
 
-    //@cond
-    namespace details {
-
-        template <typename T, class Traits>
-        struct make_lazy_list_nogc: public make_lazy_list<gc::nogc, T, Traits>
-        {
-            typedef make_lazy_list<cds::gc::nogc, T, Traits>  base_maker;
-            typedef typename base_maker::node_type node_type;
-
-            struct type_traits: public base_maker::type_traits
-            {
-                typedef typename base_maker::node_deallocator    disposer;
-            };
-
-            typedef intrusive::LazyList<cds::gc::nogc, node_type, type_traits>  type;
-        };
-
-    }   // namespace details
-    //@endcond
-
     /// Lazy ordered single-linked list (template specialization for gc::nogc)
     /** @ingroup cds_nonintrusive_list
         \anchor cds_nonintrusive_LazyList_nogc
 
-        This specialization is intended for so-called persistent usage when no item
+        This specialization is so-called append-only when no item
         reclamation may be performed. The class does not support deleting of list item.
 
-        Usually, ordered single-linked list is used as a building block for the hash table implementation.
-        The complexity of searching is <tt>O(N)</tt>.
+        The list can be ordered if \p Traits::sort is \p true that is default
+        or unordered otherwise. Unordered list can be maintained by \p equal_to
+        relationship (\p Traits::equal_to), but for the ordered list \p less
+        or \p compare relations should be specified in \p Traits.
 
-        See \ref cds_nonintrusive_LazyList_gc "LazyList" for description of template parameters.
-
-        The interface of the specialization is a little different.
+        See @ref cds_nonintrusive_LazyList_gc "cds::container::LazyList<cds::gc::nogc, T, Traits>"
     */
-    template <typename T, typename Traits>
-    class LazyList<gc::nogc, T, Traits>:
+    template <
+        typename T,
+#ifdef CDS_DOXYGEN_INVOKED
+        typename Traits = lazy_list::traits
+#else
+        typename Traits
+#endif
+    >
+    class LazyList<cds::gc::nogc, T, Traits>:
 #ifdef CDS_DOXYGEN_INVOKED
         protected intrusive::LazyList< gc::nogc, T, Traits >
 #else
-        protected details::make_lazy_list_nogc< T, Traits >::type
+        protected details::make_lazy_list< cds::gc::nogc, T, Traits >::type
 #endif
     {
         //@cond
-        typedef details::make_lazy_list_nogc< T, Traits > options;
-        typedef typename options::type  base_class;
+        typedef details::make_lazy_list< cds::gc::nogc, T, Traits > maker;
+        typedef typename maker::type  base_class;
         //@endcond
 
     public:
-        typedef T                                   value_type      ;   ///< Type of value stored in the list
-        typedef typename base_class::gc             gc              ;   ///< Garbage collector used
-        typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
-        typedef typename options::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 options::key_comparator    key_comparator  ;   ///< key comparison functor
-        typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef cds::gc::nogc gc;  ///< Garbage collector
+        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 comparing functor
+        typedef typename base_class::memory_model   memory_model;        ///< Memory ordering. See cds::opt::memory_model option
+        static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
 
     protected:
         //@cond
         typedef typename base_class::value_type     node_type;
-        typedef typename options::cxx_allocator     cxx_allocator;
-        typedef typename options::node_deallocator  node_deallocator;
-        typedef typename options::type_traits::compare  intrusive_key_comparator;
+        typedef typename maker::cxx_allocator       cxx_allocator;
+        typedef typename maker::node_deallocator    node_deallocator;
+        typedef typename base_class::key_comparator intrusive_key_comparator;
 
         typedef typename base_class::node_type      head_type;
         //@endcond
 
-    protected:
-        //@cond
-#   ifndef CDS_CXX11_LAMBDA_SUPPORT
-        struct ensure_functor
-        {
-            node_type * m_pItemFound;
-
-            ensure_functor()
-                : m_pItemFound( nullptr )
-            {}
-
-            void operator ()(bool, node_type& item, node_type& )
-            {
-                m_pItemFound = &item;
-            }
-        };
-#   endif
-        //@endcond
-
     protected:
         //@cond
         static node_type * alloc_node()
@@ -107,13 +78,11 @@ namespace cds { namespace container {
             return cxx_allocator().New( v );
         }
 
-#   ifdef CDS_EMPLACE_SUPPORT
         template <typename... Args>
         static node_type * alloc_node( Args&&... args )
         {
             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
         }
-#   endif
 
         static void free_node( node_type * pNode )
         {
@@ -263,7 +232,7 @@ namespace cds { namespace container {
             ++it    ;   // skip dummy head node
             return it;
         }
-        const_iterator cbegin()
+        const_iterator cbegin() const
         {
             const_iterator it( head() );
             ++it    ;   // skip dummy head node
@@ -277,7 +246,7 @@ namespace cds { namespace container {
         {
             return const_iterator( tail());
         }
-        const_iterator cend()
+        const_iterator cend() const
         {
             return const_iterator( tail());
         }
@@ -295,16 +264,10 @@ namespace cds { namespace container {
 
     public:
         /// Default constructor
-        /**
-            Initialize empty list
-        */
         LazyList()
         {}
 
-        /// List desctructor
-        /**
-            Clears the list
-        */
+        /// Desctructor clears the list
         ~LazyList()
         {
             clear();
@@ -323,61 +286,101 @@ namespace cds { namespace container {
             return node_to_iterator( insert_at( head(), val ) );
         }
 
-#   ifdef CDS_EMPLACE_SUPPORT
-        /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
+        /// Inserts data of type \p value_type created from \p args
         /**
             Return an iterator pointing to inserted item if success \ref end() otherwise
-
-            This function is available only for compiler that supports
-            variadic template and move semantics
         */
         template <typename... Args>
         iterator emplace( Args&&... args )
         {
             return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
         }
-#   endif
 
-        /// Ensures that the item \p val exists in the list
+        /// Updates the item
         /**
-            The operation inserts new item if the key \p val is not found in the list.
-            Otherwise, the function returns an iterator that points to item found.
+            If \p key is not in the list and \p bAllowInsert is \p true, 
+            the function inserts a new item.
+            Otherwise, the function returns an iterator pointing to the item found.
 
             Returns <tt> std::pair<iterator, bool>  </tt> where \p first is an iterator pointing to
             item found or inserted, \p second is true if new item has been added or \p false if the item
             already is in the list.
         */
         template <typename Q>
-        std::pair<iterator, bool> ensure( Q const& val )
+        std::pair<iterator, bool> update( Q const& val, bool bAllowInsert = true )
         {
-            std::pair< node_type *, bool > ret = ensure_at( head(), val );
+            std::pair< node_type *, bool > ret = update_at( head(), val, bAllowInsert );
             return std::make_pair( node_to_iterator( ret.first ), ret.second );
         }
+        //@cond
+        template <typename Q>
+        CDS_DEPRECATED("ensure() is deprecated, use update()")
+        std::pair<iterator, bool> ensure( Q const& val )
+        {
+            return update( val, true );
+        }
+        //@endcond
 
-        /// Find the key \p val
-        /** \anchor cds_nonintrusive_LazyList_nogc_find
-            The function searches the item with key equal to \p val
+        /// Checks whether the list contains \p key
+        /**
+            The function searches the item with key equal to \p key
             and returns an iterator pointed to item found if the key is found,
             and \ref end() otherwise
         */
         template <typename Q>
-        iterator find( Q const& key )
+        iterator contains( Q const& key )
         {
             return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ));
         }
+        //@cond
+        template <typename Q>
+        CDS_DEPRECATED("deprecated, use contains()")
+        iterator find( Q const& key )
+        {
+            return contains( key );
+        }
+        //@endcond
 
-        /// Finds the key \p val using \p pred predicate for searching
+        /// Checks whether the map contains \p key using \p pred predicate for searching (ordered list version)
         /**
-            The function is an analog of \ref cds_nonintrusive_LazyList_nogc_find "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.
+            \p Less must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less, bool Sort = c_bSort>
+        typename std::enable_if<Sort, iterator>::type contains( Q const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type() ));
+        }
+        //@cond
+        template <typename Q, typename Less, bool Sort = c_bSort>
+        CDS_DEPRECATED("deprecated, use contains()")
+        typename std::enable_if<Sort, iterator>::type find_with( Q const& key, Less pred )
+        {
+            return contains( key, pred );
+        }
+        //@endcond
+
+        /// Finds the key \p val using \p equal predicate for searching (unordered list version)
+        /**
+            The function is an analog of <tt>contains( key )</tt> but \p equal is used for key comparing.
+            \p Equal functor has the interface like \p std::equal_to.
         */
-        template <typename Q, typename Less>
-        iterator find_with( Q const& key, Less pred )
+        template <typename Q, typename Equal, bool Sort = c_bSort>
+        typename std::enable_if<!Sort, iterator>::type contains( Q const& key, Equal equal )
         {
-            return node_to_iterator( find_at( head(), key, typename options::template less_wrapper<Less>::type() ));
+            CDS_UNUSED( equal );
+            return node_to_iterator( find_at( head(), key, typename maker::template equal_to_wrapper<Equal>::type() ));
         }
+        //@cond
+        template <typename Q, typename Equal, bool Sort = c_bSort>
+        CDS_DEPRECATED("deprecated, use contains()")
+        typename std::enable_if<!Sort, iterator>::type find_with( Q const& key, Equal equal )
+        {
+            return contains( key, equal );
+        }
+        //@endcond
 
         /// Check if the list is empty
         bool empty() const
@@ -387,10 +390,10 @@ namespace cds { namespace container {
 
         /// Returns list's item count
         /**
-            The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
+            The value returned depends on \p Traits::item_counter type. For \p atomicity::empty_item_counter,
             this function always returns 0.
 
-            <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
+            @note Even if you use real item counter and it returns 0, this fact is not mean that the list
             is empty. To check list emptyness use \ref empty() method.
         */
         size_t size() const
@@ -399,9 +402,6 @@ namespace cds { namespace container {
         }
 
         /// Clears the list
-        /**
-            Post-condition: the list is empty
-        */
         void clear()
         {
             base_class::clear();
@@ -425,30 +425,23 @@ namespace cds { namespace container {
             return insert_node_at( refHead, alloc_node( val ));
         }
 
-#   ifdef CDS_EMPLACE_SUPPORT
         template <typename... Args>
         node_type * emplace_at( head_type& refHead, Args&&... args )
         {
             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
         }
-#   endif
+
         template <typename Q>
-        std::pair< node_type *, bool > ensure_at( head_type& refHead, Q const& val )
+        std::pair< node_type *, bool > update_at( head_type& refHead, Q const& val, bool bAllowInsert )
         {
             scoped_node_ptr pNode( alloc_node( val ));
             node_type * pItemFound = nullptr;
 
-#   ifdef CDS_CXX11_LAMBDA_SUPPORT
-            std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode,
-                [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; });
-#   else
-            ensure_functor func;
-            std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode, boost::ref(func) );
-            pItemFound = func.m_pItemFound;
-#   endif
-            assert( pItemFound != nullptr );
-
-            if ( ret.first && ret.second )
+            std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
+                [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; },
+                bAllowInsert );
+
+            if ( ret.second )
                 pNode.release();
 
             return std::make_pair( pItemFound, ret.second );
@@ -464,4 +457,4 @@ namespace cds { namespace container {
     };
 }} // namespace cds::container
 
-#endif // #ifndef __CDS_CONTAINER_LAZY_LIST_NOGC_H
+#endif // #ifndef CDSLIB_CONTAINER_LAZY_LIST_NOGC_H