Move libcds 1.6.0 from SVN
[libcds.git] / cds / details / marked_ptr.h
diff --git a/cds/details/marked_ptr.h b/cds/details/marked_ptr.h
new file mode 100644 (file)
index 0000000..3645e05
--- /dev/null
@@ -0,0 +1,374 @@
+//$$CDS-header$$
+
+#ifndef __CDS_DETAILS_MARKED_PTR_H
+#define __CDS_DETAILS_MARKED_PTR_H
+
+#include <cds/cxx11_atomic.h>
+
+namespace cds {
+    namespace details {
+
+        /// Marked pointer
+        /**
+            On the modern architectures, the default data alignment is 4 (for 32bit) or 8 byte for 64bit.
+            Therefore, the least 2 or 3 bits of the pointer is always zero and can
+            be used as a bitfield to store logical flags. This trick is widely used in
+            lock-free programming to operate with the pointer and its flags atomically.
+
+            Template parameters:
+            - T - type of pointer
+            - Bitmask - bitmask of least unused bits
+        */
+        template <typename T, int Bitmask>
+        class marked_ptr
+        {
+            T *     m_ptr   ;   ///< pointer and its mark bits
+
+        public:
+            typedef T       value_type      ;       ///< type of value the class points to
+            typedef T *     pointer_type    ;       ///< type of pointer
+            static CDS_CONSTEXPR_CONST uintptr_t bitmask = Bitmask  ;   ///< bitfield bitmask
+            static CDS_CONSTEXPR_CONST uintptr_t pointer_bitmask = ~bitmask ; ///< pointer bitmask
+
+        public:
+            /// Constructs null marked pointer. The flag is cleared.
+            CDS_CONSTEXPR marked_ptr() CDS_NOEXCEPT
+                : m_ptr( null_ptr<pointer_type>() )
+            {}
+
+            /// Constructs marked pointer with \p ptr value. The least bit(s) of \p ptr is the flag.
+            CDS_CONSTEXPR explicit marked_ptr( value_type * ptr ) CDS_NOEXCEPT
+                : m_ptr( ptr )
+            {}
+
+            /// Constructs marked pointer with \p ptr value and \p nMask flag.
+            /**
+                The \p nMask argument defines the OR-bits
+            */
+            marked_ptr( value_type * ptr, int nMask ) CDS_NOEXCEPT
+                : m_ptr( ptr )
+            {
+                assert( bits() == 0 );
+                *this |= nMask;
+            }
+
+#   ifdef CDS_CXX11_EXPLICITLY_DEFAULTED_FUNCTION_SUPPORT
+            /// Copy constructor
+            marked_ptr( marked_ptr const& src ) CDS_NOEXCEPT_DEFAULTED = default;
+            /// Copy-assignment operator
+            marked_ptr& operator =( marked_ptr const& p ) CDS_NOEXCEPT_DEFAULTED = default;
+#       if defined(CDS_MOVE_SEMANTICS_SUPPORT) && !defined(CDS_DISABLE_DEFAULT_MOVE_CTOR)
+            //@cond
+            marked_ptr( marked_ptr&& src ) CDS_NOEXCEPT_DEFAULTED = default;
+            marked_ptr& operator =( marked_ptr&& p ) CDS_NOEXCEPT_DEFAULTED = default;
+            //@endcond
+#       endif
+#   else
+            /// Copy constructor
+            marked_ptr( marked_ptr const& src ) CDS_NOEXCEPT
+                : m_ptr( src.m_ptr )
+            {}
+
+            /// Copy-assignment operator
+            marked_ptr& operator =( marked_ptr const& p ) CDS_NOEXCEPT
+            {
+                m_ptr = p.m_ptr;
+                return *this;
+            }
+#   endif
+
+            //TODO: make move ctor
+
+        private:
+            //@cond
+            static uintptr_t   to_int( value_type * p ) CDS_NOEXCEPT
+            {
+                return reinterpret_cast<uintptr_t>( p );
+            }
+
+            static value_type * to_ptr( uintptr_t n ) CDS_NOEXCEPT
+            {
+                return reinterpret_cast< value_type *>( n );
+            }
+
+            uintptr_t   to_int() const CDS_NOEXCEPT
+            {
+                return to_int( m_ptr );
+            }
+            //@endcond
+
+        public:
+            /// Returns the pointer without mark bits (real pointer) const version
+            value_type *        ptr() const CDS_NOEXCEPT
+            {
+                return to_ptr( to_int() & ~bitmask );
+            }
+
+            /// Returns the pointer and bits together
+            value_type *        all() const CDS_NOEXCEPT
+            {
+                return m_ptr;
+            }
+
+            /// Returns the least bits of pointer according to \p Bitmask template argument of the class
+            uintptr_t bits() const CDS_NOEXCEPT
+            {
+                return to_int() & bitmask;
+            }
+
+            /// Analogue for \ref ptr
+            value_type * operator ->() const CDS_NOEXCEPT
+            {
+                return ptr();
+            }
+
+            /// Assignment operator sets markup bits to zero
+            marked_ptr operator =( T * p ) CDS_NOEXCEPT
+            {
+                m_ptr = p;
+                return *this;
+            }
+
+            /// Set LSB bits as <tt>bits() | nBits</tt>
+            marked_ptr& operator |=( int nBits ) CDS_NOEXCEPT
+            {
+                assert( (nBits & pointer_bitmask) == 0 );
+                m_ptr = to_ptr( to_int() | nBits );
+                return *this;
+            }
+
+            /// Set LSB bits as <tt>bits() & nBits</tt>
+            marked_ptr& operator &=( int nBits ) CDS_NOEXCEPT
+            {
+                assert( (nBits & pointer_bitmask) == 0 );
+                m_ptr = to_ptr( to_int() & (pointer_bitmask | nBits) );
+                return *this;
+            }
+
+            /// Set LSB bits as <tt>bits() ^ nBits</tt>
+            marked_ptr& operator ^=( int nBits ) CDS_NOEXCEPT
+            {
+                assert( (nBits & pointer_bitmask) == 0 );
+                m_ptr = to_ptr( to_int() ^ nBits );
+                return *this;
+            }
+
+            /// Returns <tt>p |= nBits</tt>
+            friend marked_ptr operator |( marked_ptr p, int nBits) CDS_NOEXCEPT
+            {
+                p |= nBits;
+                return p;
+            }
+
+            /// Returns <tt>p |= nBits</tt>
+            friend marked_ptr operator |( int nBits, marked_ptr p ) CDS_NOEXCEPT
+            {
+                p |= nBits;
+                return p;
+            }
+
+            /// Returns <tt>p &= nBits</tt>
+            friend marked_ptr operator &( marked_ptr p, int nBits) CDS_NOEXCEPT
+            {
+                p &= nBits;
+                return p;
+            }
+
+            /// Returns <tt>p &= nBits</tt>
+            friend marked_ptr operator &( int nBits, marked_ptr p ) CDS_NOEXCEPT
+            {
+                p &= nBits;
+                return p;
+            }
+
+            /// Returns <tt>p ^= nBits</tt>
+            friend marked_ptr operator ^( marked_ptr p, int nBits) CDS_NOEXCEPT
+            {
+                p ^= nBits;
+                return p;
+            }
+            /// Returns <tt>p ^= nBits</tt>
+            friend marked_ptr operator ^( int nBits, marked_ptr p ) CDS_NOEXCEPT
+            {
+                p ^= nBits;
+                return p;
+            }
+
+            /// Inverts LSBs of pointer \p p
+            friend marked_ptr operator ~( marked_ptr p ) CDS_NOEXCEPT
+            {
+                return p ^ marked_ptr::bitmask;
+            }
+
+
+            /// Comparing two marked pointer including its mark bits
+            friend bool operator ==( marked_ptr p1, marked_ptr p2 ) CDS_NOEXCEPT
+            {
+                return p1.all() == p2.all();
+            }
+
+            /// Comparing marked pointer and raw pointer, mark bits of \p p1 is ignored
+            friend bool operator ==( marked_ptr p1, value_type const * p2 ) CDS_NOEXCEPT
+            {
+                return p1.ptr() == p2;
+            }
+
+            /// Comparing marked pointer and raw pointer, mark bits of \p p2 is ignored
+            friend bool operator ==( value_type const * p1, marked_ptr p2 ) CDS_NOEXCEPT
+            {
+                return p1 == p2.ptr();
+            }
+
+            /// Comparing two marked pointer including its mark bits
+            friend bool operator !=( marked_ptr p1, marked_ptr p2 ) CDS_NOEXCEPT
+            {
+                return p1.all() != p2.all();
+            }
+
+            /// Comparing marked pointer and raw pointer, mark bits of \p p1 is ignored
+            friend bool operator !=( marked_ptr p1, value_type const * p2 ) CDS_NOEXCEPT
+            {
+                return p1.ptr() != p2;
+            }
+
+            /// Comparing marked pointer and raw pointer, mark bits of \p p2 is ignored
+            friend bool operator !=( value_type const * p1, marked_ptr p2 ) CDS_NOEXCEPT
+            {
+                return p1 != p2.ptr();
+            }
+
+            //@cond
+            /// atomic< marked_ptr< T, Bitmask > > support
+            T *& impl_ref() CDS_NOEXCEPT
+            {
+                return m_ptr;
+            }
+            //@endcond
+        };
+    }   // namespace details
+
+}   // namespace cds
+
+//@cond
+CDS_CXX11_ATOMIC_BEGIN_NAMESPACE
+
+    template <typename T, int Bitmask >
+    class atomic< cds::details::marked_ptr<T, Bitmask> >
+    {
+    private:
+        typedef cds::details::marked_ptr<T, Bitmask> marked_ptr;
+        typedef CDS_ATOMIC::atomic<T *>  atomic_impl;
+
+        atomic_impl m_atomic;
+    public:
+        bool is_lock_free() const volatile CDS_NOEXCEPT
+        {
+            return m_atomic.is_lock_free();
+        }
+        bool is_lock_free() const CDS_NOEXCEPT
+        {
+            return m_atomic.is_lock_free();
+        }
+
+        void store(marked_ptr val, memory_order order = memory_order_seq_cst) volatile CDS_NOEXCEPT
+        {
+            m_atomic.store( val.all(), order );
+        }
+        void store(marked_ptr val, memory_order order = memory_order_seq_cst) CDS_NOEXCEPT
+        {
+            m_atomic.store( val.all(), order );
+        }
+
+        marked_ptr load(memory_order order = memory_order_seq_cst) const volatile CDS_NOEXCEPT
+        {
+            return marked_ptr( m_atomic.load( order ));
+        }
+        marked_ptr load(memory_order order = memory_order_seq_cst) const CDS_NOEXCEPT
+        {
+            return marked_ptr( m_atomic.load( order ));
+        }
+
+        operator marked_ptr() const volatile CDS_NOEXCEPT
+        {
+            return load();
+        }
+        operator marked_ptr() const CDS_NOEXCEPT
+        {
+            return load();
+        }
+
+        marked_ptr exchange(marked_ptr val, memory_order order = memory_order_seq_cst) volatile CDS_NOEXCEPT
+        {
+            return marked_ptr( m_atomic.exchange( val.all(), order ));
+        }
+        marked_ptr exchange(marked_ptr val, memory_order order = memory_order_seq_cst) CDS_NOEXCEPT
+        {
+            return marked_ptr( m_atomic.exchange( val.all(), order ));
+        }
+
+        bool compare_exchange_weak(marked_ptr& expected, marked_ptr desired, memory_order success_order, memory_order failure_order) volatile CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_weak( expected.impl_ref(), desired.all(), success_order, failure_order );
+        }
+        bool compare_exchange_weak(marked_ptr& expected, marked_ptr desired, memory_order success_order, memory_order failure_order) CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_weak( expected.impl_ref(), desired.all(), success_order, failure_order );
+        }
+        bool compare_exchange_strong(marked_ptr& expected, marked_ptr desired, memory_order success_order, memory_order failure_order) volatile CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_strong( expected.impl_ref(), desired.all(), success_order, failure_order );
+        }
+        bool compare_exchange_strong(marked_ptr& expected, marked_ptr desired, memory_order success_order, memory_order failure_order) CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_strong( expected.impl_ref(), desired.all(), success_order, failure_order );
+        }
+        bool compare_exchange_weak(marked_ptr& expected, marked_ptr desired, memory_order success_order = memory_order_seq_cst) volatile CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_weak( expected.impl_ref(), desired.all(), success_order );
+        }
+        bool compare_exchange_weak(marked_ptr& expected, marked_ptr desired, memory_order success_order = memory_order_seq_cst) CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_weak( expected.impl_ref(), desired.all(), success_order );
+        }
+        bool compare_exchange_strong(marked_ptr& expected, marked_ptr desired, memory_order success_order = memory_order_seq_cst) volatile CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_strong( expected.impl_ref(), desired.all(), success_order );
+        }
+        bool compare_exchange_strong(marked_ptr& expected, marked_ptr desired, memory_order success_order = memory_order_seq_cst) CDS_NOEXCEPT
+        {
+            return m_atomic.compare_exchange_strong( expected.impl_ref(), desired.all(), success_order );
+        }
+
+        CDS_CONSTEXPR atomic() CDS_NOEXCEPT
+            : m_atomic( cds::null_ptr<T *>() )
+        {}
+
+        CDS_CONSTEXPR explicit atomic(marked_ptr val) CDS_NOEXCEPT
+            : m_atomic( val.all() )
+        {}
+        CDS_CONSTEXPR explicit atomic(T * p) CDS_NOEXCEPT
+            : m_atomic( p )
+        {}
+
+#   ifdef CDS_CXX11_DELETE_DEFINITION_SUPPORT
+        atomic(const atomic&) = delete;
+        atomic& operator=(const atomic&) = delete;
+        atomic& operator=(const atomic&) volatile = delete;
+#   endif
+
+        marked_ptr operator=(marked_ptr val) volatile CDS_NOEXCEPT
+        {
+            store( val );
+            return val;
+        }
+        marked_ptr operator=(marked_ptr val) CDS_NOEXCEPT
+        {
+            store( val );
+            return val;
+        }
+    };
+
+CDS_CXX11_ATOMIC_END_NAMESPACE
+//@endcond
+
+#endif  // #ifndef __CDS_DETAILS_MARKED_PTR_H