RefCore

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
#ifndef DataFormats_Common_RefCore_h
#define DataFormats_Common_RefCore_h

/*----------------------------------------------------------------------
  
RefCore: The component of edm::Ref containing the product ID and product getter.

----------------------------------------------------------------------*/
#include "DataFormats/Provenance/interface/ProductID.h"
#include "DataFormats/Common/interface/refcore_implementation.h"

#include <algorithm>
#include <typeinfo>
#include <atomic>

namespace edm {
  class RefCoreWithIndex;
  class EDProductGetter;
  class WrapperBase;

  class RefCore {
    //RefCoreWithIndex is a specialization of RefCore done for performance
    // Since we need to freely convert one to the other the friendship is used
    friend class RefCoreWithIndex;

  public:
    RefCore() : cachePtr_(nullptr), processIndex_(0), productIndex_(0) {}

    RefCore(ProductID const& theId, void const* prodPtr, EDProductGetter const* prodGetter, bool transient);

    RefCore(RefCore const&);

    RefCore& operator=(RefCore const&);

    RefCore(RefCore&& iOther) noexcept : processIndex_(iOther.processIndex_), productIndex_(iOther.productIndex_) {
      cachePtr_.store(iOther.cachePtr_.load(std::memory_order_relaxed), std::memory_order_relaxed);
    }

    RefCore& operator=(RefCore&& iOther) noexcept {
      cachePtr_.store(iOther.cachePtr_.load(std::memory_order_relaxed), std::memory_order_relaxed);
      processIndex_ = iOther.processIndex_;
      productIndex_ = iOther.productIndex_;
      return *this;
    }

    ~RefCore() noexcept {}

    ProductID id() const { ID_IMPL; }

    /**If productPtr is not 0 then productGetter will be 0 since only one is available at a time */
    void const* productPtr() const { PRODUCTPTR_IMPL; }

    /**This function is 'const' even though it changes an internal value becuase it is meant to be
     used as a way to store in a thread-safe way a cache of a value. This allows classes which use
     the RefCore to not have to declare it 'mutable'
     */
    void setProductPtr(void const* prodPtr) const { setCacheIsProductPtr(prodPtr); }

    /**This function is 'const' even though it changes an internal value becuase it is meant to be
     used as a way to store in a thread-safe way a cache of a value. This allows classes which use
     the RefCore to not have to declare it 'mutable'
     */
    bool tryToSetProductPtrForFirstTime(void const* prodPtr) const {
      return refcoreimpl::tryToSetCacheItemForFirstTime(cachePtr_, prodPtr);
    }

    // Checks for null
    bool isNull() const { return !isNonnull(); }

    // Checks for non-null
    bool isNonnull() const { ISNONNULL_IMPL; }

    // Checks for null
    bool operator!() const { return isNull(); }

    // Checks if collection is in memory or available
    // in the Event. No type checking is done.

    bool isAvailable() const;

    EDProductGetter const* productGetter() const { PRODUCTGETTER_IMPL; }

    void setProductGetter(EDProductGetter const* prodGetter) const;

    WrapperBase const* getProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const;

    WrapperBase const* tryToGetProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const;

    // argument 'key' is the key to parent, key to thinned is returned
    std::tuple<WrapperBase const*, unsigned int> getThinnedProductPtr(std::type_info const& type,
                                                                      unsigned int key,
                                                                      EDProductGetter const* prodGetter) const;

    // argument 'key' is the key to parent
    bool isThinnedAvailable(unsigned int key, EDProductGetter const* prodGetter) const;

    void productNotFoundException(std::type_info const& type) const;

    void wrongTypeException(std::type_info const& expectedType, std::type_info const& actualType) const;

    void nullPointerForTransientException(std::type_info const& type) const;

    void swap(RefCore&) noexcept;

    bool isTransient() const { ISTRANSIENT_IMPL; }

    int isTransientInt() const { return isTransient() ? 1 : 0; }

    void pushBackItem(RefCore const& productToBeInserted, bool checkPointer);

    void pushBackRefItem(RefCore const& productToBeInserted);

  private:
    RefCore(void const* iCache, ProcessIndex iProcessIndex, ProductIndex iProductIndex)
        : cachePtr_(iCache), processIndex_(iProcessIndex), productIndex_(iProductIndex) {}
    void setId(ProductID const& iId);
    void setTransient() { SETTRANSIENT_IMPL; }
    void setCacheIsProductPtr(const void* iItem) const { SETCACHEISPRODUCTPTR_IMPL(iItem); }
    void setCacheIsProductGetter(EDProductGetter const* iGetter) const { SETCACHEISPRODUCTGETTER_IMPL(iGetter); }
    bool cachePtrIsInvalid() const {
      return 0 == (reinterpret_cast<std::uintptr_t>(cachePtr_.load()) & refcoreimpl::kCacheIsProductPtrMask);
    }

    //The low bit of the address is used to determine  if the cachePtr_
    // is storing the productPtr or the EDProductGetter. The bit is set if
    // the address refers to the EDProductGetter.
    mutable std::atomic<void const*> cachePtr_;  // transient
    //The following is what is stored in a ProductID
    // the high bit of processIndex is used to store info on
    // if this is transient.
    //If the type or order of the member data is changes you MUST also update
    // the custom streamer in RefCoreStreamer.cc and RefCoreWithIndex
    ProcessIndex processIndex_;
    ProductIndex productIndex_;
  };

  inline bool operator==(RefCore const& lhs, RefCore const& rhs) {
    return lhs.isTransient() == rhs.isTransient() &&
           (lhs.isTransient() ? lhs.productPtr() == rhs.productPtr() : lhs.id() == rhs.id());
  }

  inline bool operator!=(RefCore const& lhs, RefCore const& rhs) { return !(lhs == rhs); }

  inline bool operator<(RefCore const& lhs, RefCore const& rhs) {
    return lhs.isTransient() ? (rhs.isTransient() ? lhs.productPtr() < rhs.productPtr() : false)
                             : (rhs.isTransient() ? true : lhs.id() < rhs.id());
  }

  inline void RefCore::swap(RefCore& other) noexcept {
    std::swap(processIndex_, other.processIndex_);
    std::swap(productIndex_, other.productIndex_);
    other.cachePtr_.store(cachePtr_.exchange(other.cachePtr_.load()));
  }

  inline void swap(edm::RefCore& lhs, edm::RefCore& rhs) { lhs.swap(rhs); }
}  // namespace edm

#endif