reimplement guarded_ptr from scratch
authorkhizmax <khizmax@gmail.com>
Tue, 18 Nov 2014 13:19:28 +0000 (16:19 +0300)
committerkhizmax <khizmax@gmail.com>
Tue, 18 Nov 2014 13:19:28 +0000 (16:19 +0300)
16 files changed:
cds/container/impl/ellen_bintree_map.h
cds/container/impl/ellen_bintree_set.h
cds/container/impl/skip_list_map.h
cds/container/impl/skip_list_set.h
cds/gc/details/dhp.h
cds/gc/guarded_ptr.h [deleted file]
cds/gc/impl/dhp_decl.h
cds/gc/impl/dhp_impl.h
cds/gc/impl/hp_decl.h
cds/gc/impl/hp_impl.h
cds/intrusive/impl/ellen_bintree.h
cds/intrusive/impl/lazy_list.h
cds/intrusive/impl/michael_list.h
cds/intrusive/impl/skip_list.h
projects/Win/vc12/cds.vcxproj
projects/Win/vc12/cds.vcxproj.filters

index 654b21a..16b32a3 100644 (file)
@@ -111,7 +111,7 @@ namespace cds { namespace container {
 
     public:
         /// Guarded pointer
-        typedef cds::gc::guarded_ptr< gc, leaf_node, value_type, details::guarded_ptr_cast_set<leaf_node, value_type> > guarded_ptr;
+        typedef typename gc::template guarded_ptr< leaf_node, value_type, details::guarded_ptr_cast_set<leaf_node, value_type> > guarded_ptr;
 
     public:
         /// Default constructor
index 410a70d..dcd99e5 100644 (file)
@@ -146,7 +146,7 @@ namespace cds { namespace container {
 
     public:
         /// Guarded pointer
-        typedef cds::gc::guarded_ptr< gc, leaf_node, value_type, details::guarded_ptr_cast_set<leaf_node, value_type> > guarded_ptr;
+        typedef typename gc::template guarded_ptr< leaf_node, value_type, details::guarded_ptr_cast_set<leaf_node, value_type> > guarded_ptr;
 
     public:
         /// Default constructor
index c565fae..c84a73f 100644 (file)
@@ -3,7 +3,6 @@
 #ifndef __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H
 #define __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H
 
-#include <cds/gc/guarded_ptr.h>
 #include <cds/container/details/guarded_ptr_cast.h>
 
 namespace cds { namespace container {
index 5908219..9f699af 100644 (file)
@@ -4,7 +4,6 @@
 #define __CDS_CONTAINER_IMPL_SKIP_LIST_SET_H
 
 #include <cds/details/binary_functor_wrapper.h>
-#include <cds/gc/guarded_ptr.h>
 #include <cds/container/details/guarded_ptr_cast.h>
 
 namespace cds { namespace container {
index 795ed42..93580a2 100644 (file)
@@ -63,15 +63,13 @@ namespace cds { namespace gc {
 
             /// Internal guard representation
             struct guard_data {
-                typedef retired_ptr_node *      handoff_ptr ;   ///< trapped value type
-                typedef void *  guarded_ptr  ;   ///< type of value guarded
+                typedef void * guarded_ptr;  ///< type of value guarded
 
-                atomics::atomic<guarded_ptr>         pPost   ;   ///< pointer guarded
+                atomics::atomic<guarded_ptr>  pPost;       ///< pointer guarded
+                atomics::atomic<guard_data *> pGlobalNext; ///< next item of global list of allocated guards
+                atomics::atomic<guard_data *> pNextFree;   ///< pointer to the next item in global or thread-local free-list
 
-                atomics::atomic<guard_data *>     pGlobalNext ;   ///< next item of global list of allocated guards
-                atomics::atomic<guard_data *>     pNextFree   ;   ///< pointer to the next item in global or thread-local free-list
-
-                guard_data *             pThreadNext ;   ///< next item of thread's local list of guards
+                guard_data * pThreadNext; ///< next item of thread's local list of guards
 
                 guard_data() CDS_NOEXCEPT
                     : pPost( nullptr )
@@ -117,7 +115,7 @@ namespace cds { namespace gc {
                     details::guard_data * pGuard = m_GuardAllocator.New();
 
                     // Link guard to the list
-                    // m_GuardList is accumulated list and it cannot support concurrent deletion,
+                    // m_GuardList is an accumulating list and it cannot support concurrent deletion,
                     // so, ABA problem is impossible for it
                     details::guard_data * pHead = m_GuardList.load( atomics::memory_order_acquire );
                     do {
@@ -458,33 +456,42 @@ namespace cds { namespace gc {
                 friend class ThreadGC;
             protected:
                 details::guard_data * m_pGuard ;    ///< Pointer to guard data
+
             public:
                 /// Initialize empty guard.
                 CDS_CONSTEXPR guard() CDS_NOEXCEPT
                     : m_pGuard( nullptr )
                 {}
 
-                /// The object is not copy-constructible
+                /// Ñopy-ctor is disabled
                 guard( guard const& ) = delete;
 
+                /// Move-ctor is disabled
+                guard( guard&& ) = delete;
+
                 /// Object destructor, does nothing
                 ~guard() CDS_NOEXCEPT
                 {}
 
+                /// Get current guarded pointer
+                void * get( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT
+                {
+                    assert( m_pGuard != nullptr );
+                    return m_pGuard->pPost.load( order );
+                }
+
                 /// Guards pointer \p p
-                void set( void * p ) CDS_NOEXCEPT
+                void set( void * p, atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT
                 {
                     assert( m_pGuard != nullptr );
-                    m_pGuard->pPost.store( p, atomics::memory_order_release );
-                    //CDS_COMPILER_RW_BARRIER;
+                    m_pGuard->pPost.store( p, order );
                 }
 
                 /// Clears the guard
-                void clear() CDS_NOEXCEPT
+                void clear( atomics::memory_order order = atomics::memory_order_relaxed ) CDS_NOEXCEPT
                 {
                     assert( m_pGuard != nullptr );
-                    m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
-                    CDS_STRICT_DO( CDS_COMPILER_RW_BARRIER );
+                    m_pGuard->pPost.store( nullptr, order );
                 }
 
                 /// Guards pointer \p p
@@ -506,7 +513,6 @@ namespace cds { namespace gc {
                     GCC cannot compile code for template versions of ThreasGC::allocGuard/freeGuard,
                     the compiler produces error: \91cds::gc::dhp::details::guard_data* cds::gc::dhp::details::guard::m_pGuard\92 is protected
                     despite the fact that ThreadGC is declared as friend for guard class.
-                    We should not like to declare m_pGuard member as public one.
                     Therefore, we have to add set_guard/get_guard public functions
                 */
                 /// Set guard data
@@ -526,6 +532,18 @@ namespace cds { namespace gc {
                 {
                     return m_pGuard;
                 }
+
+                details::guard_data * release_guard() CDS_NOEXCEPT
+                {
+                    details::guard_data * p = m_pGuard;
+                    m_pGuard = nullptr;
+                    return p;
+                }
+
+                bool is_initialized() const
+                {
+                    return m_pGuard != nullptr;
+                }
             };
 
         } // namespace details
@@ -886,27 +904,32 @@ namespace cds { namespace gc {
 
         public:
             /// Initializes guard \p g
-            void allocGuard( Guard& g )
+            void allocGuard( dhp::details::guard& g )
             {
                 assert( m_pList != nullptr );
-                if ( m_pFree ) {
-                    g.m_pGuard = m_pFree;
-                    m_pFree = m_pFree->pNextFree.load(atomics::memory_order_relaxed);
-                }
-                else {
-                    g.m_pGuard = m_gc.allocGuard();
-                    g.m_pGuard->pThreadNext = m_pList;
-                    m_pList = g.m_pGuard;
+                if ( !g.m_pGuard ) {
+                    if ( m_pFree ) {
+                        g.m_pGuard = m_pFree;
+                        m_pFree = m_pFree->pNextFree.load( atomics::memory_order_relaxed );
+                    }
+                    else {
+                        g.m_pGuard = m_gc.allocGuard();
+                        g.m_pGuard->pThreadNext = m_pList;
+                        m_pList = g.m_pGuard;
+                    }
                 }
             }
 
             /// Frees guard \p g
-            void freeGuard( Guard& g )
+            void freeGuard( dhp::details::guard& g )
             {
                 assert( m_pList != nullptr );
-                g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
-                g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
-                m_pFree = g.m_pGuard;
+                if ( g.m_pGuard ) {
+                    g.m_pGuard->pPost.store( nullptr, atomics::memory_order_relaxed );
+                    g.m_pGuard->pNextFree.store( m_pFree, atomics::memory_order_relaxed );
+                    m_pFree = g.m_pGuard;
+                    g.m_pGuard = nullptr;
+                }
             }
 
             /// Initializes guard array \p arr
diff --git a/cds/gc/guarded_ptr.h b/cds/gc/guarded_ptr.h
deleted file mode 100644 (file)
index 82925e0..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-//$$CDS-header$$
-
-#ifndef __CDS_GC_GUARDED_PTR_H
-#define __CDS_GC_GUARDED_PTR_H
-
-#include <cds/details/defs.h>
-
-namespace cds { namespace gc {
-
-    /// Guarded pointer
-    /**
-        A guarded pointer is a pair of the pointer and GC's guard.
-        Usually, it is used for returning a pointer to the item from an lock-free container.
-        The guard prevents the pointer to be early disposed (freed) by GC.
-        After destructing \p %guarded_ptr object the pointer can be automatically disposed (freed) at any time.
-
-        Template arguments:
-        - \p GC - a garbage collector type like \p cds::gc::HP and any other from cds::gc namespace
-        - \p GuardedType - a type which the guard stores
-        - \p ValueType - a value type
-        - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
-
-        For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
-        In such case the \p %guarded_ptr is:
-        @code
-        typedef cds::gc::guarded_ptr< cds::gc::HP, foo > intrusive_guarded_ptr;
-        @endcode
-
-        For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
-        For example:
-        @code
-        struct foo {
-            int const   key;
-            std::string value;
-        };
-
-        struct value_accessor {
-            std::string* operator()( foo* pFoo ) const
-            {
-                return &(pFoo->value);
-            }
-        };
-
-        // Guarded ptr
-        typedef cds::gc::guarded_ptr< cds::gc::HP, Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
-        @endcode
-
-        Many set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
-    */
-    template <class GC, typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
-    class guarded_ptr
-    {
-        //TODO: use moce semantics and explicit operator bool!
-    public:
-        typedef GC          gc;           ///< Garbage collector like cds::gc::HP and any other from cds::gc namespace
-        typedef GuardedType guarded_type; ///< Guarded type
-        typedef ValueType   value_type;   ///< Value type
-        typedef Cast        value_cast;   ///< Functor for casting \p guarded_type to \p value_type
-
-    private:
-        //@cond
-        typename gc::Guard  m_guard;
-        //@endcond
-
-    public:
-        /// Creates empty guarded pointer
-        guarded_ptr() CDS_NOEXCEPT
-        {}
-
-        //@cond
-        /// Initializes guarded pointer with \p p
-        guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
-        {
-            m_guard.assign( p );
-        }
-        guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
-        {}
-        //@endcond
-
-        /// Move ctor
-        guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
-        {
-            m_guard.assign( gp.m_guard.get_native() );
-            gp.release();
-        }
-
-        /// The guarded pointer is not copy-constructible
-        guarded_ptr( guarded_ptr const& gp ) = delete;
-
-        /// Clears the guarded pointer
-        /**
-            \ref release is called if guarded pointer is not \ref empty
-        */
-        ~guarded_ptr() CDS_NOEXCEPT
-        {
-            release();
-        }
-
-        /// Move-assignment operator
-        guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
-        {
-            m_guard.assign( gp.m_guard.get_native() );
-            gp.release();
-            return *this;
-        }
-
-        /// The guarded pointer is not copy-assignable
-        guarded_ptr& operator=(guarded_ptr const& gp) = delete;
-
-        /// Returns a pointer to guarded value
-        value_type * operator ->() const CDS_NOEXCEPT
-        {
-            return value_cast()( m_guard.template get<guarded_type>() );
-        }
-
-        /// Returns a reference to guarded value
-        value_type& operator *() CDS_NOEXCEPT
-        {
-            assert( !empty());
-            return *value_cast()( m_guard.template get<guarded_type>() );
-        }
-
-        /// Returns const reference to guarded value
-        value_type const& operator *() const CDS_NOEXCEPT
-        {
-            assert( !empty());
-            return *value_cast()( m_guard.template get<guarded_type>() );
-        }
-
-        /// Checks if the guarded pointer is \p nullptr
-        bool empty() const CDS_NOEXCEPT
-        {
-            return m_guard.template get<guarded_type>() == nullptr;
-        }
-
-        /// \p bool operator returns <tt>!empty()</tt>
-        explicit operator bool() const CDS_NOEXCEPT
-        {
-            return !empty();
-        }
-
-        /// Clears guarded pointer
-        /**
-            If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
-            Dereferncing the guarded pointer after \p release() is dangerous.
-        */
-        void release() CDS_NOEXCEPT
-        {
-            m_guard.clear();
-        }
-
-        //@cond
-        // For internal use only!!!
-        typename gc::Guard& guard() CDS_NOEXCEPT
-        {
-            return m_guard;
-        }
-        //@endcond
-    };
-
-
-    //@cond
-    // Intrusive specialization
-    template <class GC, typename T>
-    class guarded_ptr< GC, T, T, void >
-    {
-    public:
-        typedef GC  gc         ;   ///< Garbage collector like cds::gc::HP
-        typedef T   guarded_type;  ///< Guarded type
-        typedef T   value_type ;   ///< Value type
-
-    private:
-        typename gc::Guard  m_guard;
-
-    public:
-        guarded_ptr() CDS_NOEXCEPT
-        {}
-
-        guarded_ptr( value_type * p ) CDS_NOEXCEPT
-        {
-            m_guard.assign( p );
-        }
-
-        guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
-        {
-            m_guard.assign( gp.m_guard.get_native() );
-            gp.release();
-        }
-
-        guarded_ptr( guarded_ptr const& gp ) = delete;
-
-        ~guarded_ptr() CDS_NOEXCEPT
-        {
-            release();
-        }
-
-        guarded_ptr& operator=(guarded_ptr&& gp) CDS_NOEXCEPT
-        {
-            m_guard.assign( gp.m_guard.get_native() );
-            gp.release();
-            return *this;
-        }
-
-        guarded_ptr& operator=(guarded_ptr const& gp) = delete;
-
-        value_type * operator ->() const CDS_NOEXCEPT
-        {
-            return m_guard.template get<value_type>();
-        }
-
-        value_type& operator *() CDS_NOEXCEPT
-        {
-            assert( !empty());
-            return *m_guard.template get<value_type>();
-        }
-
-        value_type const& operator *() const CDS_NOEXCEPT
-        {
-            assert( !empty());
-            return *m_guard.template get<value_type>();
-        }
-
-        bool empty() const CDS_NOEXCEPT
-        {
-            return m_guard.template get<guarded_type>() == nullptr;
-        }
-
-        explicit operator bool() const CDS_NOEXCEPT
-        {
-            return !empty();
-        }
-
-        void release() CDS_NOEXCEPT
-        {
-            m_guard.clear();
-        }
-
-        typename gc::Guard& guard() CDS_NOEXCEPT
-        {
-            return m_guard;
-        }
-    };
-    //@endcond
-
-}} // namespace cds::gc
-
-#endif // #ifndef __CDS_GC_GUARDED_PTR_H
index a7fd2de..a0e4d4a 100644 (file)
@@ -88,6 +88,12 @@ namespace cds { namespace gc {
                 Otherwise it detaches the current thread from Dynamic Hazard Pointer GC.
             */
             ~thread_gc()    ;   // inline in dhp_impl.h
+
+        public: // for internal use only!!!
+            //@cond
+            static void alloc_guard( cds::gc::dhp::details::guard& g ); // inline in dhp_impl.h
+            static void free_guard( cds::gc::dhp::details::guard& g ); // inline in dhp_impl.h
+            //@endcond
         };
 
 
@@ -107,6 +113,11 @@ namespace cds { namespace gc {
             typedef dhp::Guard base_class;
             //@endcond
 
+        public: // for internal use only
+            //@cond
+            typedef cds::gc::dhp::details::guard native_guard;
+            //@endcond
+
         public:
             // Default ctor
             Guard();   // inline in dhp_impl.h
@@ -364,6 +375,190 @@ namespace cds { namespace gc {
             }
         };
 
+        /// Guarded pointer
+        /**
+            A guarded pointer is a pair of a pointer and GC's guard.
+            Usually, it is used for returning a pointer to the item from an lock-free container.
+            The guard prevents the pointer to be early disposed (freed) by GC.
+            After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
+
+            Template arguments:
+            - \p GuardedType - a type which the guard stores
+            - \p ValueType - a value type
+            - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
+
+            For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
+            In such case the \p %guarded_ptr is:
+            @code
+            typedef cds::gc::DHP::guarded_ptr< foo > intrusive_guarded_ptr;
+            @endcode
+
+            For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
+            For example:
+            @code
+            struct foo {
+                int const   key;
+                std::string value;
+            };
+
+            struct value_accessor {
+                std::string* operator()( foo* pFoo ) const
+                {
+                    return &(pFoo->value);
+                }
+            };
+
+            // Guarded ptr
+            typedef cds::gc::DHP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
+            @endcode
+
+            You don't need use this class directly.
+            All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
+        */
+        template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
+        class guarded_ptr
+        {
+            //@cond
+            struct trivial_cast {
+                ValueType * operator()( GuardedType * p ) const
+                {
+                    return p;
+                }
+            };
+            //@endcond
+
+        public:
+            typedef GuardedType guarded_type; ///< Guarded type
+            typedef ValueType   value_type;   ///< Value type
+
+            /// Functor for casting \p guarded_type to \p value_type
+            typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
+
+            //@cond
+            typedef cds::gc::dhp::details::guard native_guard;
+            //@endcond
+
+        private:
+            //@cond
+            native_guard    m_guard;
+            //@endcond
+
+        public:
+            /// Creates empty guarded pointer
+            guarded_ptr() CDS_NOEXCEPT
+            {}
+
+            //@cond
+            /// Initializes guarded pointer with \p p
+            guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
+            {
+                alloc_guard();
+                assert( m_guard.is_initialized() );
+                m_guard.set( p );
+            }
+            guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
+            {}
+            //@endcond
+
+            /// Move ctor
+            guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
+            {
+                m_guard.set_guard( gp.m_guard.release_guard() );
+            }
+
+            /// The guarded pointer is not copy-constructible
+            guarded_ptr( guarded_ptr const& gp ) = delete;
+
+            /// Clears the guarded pointer
+            /**
+                \ref release is called if guarded pointer is not \ref empty
+            */
+            ~guarded_ptr() CDS_NOEXCEPT
+            {
+                free_guard();
+            }
+
+            /// Move-assignment operator
+            guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
+            {
+                free_guard();
+                m_guard.set_guard( gp.m_guard.release_guard() );
+                return *this;
+            }
+
+            /// The guarded pointer is not copy-assignable
+            guarded_ptr& operator=(guarded_ptr const& gp) = delete;
+
+            /// Returns a pointer to guarded value
+            value_type * operator ->() const CDS_NOEXCEPT
+            {
+                assert( !empty() );
+                return value_cast()( reinterpret_cast<guarded_type *>(m_guard.get()));
+            }
+
+            /// Returns a reference to guarded value
+            value_type& operator *() CDS_NOEXCEPT
+            {
+                assert( !empty());
+                return *value_cast()(reinterpret_cast<guarded_type *>(m_guard.get()));
+            }
+
+            /// Returns const reference to guarded value
+            value_type const& operator *() const CDS_NOEXCEPT
+            {
+                assert( !empty() );
+                return *value_cast()(reinterpret_cast<guarded_type *>(m_guard.get()));
+            }
+
+            /// Checks if the guarded pointer is \p nullptr
+            bool empty() const CDS_NOEXCEPT
+            {
+                return !m_guard.is_initialized() || m_guard.get() == nullptr;
+            }
+
+            /// \p bool operator returns <tt>!empty()</tt>
+            explicit operator bool() const CDS_NOEXCEPT
+            {
+                return !empty();
+            }
+
+            /// Clears guarded pointer
+            /**
+                If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
+                Dereferncing the guarded pointer after \p release() is dangerous.
+            */
+            void release() CDS_NOEXCEPT
+            {
+                if ( m_guard.is_initialized() )
+                    m_guard.clear();
+            }
+
+            //@cond
+            // For internal use only!!!
+            native_guard& guard() CDS_NOEXCEPT
+            {
+                alloc_guard();
+                assert( m_guard.is_initialized() );
+                return m_guard;
+            }
+            //@endcond
+
+        private:
+            //@cond
+            void alloc_guard()
+            {
+                if ( !m_guard.is_initialized() )
+                    thread_gc::alloc_guard( m_guard );
+            }
+
+            void free_guard()
+            {
+                if ( m_guard.is_initialized() )
+                    thread_gc::free_guard( m_guard );
+            }
+            //@endcond
+        };
+
     public:
         /// Initializes dhp::GarbageCollector singleton
         /**
index f4535bd..5028d93 100644 (file)
@@ -23,6 +23,15 @@ namespace cds { namespace gc {
             cds::threading::Manager::detachThread();
     }
 
+    inline /*static*/ void DHP::thread_gc::alloc_guard( cds::gc::dhp::details::guard& g )
+    {
+        return cds::threading::getGC<DHP>().allocGuard(g);
+    }
+    inline /*static*/ void DHP::thread_gc::free_guard( cds::gc::dhp::details::guard& g )
+    {
+        cds::threading::getGC<DHP>().freeGuard(g);
+    }
+
     inline DHP::Guard::Guard()
         : Guard::base_class( cds::threading::getGC<DHP>() )
     {}
index 28c3d5b..72de7d0 100644 (file)
@@ -90,6 +90,12 @@ namespace cds { namespace gc {
                 Otherwise it detaches the current thread from Hazard Pointer GC.
             */
             ~thread_gc() ;  // inline in hp_impl.h
+
+        public: // for internal use only!!!
+            //@cond
+            static cds::gc::hp::details::hp_guard& alloc_guard(); // inline in hp_impl.h
+            static void free_guard( cds::gc::hp::details::hp_guard& g ); // inline in hp_impl.h
+            //@endcond
         };
 
         /// Hazard Pointer guard
@@ -362,6 +368,196 @@ namespace cds { namespace gc {
             }
         };
 
+        /// Guarded pointer
+        /**
+            A guarded pointer is a pair of a pointer and GC's guard.
+            Usually, it is used for returning a pointer to the item from an lock-free container.
+            The guard prevents the pointer to be early disposed (freed) by GC.
+            After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
+
+            Template arguments:
+            - \p GuardedType - a type which the guard stores
+            - \p ValueType - a value type
+            - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
+
+            For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
+            In such case the \p %guarded_ptr is:
+            @code
+            typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
+            @endcode
+
+            For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
+            For example:
+            @code
+            struct foo {
+                int const   key;
+                std::string value;
+            };
+
+            struct value_accessor {
+                std::string* operator()( foo* pFoo ) const
+                {
+                    return &(pFoo->value);
+                }
+            };
+
+            // Guarded ptr
+            typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
+            @endcode
+
+            You don't need use this class directly.
+            All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
+        */
+        template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
+        class guarded_ptr
+        {
+            //@cond
+            struct trivial_cast {
+                ValueType * operator()( GuardedType * p ) const
+                {
+                    return p;
+                }
+            };
+            //@endcond
+
+        public:
+            typedef GuardedType guarded_type; ///< Guarded type
+            typedef ValueType   value_type;   ///< Value type
+
+            /// Functor for casting \p guarded_type to \p value_type
+            typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
+
+            //@cond
+            typedef cds::gc::hp::details::hp_guard native_guard;
+            //@endcond
+
+        private:
+            //@cond
+            native_guard *  m_pGuard;
+            //@endcond
+
+        public:
+            /// Creates empty guarded pointer
+            guarded_ptr() CDS_NOEXCEPT
+                : m_pGuard(nullptr)
+            {}
+
+            //@cond
+            /// Initializes guarded pointer with \p p
+            guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
+            {
+                alloc_guard();
+                assert( m_pGuard );
+                m_pGuard->set(p);
+            }
+            guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
+                : m_pGuard( nullptr )
+            {}
+            //@endcond
+
+            /// Move ctor
+            guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
+                : m_pGuard( gp.m_pGuard )
+            {
+                gp.m_pGuard = nullptr;
+            }
+
+            /// The guarded pointer is not copy-constructible
+            guarded_ptr( guarded_ptr const& gp ) = delete;
+
+            /// Clears the guarded pointer
+            /**
+                \ref release is called if guarded pointer is not \ref empty
+            */
+            ~guarded_ptr() CDS_NOEXCEPT
+            {
+                free_guard();
+            }
+
+            /// Move-assignment operator
+            guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
+            {
+                free_guard();
+                m_pGuard = gp.m_pGuard;
+                gp.m_pGuard = nullptr;
+                return *this;
+            }
+
+            /// The guarded pointer is not copy-assignable
+            guarded_ptr& operator=(guarded_ptr const& gp) = delete;
+
+            /// Returns a pointer to guarded value
+            value_type * operator ->() const CDS_NOEXCEPT
+            {
+                assert( !empty() );
+                return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
+            }
+
+            /// Returns a reference to guarded value
+            value_type& operator *() CDS_NOEXCEPT
+            {
+                assert( !empty());
+                return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
+            }
+
+            /// Returns const reference to guarded value
+            value_type const& operator *() const CDS_NOEXCEPT
+            {
+                assert( !empty() );
+                return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
+            }
+
+            /// Checks if the guarded pointer is \p nullptr
+            bool empty() const CDS_NOEXCEPT
+            {
+                return !m_pGuard || m_pGuard->get() == nullptr;
+            }
+
+            /// \p bool operator returns <tt>!empty()</tt>
+            explicit operator bool() const CDS_NOEXCEPT
+            {
+                return !empty();
+            }
+
+            /// Clears guarded pointer
+            /**
+                If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
+                Dereferncing the guarded pointer after \p release() is dangerous.
+            */
+            void release() CDS_NOEXCEPT
+            {
+                if ( m_pGuard )
+                    m_pGuard->clear();
+            }
+
+            //@cond
+            // For internal use only!!!
+            native_guard& guard() CDS_NOEXCEPT
+            {
+                alloc_guard();
+                assert( m_pGuard );
+                return *m_pGuard;
+            }
+            //@endcond
+
+        private:
+            //@cond
+            void alloc_guard()
+            {
+                if ( !m_pGuard )
+                    m_pGuard = &thread_gc::alloc_guard();
+            }
+
+            void free_guard()
+            {
+                if ( m_pGuard ) {
+                    thread_gc::free_guard( *m_pGuard );
+                    m_pGuard = nullptr;
+                }
+            }
+            //@endcond
+        };
+
     public:
         /// \p scan() type
         enum class scan_type {
index 2b63189..ac39536 100644 (file)
@@ -24,6 +24,16 @@ namespace cds { namespace gc {
             cds::threading::Manager::detachThread();
     }
 
+    inline /*static*/ cds::gc::hp::details::hp_guard& HP::thread_gc::alloc_guard()
+    {
+        return cds::threading::getGC<HP>().allocGuard();
+    }
+
+    inline /*static*/ void HP::thread_gc::free_guard( cds::gc::hp::details::hp_guard& g )
+    {
+        cds::threading::getGC<HP>().freeGuard( g );
+    }
+
     inline HP::Guard::Guard()
         : Guard::base_class( cds::threading::getGC<HP>() )
     {}
index 38df2b5..0b6ec56 100644 (file)
@@ -8,7 +8,6 @@
 #include <cds/opt/compare.h>
 #include <cds/details/binary_functor_wrapper.h>
 #include <cds/urcu/details/check_deadlock.h>
-#include <cds/gc/guarded_ptr.h>
 
 namespace cds { namespace intrusive {
 
@@ -119,7 +118,7 @@ namespace cds { namespace intrusive {
         typedef typename traits::disposer  disposer;    ///< leaf node disposer
         typedef typename traits::back_off  back_off;    ///< back-off strategy
 
-        typedef cds::gc::guarded_ptr< gc, value_type > guarded_ptr; ///< Guarded pointer
+        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
 
     protected:
         //@cond
@@ -1327,16 +1326,15 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q>
-        bool extract_( typename gc::Guard& guard, Q const& key )
+        bool extract_( typename guarded_ptr::native_guard& guard, Q const& key )
         {
-            guarded_ptr gp;
             return erase_( key, node_compare(),
                 []( Q const&, leaf_node const& ) -> bool { return true; },
-                [&guard]( value_type& found ) { guard.assign( &found ); } );
+                [&guard]( value_type& found ) { guard.set( &found ); } );
         }
 
         template <typename Q, typename Less>
-        bool extract_with_( typename gc::Guard& guard, Q const& key, Less pred )
+        bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less pred )
         {
             typedef ellen_bintree::details::compare<
                 key_type,
@@ -1347,10 +1345,10 @@ namespace cds { namespace intrusive {
 
             return erase_( key, compare_functor(),
                 []( Q const&, leaf_node const& ) -> bool { return true; },
-                [&guard]( value_type& found ) { guard.assign( &found ); } );
+                [&guard]( value_type& found ) { guard.set( &found ); } );
         }
 
-        bool extract_max_( typename gc::Guard& gp )
+        bool extract_max_( typename guarded_ptr::native_guard& gp )
         {
             update_desc * pOp = nullptr;
             search_result res;
@@ -1396,11 +1394,11 @@ namespace cds { namespace intrusive {
 
             --m_ItemCounter;
             m_Stat.onExtractMaxSuccess();
-            gp.assign( node_traits::to_value_ptr( res.pLeaf ));
+            gp.set( node_traits::to_value_ptr( res.pLeaf ));
             return true;
         }
 
-        bool extract_min_( typename gc::Guard& gp )
+        bool extract_min_( typename guarded_ptr::native_guard& gp )
         {
             update_desc * pOp = nullptr;
             search_result res;
@@ -1446,7 +1444,7 @@ namespace cds { namespace intrusive {
 
             --m_ItemCounter;
             m_Stat.onExtractMinSuccess();
-            gp.assign( node_traits::to_value_ptr( res.pLeaf ));
+            gp.set( node_traits::to_value_ptr( res.pLeaf ));
             return true;
         }
 
@@ -1490,15 +1488,15 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q>
-        bool get_( typename gc::Guard& guard, Q const& val ) const
+        bool get_( typename guarded_ptr::native_guard& guard, Q const& val ) const
         {
-            return find_( val, [&guard]( value_type& found, Q const& ) { guard.assign( &found ); } );
+            return find_( val, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
         }
 
         template <typename Q, typename Less>
-        bool get_with_( typename gc::Guard& guard, Q const& val, Less pred ) const
+        bool get_with_( typename guarded_ptr::native_guard& guard, Q const& val, Less pred ) const
         {
-            return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.assign( &found ); } );
+            return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
         }
 
         //@endcond
index 274f77e..eda3714 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <mutex>        // unique_lock
 #include <cds/intrusive/details/lazy_list_base.h>
-#include <cds/gc/guarded_ptr.h>
 
 namespace cds { namespace intrusive {
 
index 757bc7a..8c2eadf 100644 (file)
@@ -4,7 +4,6 @@
 #define __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H
 
 #include <cds/intrusive/details/michael_list_base.h>
-#include <cds/gc/guarded_ptr.h>
 #include <cds/details/make_const_type.h>
 
 namespace cds { namespace intrusive {
index 0255a74..86c505e 100644 (file)
@@ -9,7 +9,6 @@
 #include <cds/intrusive/details/skip_list_base.h>
 #include <cds/opt/compare.h>
 #include <cds/details/binary_functor_wrapper.h>
-#include <cds/gc/guarded_ptr.h>
 
 namespace cds { namespace intrusive {
 
index df4d8fb..2f97461 100644 (file)
     <ClInclude Include="..\..\..\cds\gc\details\hp_alloc.h" />\r
     <ClInclude Include="..\..\..\cds\gc\details\hp_type.h" />\r
     <ClInclude Include="..\..\..\cds\gc\dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\gc\guarded_ptr.h" />\r
     <ClInclude Include="..\..\..\cds\gc\impl\dhp_decl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\impl\dhp_impl.h" />\r
     <ClInclude Include="..\..\..\cds\gc\impl\hp_decl.h" />\r
index 0cbfe9d..0fcc08e 100644 (file)
     <ClInclude Include="..\..\..\cds\details\defs.h">\r
       <Filter>Header Files\cds\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\gc\guarded_ptr.h">\r
-      <Filter>Header Files\cds\gc</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\..\cds\details\is_aligned.h">\r
       <Filter>Header Files\cds\details</Filter>\r
     </ClInclude>\r