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: 56 57 98.2 %
Date: 2020-02-21 00:44:40 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 <cassert>
      14             : #include <atomic>
      15             : #include <type_traits>
      16             : 
      17             : namespace mcrl2
      18             : {
      19             : namespace utilities
      20             : {
      21             : 
      22             : /// \brief Enable to count the number of reference count changes.
      23             : constexpr static bool EnableReferenceCountMetrics = false;
      24             : 
      25             : /// \brief Stores a reference count that can be incremented and decremented.
      26             : /// \details The template variable is such that reference_count_changes corresponds
      27             : ///          to the amount of times the reference count of type T changed.
      28             : template<typename T, bool ThreadSafe = false>
      29             : class shared_reference_counted
      30             : {
      31             : public:
      32      841449 :   shared_reference_counted()
      33      841449 :     : m_reference_count(0)
      34      841449 :   {}
      35             : 
      36             :   /// \brief Obtain the reference count.
      37     1698765 :   std::size_t reference_count() const
      38             :   {
      39     1698765 :     return m_reference_count;
      40             :   }
      41             : 
      42             :   /// \brief Increment the reference count by one.
      43   671152479 :   void increment_reference_count() const
      44             :   {
      45   671152479 :     ++m_reference_count;
      46   671152479 :     increment_reference_count_changes();
      47   671152479 :   }
      48             : 
      49             :   /// \brief Decrement the reference count by one.
      50   670277729 :   void decrement_reference_count() const
      51             :   {
      52   670277729 :     --m_reference_count;
      53   670277729 :     increment_reference_count_changes();
      54   670277729 :   }
      55             : 
      56             :   /// \brief Obtain the number of times that this reference count has changed.
      57             :   static std::size_t& reference_count_changes()
      58             :   {
      59             :     static std::size_t g_reference_count_changes;
      60             :     return g_reference_count_changes;
      61             :   }
      62             : 
      63             :   /// \brief Increment the number of reference count changes.
      64  1341430216 :   static void increment_reference_count_changes()
      65             :   {
      66             :     if (EnableReferenceCountMetrics)
      67             :     {
      68             :       ++reference_count_changes();
      69             :     }
      70  1341430216 :   }
      71             : 
      72             : protected:
      73             :   using SizeType = typename std::conditional<ThreadSafe, std::atomic<std::size_t>, std::size_t>::type;
      74             : 
      75             :   // The underlying reference counter can always be changed.
      76             :   mutable SizeType m_reference_count;
      77             : };
      78             : 
      79             : /// \brief A reference counted reference to a shared_reference_counted object.
      80             : /// \details Similar to a shared_ptr except that reference counts are only atomic when
      81             : ///          thread safety is desired and that it stores the reference count in the
      82             : ///          inherited object.
      83             : template<typename T>
      84             : class shared_reference
      85             : {
      86             : public:
      87             : 
      88             :   /// \brief The default constructor.
      89        1533 :   shared_reference() noexcept
      90        1533 :     : m_reference(nullptr)
      91        1533 :   {}
      92             : 
      93             :   /// \brief Takes ownership of the passed reference, which means
      94             :   ///        that its reference count is incremented.
      95     1433833 :   shared_reference(T* reference) noexcept
      96     1433833 :     : m_reference(reference)
      97             :   {
      98     1433833 :     assert(defined());
      99     1433833 :     m_reference->increment_reference_count();
     100     1433833 :   }
     101             : 
     102             :   /// \brief Takes a reference, but do not changes the reference counter.
     103             :   shared_reference(T* reference, bool) noexcept
     104             :     : m_reference(reference)
     105             :   {}
     106             : 
     107             :   /// \brief Copy constructor.
     108     1100324 :   shared_reference(const shared_reference<T>& other) noexcept
     109     1100324 :     : m_reference(other.m_reference)
     110             :   {
     111     1100324 :     if (defined())
     112             :     {
     113     1100212 :       m_reference->increment_reference_count();
     114             :     }
     115     1100324 :   }
     116             : 
     117             :   /// \brief Move constructor.
     118     1435446 :   shared_reference(shared_reference<T>&& other) noexcept
     119     1435446 :     : m_reference(other.m_reference)
     120             :   {
     121     1435446 :     other.m_reference = nullptr;
     122     1435446 :   }
     123             : 
     124             :   /// \brief Copy assignment constructor.
     125         423 :   shared_reference<T>& operator=(const shared_reference<T>& other) noexcept
     126             :   {
     127             :     // Increment first to prevent the same reference from getting a reference count of zero temporarily.
     128         423 :     if (other.defined())
     129             :     {
     130         423 :       other.m_reference->increment_reference_count();
     131             :     }
     132             : 
     133             :     // Decrement the reference from the reference that is currently referred to.
     134         423 :     if (defined())
     135             :     {
     136           0 :       m_reference->decrement_reference_count();
     137             :     }
     138             : 
     139         423 :     m_reference=other.m_reference;
     140         423 :     return *this;
     141             :   }
     142             : 
     143             :   /// \brief Move assignment constructor.
     144        1402 :   shared_reference<T>& operator=(shared_reference<T>&& other) noexcept
     145             :   {
     146        1402 :     if (defined())
     147             :     {
     148           1 :       m_reference->decrement_reference_count();
     149             :     }
     150             : 
     151        1402 :     m_reference = other.m_reference;
     152        1402 :     other.m_reference = nullptr;
     153        1402 :     return *this;
     154             :   }
     155             : 
     156             :   /// \brief Check whether the shared_reference has a valid reference.
     157  2856870427 :   bool defined() const
     158             :   {
     159  2856870427 :     return m_reference != nullptr;
     160             :   }
     161             : 
     162  8614248616 :   bool operator ==(const shared_reference<T>& other) const noexcept
     163             :   {
     164  8614248616 :     return m_reference == other.m_reference;
     165             :   }
     166             : 
     167             :   bool operator <(const shared_reference<T>& other) const noexcept
     168             :   {
     169             :     return m_reference < other.m_reference;
     170             :   }
     171             : 
     172             :   // Comparison operators follow from equivalence and less than.
     173  1246669093 :   bool operator !=(const shared_reference<T>& other) const noexcept
     174             :   {
     175  1246669093 :     return m_reference != other.m_reference;
     176             :   }
     177             : 
     178             :   bool operator <=(const shared_reference<T>& other) const noexcept
     179             :   {
     180             :     return m_reference <= other.m_reference;
     181             :   }
     182             : 
     183             :   bool operator >(const shared_reference<T>& other) const noexcept
     184             :   {
     185             :     return m_reference > other.m_reference;
     186             :   }
     187             : 
     188             :   bool operator >=(const shared_reference& other) const noexcept
     189             :   {
     190             :     return m_reference >= other.m_reference;
     191             :   }
     192             : 
     193  2719443066 :   T* operator->() const noexcept
     194             :   {
     195  2719443066 :     assert(defined());
     196  2719443066 :     return m_reference;
     197             :   }
     198             : 
     199   133170232 :   T* get() const noexcept
     200             :   {
     201   133170232 :     assert(defined());
     202   133170232 :     return m_reference;
     203             :   }
     204             : 
     205             :   T& operator*() const noexcept
     206             :   {
     207             :     assert(defined());
     208             :     return *m_reference;
     209             :   }
     210             : 
     211             :   /// \brief Swaps *this with the other shared reference.
     212             :   /// \details Prevents the change of any reference count adaptations
     213             :   void swap(shared_reference<T>& other)
     214             :   {
     215             :     using std::swap;
     216             :     swap(m_reference, other.m_reference);
     217             :   }
     218             : 
     219             : private:
     220             :   T* m_reference;
     221             : };
     222             : 
     223             : } // namespace utilities
     224             : } // namespace mcrl2
     225             : 
     226             : namespace std
     227             : {
     228             : 
     229             : template<typename T>
     230             : void swap(mcrl2::utilities::shared_reference<T>& a, mcrl2::utilities::shared_reference<T>& b) noexcept
     231             : {
     232             :   a.swap(b);
     233             : }
     234             : 
     235             : } // namespace std
     236             : 
     237             : #endif // MCRL2_UTILITIES_SHARED_REFERENCE_H_

Generated by: LCOV version 1.13