Removed MSVC 14 (VC 2015) projects
[libcds.git] / cds / algo / atomic.h
index 8cb74bada3e4ad1073b81e3f93f3ab60d19d8ea9..987b6e0452ed7c09c895496cfb1e1bfa9f2f6626 100644 (file)
@@ -32,6 +32,7 @@
 #define CDSLIB_CXX11_ATOMIC_H
 
 #include <cds/details/defs.h>
+#include <cds/user_setup/cache_line.h>
 
 namespace cds {
 
@@ -121,7 +122,7 @@ namespace cds {
                 Returns \p n.
             */
             value_type operator =(
-                value_type n    //< new value of the counter
+                value_type n    ///< new value of the counter
             ) CDS_NOEXCEPT
             {
                 m_counter.exchange( n, atomics::memory_order_relaxed );
@@ -194,17 +195,19 @@ namespace cds {
         /// Atomic item counter
         /**
             This class is simplified interface around \p std::atomic_size_t.
-            The class supports getting of current value of the counter and increment/decrement its value.
+            The class supports getting current value of the counter and increment/decrement its value.
+
+            See also: improved version that eliminates false sharing - \p cache_friendly_item_counter.
         */
         class item_counter
         {
         public:
-            typedef atomics::atomic_size_t   atomic_type ;   ///< atomic type used
-            typedef size_t counter_type    ;   ///< Integral item counter type (size_t)
+            typedef atomics::atomic_size_t   atomic_type;   ///< atomic type used
+            typedef size_t counter_type;                    ///< Integral item counter type (size_t)
 
         private:
             //@cond
-            atomic_type                         m_Counter   ;   ///< Atomic item counter
+            atomic_type     m_Counter;   ///< Atomic item counter
             //@endcond
 
         public:
@@ -243,12 +246,143 @@ namespace cds {
                 return m_Counter.fetch_add( 1, order );
             }
 
+            /// Increments the counter. Semantics: postincrement
+            counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+            {
+                return m_Counter.fetch_add( count, order );
+            }
+
+            /// Decrements the counter. Semantics: postdecrement
+            counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
+            {
+                return m_Counter.fetch_sub( 1, order );
+            }
+
+            /// Decrements the counter. Semantics: postdecrement
+            counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+            {
+                return m_Counter.fetch_sub( count, order );
+            }
+
+            /// Preincrement
+            counter_type operator ++()
+            {
+                return inc() + 1;
+            }
+            /// Postincrement
+            counter_type operator ++(int)
+            {
+                return inc();
+            }
+
+            /// Predecrement
+            counter_type operator --()
+            {
+                return dec() - 1;
+            }
+            /// Postdecrement
+            counter_type operator --(int)
+            {
+                return dec();
+            }
+
+            /// Increment by \p count
+            counter_type operator +=( counter_type count )
+            {
+                return inc( count ) + count;
+            }
+
+            /// Decrement by \p count
+            counter_type operator -=( counter_type count )
+            {
+                return dec( count ) - count;
+            }
+
+            /// Resets count to 0
+            void reset(atomics::memory_order order = atomics::memory_order_relaxed)
+            {
+                m_Counter.store( 0, order );
+            }
+        };
+
+#if CDS_COMPILER == CDS_COMPILER_CLANG
+    // CLang unhappy: pad1_ and pad2_ - unused private field warning
+#   pragma GCC diagnostic push
+#   pragma GCC diagnostic ignored "-Wunused-private-field"
+#endif
+        /// Atomic cache-friendly item counter
+        /**
+            Atomic item counter with cache-line padding to avoid false sharing.
+            Adding cache-line padding before and after atomic counter eliminates the contention
+            in read path of many containers and can notably improve search operations in sets/maps.
+        */
+        class cache_friendly_item_counter
+        {
+        public:
+            typedef atomics::atomic_size_t   atomic_type;   ///< atomic type used
+            typedef size_t counter_type;                    ///< Integral item counter type (size_t)
+
+        private:
+            //@cond
+            char            pad1_[cds::c_nCacheLineSize];
+            atomic_type     m_Counter;   ///< Atomic item counter
+            char            pad2_[cds::c_nCacheLineSize - sizeof( atomic_type )];
+            //@endcond
+
+        public:
+            /// Default ctor initializes the counter to zero.
+            cache_friendly_item_counter()
+                : m_Counter(counter_type(0))
+            {}
+
+            /// Returns current value of the counter
+            counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
+            {
+                return m_Counter.load( order );
+            }
+
+            /// Same as \ref value() with relaxed memory ordering
+            operator counter_type() const
+            {
+                return value();
+            }
+
+            /// Returns underlying atomic interface
+            atomic_type& getAtomic()
+            {
+                return m_Counter;
+            }
+
+            /// Returns underlying atomic interface (const)
+            const atomic_type& getAtomic() const
+            {
+                return m_Counter;
+            }
+
+            /// Increments the counter. Semantics: postincrement
+            counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
+            {
+                return m_Counter.fetch_add( 1, order );
+            }
+
+            /// Increments the counter. Semantics: postincrement
+            counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+            {
+                return m_Counter.fetch_add( count, order );
+            }
+
             /// Decrements the counter. Semantics: postdecrement
             counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
             {
                 return m_Counter.fetch_sub( 1, order );
             }
 
+            /// Decrements the counter. Semantics: postdecrement
+            counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+            {
+                return m_Counter.fetch_sub( count, order );
+            }
+
             /// Preincrement
             counter_type operator ++()
             {
@@ -271,12 +405,27 @@ namespace cds {
                 return dec();
             }
 
+            /// Increment by \p count
+            counter_type operator +=( counter_type count )
+            {
+                return inc( count ) + count;
+            }
+
+            /// Decrement by \p count
+            counter_type operator -=( counter_type count )
+            {
+                return dec( count ) - count;
+            }
+
             /// Resets count to 0
             void reset(atomics::memory_order order = atomics::memory_order_relaxed)
             {
                 m_Counter.store( 0, order );
             }
         };
+#if CDS_COMPILER == CDS_COMPILER_CLANG
+#   pragma GCC diagnostic pop
+#endif
 
         /// Empty item counter
         /**
@@ -303,36 +452,62 @@ namespace cds {
             }
 
             /// Dummy increment. Always returns 0
-            static size_t inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+            static counter_type inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+            {
+                return 0;
+            }
+
+            /// Dummy increment. Always returns 0
+            static counter_type inc( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
+            {
+                return 0;
+            }
+
+            /// Dummy increment. Always returns 0
+            static counter_type dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
             {
                 return 0;
             }
 
             /// Dummy increment. Always returns 0
-            static size_t dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+            static counter_type dec( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
             {
                 return 0;
             }
 
             /// Dummy pre-increment. Always returns 0
-            size_t operator ++() const
+            counter_type operator ++() const
             {
                 return 0;
             }
             /// Dummy post-increment. Always returns 0
-            size_t operator ++(int) const
+            counter_type operator ++(int) const
             {
                 return 0;
             }
 
             /// Dummy pre-decrement. Always returns 0
-            size_t operator --() const
+            counter_type operator --() const
             {
                 return 0;
             }
             /// Dummy post-decrement. Always returns 0
-            size_t operator --(int) const
+            counter_type operator --(int) const
+            {
+                return 0;
+            }
+
+            /// Dummy increment by \p count, always returns 0
+            counter_type operator +=( counter_type count )
+            {
+                CDS_UNUSED( count );
+                return 0;
+            }
+
+            /// Dummy decrement by \p count, always returns 0
+            counter_type operator -=( counter_type count )
             {
+                CDS_UNUSED( count );
                 return 0;
             }