RefCoreWithIndex

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 159 160 161 162 163 164 165 166 167
#ifndef DataFormats_Common_RefCoreWithIndex_h
#define DataFormats_Common_RefCoreWithIndex_h

/*----------------------------------------------------------------------
  
RefCoreWithIndex: The component of edm::Ref containing the product ID and product getter and the index into the collection.
    This class is a specialization of RefCore and forwards most of the
    implementation to RefCore.

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

#include <algorithm>
#include <typeinfo>

#include <atomic>

namespace edm {
  class EDProductGetter;
  class WrapperBase;

  class RefCoreWithIndex {
  public:
    RefCoreWithIndex()
        : cachePtr_(nullptr), processIndex_(0), productIndex_(0), elementIndex_(edm::key_traits<unsigned int>::value) {}

    RefCoreWithIndex(ProductID const& theId,
                     void const* prodPtr,
                     EDProductGetter const* prodGetter,
                     bool transient,
                     unsigned int elementIndex);

    /**No checks are done: id must be valid; transient bit is not set  */
    RefCoreWithIndex(ProductID const& id, void const* prodPtr, unsigned int index)
        : cachePtr_(prodPtr),
          processIndex_(id.processIndex()),
          productIndex_(id.productIndex()),
          elementIndex_(index) {}

    RefCoreWithIndex(RefCore const& iCore, unsigned int);

    RefCoreWithIndex(RefCoreWithIndex const&);

    RefCoreWithIndex& operator=(RefCoreWithIndex const&);

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

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

    ~RefCoreWithIndex() 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);
    }

    unsigned int index() const { return elementIndex_; }

    // 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.
    // This function is potentially costly as it might cause a disk
    // read (note that it does not cause the data to be cached locally)
    bool isAvailable() const { return toRefCore().isAvailable(); }

    //Convert to an equivalent RefCore. Needed for Ref specialization.
    RefCore const& toRefCore() const { return *reinterpret_cast<const RefCore*>(this); }

    EDProductGetter const* productGetter() const { PRODUCTGETTER_IMPL; }

    void setProductGetter(EDProductGetter const* prodGetter) const { toRefCore().setProductGetter(prodGetter); }

    WrapperBase const* getProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const {
      return toRefCore().getProductPtr(type, prodGetter);
    }

    void productNotFoundException(std::type_info const& type) const { toRefCore().productNotFoundException(type); }

    void wrongTypeException(std::type_info const& expectedType, std::type_info const& actualType) const {
      toRefCore().wrongTypeException(expectedType, actualType);
    }

    void nullPointerForTransientException(std::type_info const& type) const {
      toRefCore().nullPointerForTransientException(type);
    }

    void swap(RefCoreWithIndex&);

    bool isTransient() const { ISTRANSIENT_IMPL; }

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

    void pushBackItem(RefCoreWithIndex const& productToBeInserted, bool checkPointer) {
      toUnConstRefCore().pushBackItem(productToBeInserted.toRefCore(), checkPointer);
    }

  private:
    RefCore& toUnConstRefCore() { return *reinterpret_cast<RefCore*>(this); }

    void setId(ProductID const& iId) { toUnConstRefCore().setId(iId); }
    void setTransient() { SETTRANSIENT_IMPL; }
    void setCacheIsProductPtr(void const* iItem) const { SETCACHEISPRODUCTPTR_IMPL(iItem); }
    void setCacheIsProductGetter(EDProductGetter const* iGetter) const { SETCACHEISPRODUCTGETTER_IMPL(iGetter); }

    //NOTE: the order MUST remain the same as a RefCore
    // since we play tricks to allow a pointer to a RefCoreWithIndex
    // to be the same as a pointer to a RefCore

    //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.
    ProcessIndex processIndex_;
    ProductIndex productIndex_;
    unsigned int elementIndex_;
  };

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

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

#endif