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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
// -*- C++ -*-
//
// Package:     Common
// Class  :     PtrVectorBase
//
// Implementation:
//     <Notes on implementation>
//
// Original Author:  Chris Jones
//         Created:  Wed Oct 24 15:49:27 EDT 2007
//

// user include files
#include "DataFormats/Common/interface/WrapperBase.h"
#include "DataFormats/Common/interface/PtrVectorBase.h"
#include "DataFormats/Common/interface/traits.h"
#include "DataFormats/Common/interface/EDProductGetter.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include "FWCore/Utilities/interface/Exception.h"

// system include files
#include <ostream>

//
// constants, enums and typedefs
//
namespace edm {
  //
  // static data member definitions
  //

  //
  // constructor and destructor
  //
  PtrVectorBase::PtrVectorBase() : cachedItems_(nullptr) {}

  PtrVectorBase::~PtrVectorBase() { delete cachedItems_.load(); }

  PtrVectorBase::PtrVectorBase(const PtrVectorBase& iOther)
      : core_(iOther.core_), indicies_(iOther.indicies_), cachedItems_(nullptr) {
    auto cache = iOther.cachedItems_.load();
    if (cache) {
      cachedItems_.store(new std::vector<void const*>(*cache));
    }
  }

  //
  // assignment operators
  //

  //
  // member functions
  //

  /// swap
  void PtrVectorBase::swap(PtrVectorBase& other) {
    core_.swap(other.core_);
    indicies_.swap(other.indicies_);
    other.cachedItems_.store(cachedItems_.exchange(other.cachedItems_.load()));
  }

  void PtrVectorBase::push_back_base(RefCore const& core, key_type iKey, void const* iData) {
    core_.pushBackItem(core, false);
    //Did we already push a 'non-cached' Ptr into the container or is this a 'non-cached' Ptr?
    if (not cachedItems_ and indicies_.empty()) {
      cachedItems_.store(new std::vector<void const*>());
      (*cachedItems_).reserve(indicies_.capacity());
    }
    auto tmpCachedItems = cachedItems_.load();
    if (tmpCachedItems and (indicies_.size() == (*tmpCachedItems).size())) {
      if (iData) {
        tmpCachedItems->push_back(iData);
      } else if (key_traits<key_type>::value == iKey) {
        tmpCachedItems->push_back(nullptr);
      } else {
        delete tmpCachedItems;
        cachedItems_.store(nullptr);
      }
    }
    indicies_.push_back(iKey);
  }

  bool PtrVectorBase::isAvailable() const {
    if (indicies_.empty()) {
      return core_.isAvailable();
    }
    if (!hasCache()) {
      if (!id().isValid() || productGetter() == nullptr) {
        return false;
      }
      getProduct_();
    }
    auto tmpCachedItems = cachedItems_.load();
    for (auto ptr : *tmpCachedItems) {
      if (ptr == nullptr) {
        return false;
      }
    }
    return true;
  }

  //
  // const member functions
  //
  void PtrVectorBase::getProduct_() const {
    if (hasCache()) {
      return;
    }
    if (indicies_.empty()) {
      return;
    }
    //NOTE: Another thread could be getting the data
    auto tmpProductGetter = productGetter();
    if (nullptr == tmpProductGetter) {
      throw Exception(errors::LogicError) << "Tried to get data for a PtrVector which has no EDProductGetter\n";
    }
    WrapperBase const* product = tmpProductGetter->getIt(id());

    auto tmpCachedItems = std::make_unique<std::vector<void const*>>();

    if (product != nullptr) {
      product->fillPtrVector(typeInfo(), indicies_, *tmpCachedItems);

      std::vector<void const*>* expected = nullptr;
      if (cachedItems_.compare_exchange_strong(expected, tmpCachedItems.get())) {
        //we were the first thread to change the value
        tmpCachedItems.release();
      }

      return;
    }

    tmpCachedItems->resize(indicies_.size(), nullptr);

    std::vector<unsigned int> thinnedKeys;
    thinnedKeys.assign(indicies_.begin(), indicies_.end());
    std::vector<WrapperBase const*> wrappers(indicies_.size(), nullptr);
    tmpProductGetter->getThinnedProducts(id(), wrappers, thinnedKeys);
    unsigned int nWrappers = wrappers.size();
    assert(wrappers.size() == indicies_.size());
    assert(wrappers.size() == tmpCachedItems->size());
    for (unsigned k = 0; k < nWrappers; ++k) {
      if (wrappers[k] != nullptr) {
        wrappers[k]->setPtr(typeInfo(), thinnedKeys[k], (*tmpCachedItems)[k]);
      }
    }
    {
      std::vector<void const*>* expected = nullptr;
      if (cachedItems_.compare_exchange_strong(expected, tmpCachedItems.get())) {
        //we were the first thread to change the value
        tmpCachedItems.release();
      }
    }
  }

  bool PtrVectorBase::checkCachedItems() const {
    auto tmp = cachedItems_.load();
    if (not tmp) {
      return false;
    }
    for (auto item : *tmp) {
      if (item == nullptr) {
        throw Exception(errors::InvalidReference)
            << "Asked for data from a PtrVector which refers to a non-existent product with ProductID " << id() << "\n";
      }
    }
    return true;
  }

  bool PtrVectorBase::operator==(PtrVectorBase const& iRHS) const {
    if (core_ != iRHS.core_) {
      return false;
    }
    if (indicies_.size() != iRHS.indicies_.size()) {
      return false;
    }
    return std::equal(indicies_.begin(), indicies_.end(), iRHS.indicies_.begin());
  }

  //
  // static member functions
  //

  static const std::vector<void const*> s_emptyCache{};

  const std::vector<void const*>& PtrVectorBase::emptyCache() { return s_emptyCache; }

}  // namespace edm