Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:13:11

0001 #ifndef FWCore_Utilities_atomic_value_ptr_h
0002 #define FWCore_Utilities_atomic_value_ptr_h
0003 
0004 // ----------------------------------------------------------------------
0005 //
0006 // atomic_value_ptr.h - Smart pointer permitting copying of pointed-to object.
0007 //
0008 // This is an atomic version of value_ptr.
0009 //
0010 // The prologue of FWCore/Utilities/interface/value_ptr.h
0011 // describes the functionality of value_ptr.
0012 //
0013 // This allows the value of the pointer to be changed atomically.
0014 // Note that copy/move construction and copy/move assignment
0015 // are *not* atomic, as an object of type T must be copied or moved.
0016 // ----------------------------------------------------------------------
0017 
0018 #include <atomic>
0019 
0020 #include <memory>
0021 
0022 namespace edm {
0023 
0024   // --------------------------------------------------------------------
0025   //
0026   //  Auxiliary traits class template providing default clone()
0027   //  Users should specialize this template for types that have their
0028   //  own self-copy operations; failure to do so may lead to slicing!
0029   //  User specified clone methods must be thread safe.
0030   //
0031   // --------------------------------------------------------------------
0032 
0033   template <typename T>
0034   struct atomic_value_ptr_traits {
0035     static T* clone(T const* p) { return new T(*p); }
0036   };
0037 
0038   // --------------------------------------------------------------------
0039   //
0040   // Copyable smart pointer class template using an atomic pointer.
0041   //
0042   // --------------------------------------------------------------------
0043 
0044   template <typename T>
0045   class atomic_value_ptr {
0046   public:
0047     // --------------------------------------------------
0048     // Default constructor/destructor:
0049     // --------------------------------------------------
0050 
0051     atomic_value_ptr() : myP(nullptr) {}
0052     explicit atomic_value_ptr(T* p) : myP(p) {}
0053     ~atomic_value_ptr() { delete myP.load(); }
0054 
0055     // --------------------------------------------------
0056     // Copy constructor/copy assignment:
0057     // --------------------------------------------------
0058 
0059     atomic_value_ptr(atomic_value_ptr const& orig) : myP(createFrom(orig.myP.load())) {}
0060 
0061     atomic_value_ptr& operator=(atomic_value_ptr const& orig) {
0062       atomic_value_ptr<T> local(orig);
0063       exchangeWithLocal(local);
0064       return *this;
0065     }
0066 
0067     atomic_value_ptr(atomic_value_ptr&& orig) : myP(orig.myP.load()) { orig.myP.store(nullptr); }
0068 
0069     atomic_value_ptr& operator=(atomic_value_ptr&& orig) {
0070       atomic_value_ptr<T> local(orig);
0071       exchangeWithLocal(local);
0072       return *this;
0073     }
0074 
0075     // --------------------------------------------------
0076     // Access mechanisms:
0077     // --------------------------------------------------
0078 
0079     T& operator*() const { return *myP; }
0080     T* operator->() const { return myP.load(); }
0081 
0082     // --------------------------------------------------
0083     // Copy-like construct/assign from compatible atomic_value_ptr<>:
0084     // --------------------------------------------------
0085 
0086     template <typename U>
0087     atomic_value_ptr(atomic_value_ptr<U> const& orig) : myP(createFrom(orig.operator->())) {}
0088 
0089     template <typename U>
0090     atomic_value_ptr& operator=(atomic_value_ptr<U> const& orig) {
0091       atomic_value_ptr<T> local(orig);
0092       exchangeWithLocal(local);
0093       return *this;
0094     }
0095 
0096     // --------------------------------------------------
0097     // move-like construct/assign from unique_ptr<>:
0098     // --------------------------------------------------
0099 
0100     atomic_value_ptr(std::unique_ptr<T> orig) : myP(orig.release()) { orig = nullptr; }
0101 
0102     atomic_value_ptr& operator=(std::unique_ptr<T> orig) {
0103       atomic_value_ptr<T> local(std::move(orig));
0104       exchangeWithLocal(local);
0105       return *this;
0106     }
0107 
0108     T* load() const { return myP.load(); }
0109 
0110     bool compare_exchange_strong(T*& oldValue, T* newValue) { return myP.compare_exchange_strong(oldValue, newValue); }
0111 
0112     // The following typedef, function, and operator definition
0113     // support the following syntax:
0114     //   atomic_value_ptr<T> ptr(..);
0115     //   if (ptr) { ...
0116     // Where the conditional will evaluate as true if and only if the
0117     // pointer atomic_value_ptr contains is not null.
0118   private:
0119     typedef void (atomic_value_ptr::*bool_type)() const;
0120     void this_type_does_not_support_comparisons() const {}
0121 
0122   public:
0123     operator bool_type() const {
0124       return myP != nullptr ? &atomic_value_ptr<T>::this_type_does_not_support_comparisons : nullptr;
0125     }
0126 
0127   private:
0128     // --------------------------------------------------
0129     // Manipulation:
0130     // --------------------------------------------------
0131 
0132     // This function must be invoked by the object available across threads.
0133     // The argument "local" must reference an object local to one thread.
0134     void exchangeWithLocal(atomic_value_ptr& local) {
0135       T* old = myP.exchange(local.myP.load());
0136       local.myP = old;
0137     }
0138 
0139     // --------------------------------------------------
0140     // Implementation aid:
0141     // --------------------------------------------------
0142 
0143     template <typename U>
0144     static T* createFrom(U const* p) {
0145       return p ? atomic_value_ptr_traits<U>::clone(p) : nullptr;
0146     }
0147 
0148     // --------------------------------------------------
0149     // Member data:
0150     // --------------------------------------------------
0151 
0152     mutable std::atomic<T*> myP;
0153 
0154   };  // atomic_value_ptr
0155 
0156   // Do not allow nonsensical comparisons that the bool_type
0157   // conversion operator definition above would otherwise allow.
0158   // The function call inside the next 4 operator definitions is
0159   // private, so compilation will fail if there is an atempt to
0160   // instantiate these 4 operators.
0161   template <typename T, typename U>
0162   inline bool operator==(atomic_value_ptr<T> const& lhs, U const& rhs) {
0163     lhs.this_type_does_not_support_comparisons();
0164     return false;
0165   }
0166 
0167   template <typename T, typename U>
0168   inline bool operator!=(atomic_value_ptr<T> const& lhs, U const& rhs) {
0169     lhs.this_type_does_not_support_comparisons();
0170     return false;
0171   }
0172 
0173   template <typename T, typename U>
0174   inline bool operator==(U const& lhs, atomic_value_ptr<T> const& rhs) {
0175     rhs.this_type_does_not_support_comparisons();
0176     return false;
0177   }
0178 
0179   template <typename T, typename U>
0180   inline bool operator!=(U const& lhs, atomic_value_ptr<T> const& rhs) {
0181     rhs.this_type_does_not_support_comparisons();
0182     return false;
0183   }
0184 }  // namespace edm
0185 
0186 #endif  // FWCoreUtilities_atomic_value_ptr_h