LCOV - code coverage report
Current view: top level - utilities/include/mcrl2/utilities - shared_reference.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 68 69 98.6 %
Date: 2024-03-08 02:52:28 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Maurice Laveaux
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : 
      10             : #ifndef MCRL2_UTILITIES_SHARED_REFERENCE_H_
      11             : #define MCRL2_UTILITIES_SHARED_REFERENCE_H_
      12             : 
      13             : #include "tagged_pointer.h"
      14             : 
      15             : #include <cassert>
      16             : #include <atomic>
      17             : #include <type_traits>
      18             : 
      19             : #include "mcrl2/utilities/tagged_pointer.h"
      20             : 
      21             : namespace mcrl2
      22             : {
      23             : namespace utilities
      24             : {
      25             : 
      26             : /// \brief Enable to count the number of reference count changes.
      27             : constexpr static bool EnableReferenceCountMetrics = false;
      28             : 
      29             : /// \brief Stores a reference count that can be incremented and decremented.
      30             : /// \details The template variable is such that reference_count_changes corresponds
      31             : ///          to the amount of times the reference count of type T changed.
      32             : template<typename T, bool ThreadSafe = false>
      33             : class shared_reference_counted
      34             : {
      35             : public:
      36       75817 :   shared_reference_counted()
      37       75817 :     : m_reference_count(0)
      38       75817 :   {}
      39             : 
      40             :   /// \brief Obtain the reference count.
      41       29604 :   std::size_t reference_count() const
      42             :   {
      43       29604 :     return m_reference_count;
      44             :   }
      45             : 
      46             :   /// \brief Increment the reference count by one.
      47     3169404 :   void increment_reference_count() const
      48             :   {
      49             :     if constexpr (ThreadSafe)
      50             :     {
      51     3169404 :       m_reference_count.fetch_add(1, std::memory_order_relaxed);
      52             :     }
      53             :     else
      54             :     {
      55             :       ++m_reference_count;
      56             :     }
      57     3169404 :     count_reference_count_changes();
      58     3169404 :   }
      59             : 
      60             :   /// \brief Decrement the reference count by one.
      61     2266857 :   void decrement_reference_count() const
      62             :   {
      63             :     if constexpr (ThreadSafe)
      64             :     {
      65     2266857 :       m_reference_count.fetch_sub(1, std::memory_order_release);
      66             :     }
      67             :     else
      68             :     {
      69             :       --m_reference_count;
      70             :     }
      71     2266857 :     count_reference_count_changes();
      72     2266857 :   }
      73             : 
      74             :   /// \brief Obtain the number of times that this reference count has changed.
      75             :   static std::atomic<std::size_t>& reference_count_changes()
      76             :   {
      77             :     static std::atomic<std::size_t> g_reference_count_changes;
      78             :     return g_reference_count_changes;
      79             :   }
      80             : 
      81             :   /// \brief Increment the number of reference count changes.
      82     5436261 :   static void count_reference_count_changes()
      83             :   {
      84             :     if constexpr (EnableReferenceCountMetrics)
      85             :     {
      86             :       ++reference_count_changes();
      87             :     }
      88     5436261 :   }
      89             : 
      90             : protected:
      91             :   using SizeType = typename std::conditional<ThreadSafe, std::atomic<std::size_t>, std::size_t>::type;
      92             : 
      93             :   // The underlying reference counter can always be changed.
      94             :   mutable SizeType m_reference_count;
      95             : };
      96             : 
      97             : /// \brief A reference counted reference to a shared_reference_counted object.
      98             : /// \details Similar to a shared_ptr except that reference counts are only atomic when
      99             : ///          thread safety is desired and that it stores the reference count in the
     100             : ///          inherited object.
     101             : template<typename T>
     102             : class shared_reference
     103             : {
     104             : public:
     105             : 
     106             :   /// \brief The default constructor.
     107       15715 :   shared_reference() noexcept
     108       15715 :     : m_reference(nullptr)
     109       15715 :   {}
     110             : 
     111             :   /// \brief Takes ownership of the passed reference, which means
     112             :   ///        that its reference count is incremented.
     113     1095235 :   shared_reference(T* reference) noexcept
     114     1095235 :     : m_reference(reference)
     115             :   {
     116     1095235 :     assert(defined());
     117     1095235 :     m_reference->increment_reference_count();
     118     1095235 :   }
     119             : 
     120             :   /// \brief Copy constructor.
     121     2071644 :   shared_reference(const shared_reference<T>& other) noexcept
     122     2071644 :     : m_reference(other.m_reference)
     123             :   {
     124     2071644 :     if (defined())
     125             :     {
     126     2071581 :       m_reference->increment_reference_count();
     127             :     }
     128     2071644 :   }
     129             : 
     130             :   /// \brief Move constructor.
     131     1095235 :   shared_reference(shared_reference<T>&& other) noexcept
     132     1095235 :     : m_reference(other.m_reference)
     133             :   {
     134     1095235 :     other.m_reference = nullptr;
     135     1095235 :   }
     136             : 
     137     3374799 :   ~shared_reference()
     138             :   {
     139     3374799 :     if (defined())
     140             :     {
     141     2266856 :       m_reference->decrement_reference_count();
     142             :     }
     143     3374799 :   }
     144             : 
     145             :   /// \brief Copy assignment constructor.
     146        2588 :   shared_reference<T>& operator=(const shared_reference<T>& other) noexcept
     147             :   {
     148             :     // Increment first to prevent the same reference from getting a reference count of zero temporarily.
     149        2588 :     if (other.defined())
     150             :     {
     151        2588 :       other.m_reference->increment_reference_count();
     152             :     }
     153             : 
     154             :     // Decrement the reference from the reference that is currently referred to.
     155        2588 :     if (defined())
     156             :     {
     157           0 :       m_reference->decrement_reference_count();
     158             :     }
     159             : 
     160        2588 :     m_reference=other.m_reference;
     161        2588 :     return *this;
     162             :   }
     163             : 
     164             :   /// \brief Move assignment constructor.
     165       12405 :   shared_reference<T>& operator=(shared_reference<T>&& other) noexcept
     166             :   {
     167       12405 :     if (defined())
     168             :     {
     169           1 :       m_reference->decrement_reference_count();
     170             :     }
     171             : 
     172       12405 :     m_reference = other.m_reference;
     173       12405 :     other.m_reference = nullptr;
     174       12405 :     return *this;
     175             :   }
     176             : 
     177             :   /// \brief Check whether the shared_reference has a valid reference.
     178 13101084348 :   bool defined() const
     179             :   {
     180 13101084348 :     return m_reference.get() != nullptr;
     181             :   }
     182             : 
     183 70186438114 :   bool operator ==(const shared_reference<T>& other) const noexcept
     184             :   {
     185 70186438114 :     return m_reference == other.m_reference;
     186             :   }
     187             : 
     188             :   bool operator <(const shared_reference<T>& other) const noexcept
     189             :   {
     190             :     return m_reference < other.m_reference;
     191             :   }
     192             : 
     193             :   // Comparison operators follow from equivalence and less than.
     194  6370075682 :   bool operator !=(const shared_reference<T>& other) const noexcept
     195             :   {
     196  6370075682 :     return m_reference != other.m_reference;
     197             :   }
     198             : 
     199             :   bool operator <=(const shared_reference<T>& other) const noexcept
     200             :   {
     201             :     return m_reference <= other.m_reference;
     202             :   }
     203             : 
     204             :   bool operator >(const shared_reference<T>& other) const noexcept
     205             :   {
     206             :     return m_reference > other.m_reference;
     207             :   }
     208             : 
     209             :   bool operator >=(const shared_reference& other) const noexcept
     210             :   {
     211             :     return m_reference >= other.m_reference;
     212             :   }
     213             : 
     214 12932941156 :   T* operator->() const noexcept
     215             :   {
     216 12932941156 :     assert(defined());
     217 12932941156 :     return m_reference.get();
     218             :   }
     219             : 
     220   159265419 :   T* get() const noexcept
     221             :   {
     222   159265419 :     assert(defined());
     223   159265419 :     return m_reference.get();
     224             :   }
     225             : 
     226             :   T& operator*() const noexcept
     227             :   {
     228             :     assert(defined());
     229             :     return *m_reference;
     230             :   }
     231             : 
     232             :   /// \brief Swaps *this with the other shared reference.
     233             :   void swap(shared_reference<T>& other)
     234             :   {
     235             :     m_reference.swap(other.m_reference);
     236             :   }
     237             : 
     238     6546423 :   bool tagged() const noexcept
     239             :   {
     240     6546423 :     return m_reference.tagged();
     241             :   }
     242             : 
     243       48405 :   void tag() const
     244             :   {
     245       48405 :     m_reference.tag();
     246       48405 :   }
     247             : 
     248       29474 :   void untag() const
     249             :   {
     250       29474 :     m_reference.untag();
     251       29474 :   }
     252             : 
     253             : private:
     254             :   mutable utilities::tagged_pointer<T> m_reference;
     255             : };
     256             : 
     257             : } // namespace utilities
     258             : } // namespace mcrl2
     259             : 
     260             : namespace std
     261             : {
     262             : 
     263             : template<typename T>
     264             : void swap(mcrl2::utilities::shared_reference<T>& a, mcrl2::utilities::shared_reference<T>& b) noexcept
     265             : {
     266             :   a.swap(b);
     267             : }
     268             : 
     269             : } // namespace std
     270             : 
     271             : #endif // MCRL2_UTILITIES_SHARED_REFERENCE_H_

Generated by: LCOV version 1.14