Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:03:50

0001 #ifndef DataFormats_Common_AtomicPtrCache_h
0002 #define DataFormats_Common_AtomicPtrCache_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     DataFormats/Common
0006 // Class  :     AtomicPtrCache
0007 //
0008 /**\class edm::AtomicPtrCache AtomicPtrCache.h "DataFormats/Common/interface/AtomicPtrCache.h"
0009 
0010  Description: A thread safe cache managed by a pointer
0011 
0012  Usage:
0013     Data products which need to cache results into non-trivial structures (e.g. an std::vector)
0014  can use this class to manage the cache in a thread-safe way.
0015  The thread-safety guarantee is only the standard C++, if calls are made to const functions simultaneously
0016  then everything is thread safe. Calling a non-const function while calling any other functions
0017  is not thread-safe.
0018  
0019  This class also hides the std::atomic from ROOT so this class can safely be used in a stored class.
0020 
0021  WARNING: member data which uses this class must be made transient in the classes_def.xml file!
0022 
0023 */
0024 //
0025 // Original Author:  Chris Jones
0026 //         Created:  Thu, 07 Nov 2013 00:50:40 GMT
0027 //
0028 
0029 // system include files
0030 #include <atomic>
0031 #include <memory>
0032 // user include files
0033 
0034 // forward declarations
0035 
0036 namespace edm {
0037   template <typename T>
0038   class AtomicPtrCache {
0039   public:
0040     AtomicPtrCache();
0041 
0042     ///Takes exclusive ownership of the value
0043     explicit AtomicPtrCache(T*);
0044 
0045     ///Uses T's copy constructor to make a copy
0046     AtomicPtrCache(const AtomicPtrCache<T>&);
0047     AtomicPtrCache& operator=(const AtomicPtrCache<T>&);
0048 
0049     ~AtomicPtrCache();
0050 
0051     // ---------- const member functions ---------------------
0052     T const* operator->() const { return load(); }
0053     T const& operator*() const { return *load(); }
0054     T const* load() const;
0055 
0056     bool isSet() const;
0057     ///returns true if actually was set.
0058     /// Will delete value held by iNewValue if not the first time set
0059     bool set(std::unique_ptr<T> iNewValue) const;
0060     // ---------- static member functions --------------------
0061 
0062     // ---------- member functions ---------------------------
0063     T* operator->() { return load(); }
0064     T& operator*() { return *load(); }
0065 
0066     T* load();
0067 
0068     ///unsets the value and deletes the memory
0069     void reset();
0070 
0071     T* release();
0072 
0073   private:
0074     // ---------- member data --------------------------------
0075     mutable std::atomic<T*> m_data;
0076   };
0077   template <typename T>
0078   inline AtomicPtrCache<T>::AtomicPtrCache() : m_data{nullptr} {}
0079 
0080   template <typename T>
0081   inline AtomicPtrCache<T>::AtomicPtrCache(T* iValue) : m_data{iValue} {}
0082 
0083   template <typename T>
0084   inline AtomicPtrCache<T>::AtomicPtrCache(const AtomicPtrCache<T>& iOther) : m_data{nullptr} {
0085     auto ptr = iOther.m_data.load(std::memory_order_acquire);
0086     if (ptr != nullptr) {
0087       m_data.store(new T{*ptr}, std::memory_order_release);
0088     }
0089   }
0090   template <typename T>
0091   inline AtomicPtrCache<T>& AtomicPtrCache<T>::operator=(const AtomicPtrCache<T>& iOther) {
0092     auto ptr = iOther.m_data.load(std::memory_order_acquire);
0093     if (ptr != nullptr) {
0094       auto ourPtr = m_data.load(std::memory_order_acquire);
0095       if (ourPtr != nullptr) {
0096         *ourPtr = *ptr;
0097       } else {
0098         m_data.store(new T{*ptr}, std::memory_order_release);
0099       }
0100     } else {
0101       delete m_data.exchange(nullptr, std::memory_order_acq_rel);
0102     }
0103     return *this;
0104   }
0105 
0106   template <typename T>
0107   inline AtomicPtrCache<T>::~AtomicPtrCache() {
0108     delete m_data.load(std::memory_order_acquire);
0109   }
0110 
0111   template <typename T>
0112   inline T* AtomicPtrCache<T>::load() {
0113     return m_data.load(std::memory_order_acquire);
0114   }
0115 
0116   template <typename T>
0117   inline T const* AtomicPtrCache<T>::load() const {
0118     return m_data.load(std::memory_order_acquire);
0119   }
0120 
0121   template <typename T>
0122   inline bool AtomicPtrCache<T>::isSet() const {
0123     return nullptr != m_data.load(std::memory_order_acquire);
0124   }
0125 
0126   template <typename T>
0127   inline bool AtomicPtrCache<T>::set(std::unique_ptr<T> iNewValue) const {
0128     bool retValue;
0129     T* expected = nullptr;
0130     if ((retValue = m_data.compare_exchange_strong(expected, iNewValue.get(), std::memory_order_acq_rel))) {
0131       iNewValue.release();
0132     }
0133     return retValue;
0134   }
0135 
0136   template <typename T>
0137   inline void AtomicPtrCache<T>::reset() {
0138     delete m_data.exchange(nullptr, std::memory_order_acq_rel);
0139   }
0140 
0141   template <typename T>
0142   inline T* AtomicPtrCache<T>::release() {
0143     T* tmp = m_data.exchange(nullptr);
0144     return tmp;
0145   }
0146 }  // namespace edm
0147 #endif