File indexing completed on 2024-04-06 12:03:50
0001 #ifndef DataFormats_Common_AssociationVector_h
0002 #define DataFormats_Common_AssociationVector_h
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
0015 #include "DataFormats/Common/interface/CommonExceptions.h"
0016 #include "DataFormats/Common/interface/FillView.h"
0017 #include "DataFormats/Common/interface/Ref.h"
0018 #include "DataFormats/Common/interface/RefProd.h"
0019 #include "DataFormats/Common/interface/RefToBase.h"
0020 #include "DataFormats/Common/interface/RefToBaseProd.h"
0021 #include "DataFormats/Common/interface/traits.h"
0022 #include "DataFormats/Provenance/interface/ProductID.h"
0023 #include "FWCore/Utilities/interface/EDMException.h"
0024
0025 #include <atomic>
0026 #include <type_traits>
0027 #include <memory>
0028
0029 namespace edm {
0030 template <class T>
0031 class Ptr;
0032
0033 namespace helper {
0034
0035 struct AssociationIdenticalKeyReference {
0036 template <typename T>
0037 static T const& get(T const& t, ProductID) {
0038 return t;
0039 }
0040 };
0041
0042 template <typename T>
0043 struct AssociationKeyReferenceTrait {
0044 typedef AssociationIdenticalKeyReference type;
0045 };
0046
0047 template <typename REFPROD>
0048 struct RefFromRefProdTrait {};
0049
0050 template <typename C>
0051 struct RefFromRefProdTrait<RefProd<C> > {
0052 typedef Ref<typename RefProd<C>::product_type> ref_type;
0053 };
0054
0055 template <typename T>
0056 struct RefFromRefProdTrait<RefToBaseProd<T> > {
0057 typedef RefToBase<T> ref_type;
0058 };
0059 }
0060
0061 template <typename KeyRefProd,
0062 typename CVal,
0063 typename KeyRef = typename helper::RefFromRefProdTrait<KeyRefProd>::ref_type,
0064 typename SizeType =
0065 unsigned int,
0066 typename KeyReferenceHelper = typename helper::AssociationKeyReferenceTrait<KeyRef>::type>
0067 class AssociationVector {
0068 static_assert(std::is_convertible<SizeType, typename CVal::size_type>::value,
0069 "Can not convert container size_type to unsigned int.");
0070 typedef AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> self;
0071
0072 public:
0073 typedef KeyRefProd refprod_type;
0074 typedef typename KeyRefProd::product_type CKey;
0075 typedef SizeType size_type;
0076 typedef typename KeyRef::value_type key_type;
0077 typedef typename std::pair<KeyRef, typename CVal::value_type> value_type;
0078 typedef std::vector<value_type> transient_vector_type;
0079 typedef value_type const& const_reference;
0080 AssociationVector();
0081 AssociationVector(KeyRefProd const& ref, CKey const* = nullptr);
0082 AssociationVector(AssociationVector const&);
0083 ~AssociationVector();
0084
0085 size_type size() const;
0086 bool empty() const;
0087 const_reference operator[](size_type n) const;
0088 typename CVal::const_reference operator[](KeyRef const& k) const;
0089 typename CVal::reference operator[](KeyRef const& k);
0090
0091 template <typename K>
0092 typename CVal::const_reference operator[](edm::Ptr<K> const& k) const;
0093 template <typename K>
0094 typename CVal::const_reference operator[](edm::RefToBase<K> const& k) const;
0095
0096 self& operator=(self const&);
0097
0098 void clear();
0099 void swap(self& other);
0100 KeyRefProd const& keyProduct() const { return ref_; }
0101 KeyRef key(size_type i) const { return KeyRef(ref_, i); }
0102 typename CVal::value_type const value(size_type i) const { return data_[i]; }
0103 void setValue(size_type i, typename CVal::value_type const& val);
0104 void fillView(ProductID const& id, std::vector<void const*>& pointers, FillViewHelperVector& helpers) const;
0105
0106 typedef typename transient_vector_type::const_iterator const_iterator;
0107
0108 const_iterator begin() const { return transientVector().begin(); }
0109 const_iterator end() const { return transientVector().end(); }
0110
0111
0112 CMS_CLASS_VERSION(11)
0113
0114 private:
0115 enum CacheState { kUnset, kFilling, kSet };
0116 CVal data_;
0117 KeyRefProd ref_;
0118 mutable std::atomic<transient_vector_type*> transientVector_;
0119
0120 transient_vector_type const& transientVector() const;
0121 void fixup() const;
0122 };
0123
0124 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0125 inline
0126 typename AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::transient_vector_type const&
0127 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::transientVector() const {
0128 fixup();
0129 return *(transientVector_.load(std::memory_order_acquire));
0130 }
0131
0132 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0133 inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::AssociationVector()
0134 : data_(), ref_(), transientVector_(nullptr) {}
0135
0136 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0137 inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::AssociationVector(
0138 KeyRefProd const& ref, CKey const* coll)
0139 : data_(coll == nullptr ? ref->size() : coll->size()),
0140 ref_(ref),
0141 transientVector_(new transient_vector_type(coll == nullptr ? ref->size() : coll->size())) {}
0142
0143 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0144 inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::AssociationVector(
0145 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> const& o)
0146 : data_(o.data_), ref_(o.ref_), transientVector_() {
0147 auto t = o.transientVector_.load(std::memory_order_acquire);
0148 if (t) {
0149 transientVector_.store(new transient_vector_type(*t), std::memory_order_release);
0150 }
0151 }
0152
0153 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0154 inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::~AssociationVector() {
0155 delete transientVector_.load(std::memory_order_acquire);
0156 }
0157
0158 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0159 inline typename AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::const_reference
0160 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](size_type n) const {
0161 return transientVector()[n];
0162 }
0163
0164 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0165 inline typename CVal::const_reference
0166 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](KeyRef const& k) const {
0167 KeyRef keyRef = KeyReferenceHelper::get(k, ref_.id());
0168 checkForWrongProduct(keyRef.id(), ref_.id());
0169 return data_[keyRef.key()];
0170 }
0171
0172 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0173 template <typename K>
0174 inline typename CVal::const_reference
0175 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](edm::Ptr<K> const& k) const {
0176 static_assert(std::is_base_of<K, key_type>::value,
0177 "edm::Ptr's key type is not a base class of AssociationVector's item type");
0178 checkForWrongProduct(k.id(), ref_.id());
0179 return data_[k.key()];
0180 }
0181
0182 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0183 template <typename K>
0184 typename CVal::const_reference AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](
0185 edm::RefToBase<K> const& k) const {
0186 static_assert(std::is_base_of<K, key_type>::value,
0187 "edm::RefToBase's key type is not a base class of AssociationVector's item type");
0188 checkForWrongProduct(k.id(), ref_.id());
0189 return data_[k.key()];
0190 }
0191
0192 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0193 inline typename CVal::reference AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator[](
0194 KeyRef const& k) {
0195 KeyRef keyRef = KeyReferenceHelper::get(k, ref_.id());
0196 auto t = transientVector_.exchange(nullptr, std::memory_order_acq_rel);
0197 delete t;
0198 checkForWrongProduct(keyRef.id(), ref_.id());
0199 return data_[keyRef.key()];
0200 }
0201
0202 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0203 inline AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>&
0204 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::operator=(self const& o) {
0205 if (this == &o) {
0206 return *this;
0207 }
0208 data_ = o.data_;
0209 ref_ = o.ref_;
0210 auto t = transientVector_.exchange(nullptr, std::memory_order_acq_rel);
0211 delete t;
0212 return *this;
0213 }
0214
0215 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0216 inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::setValue(
0217 size_type i, typename CVal::value_type const& val) {
0218 data_[i] = val;
0219 KeyRef ref(ref_, i);
0220 auto t = transientVector_.load(std::memory_order_acquire);
0221 (*t)[i].first = ref;
0222 (*t)[i].second = data_[i];
0223 }
0224
0225 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0226 inline typename AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::size_type
0227 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::size() const {
0228 return data_.size();
0229 }
0230
0231 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0232 inline bool AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::empty() const {
0233 return data_.empty();
0234 }
0235
0236 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0237 inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::clear() {
0238 data_.clear();
0239 auto t = transientVector_.load(std::memory_order_acquire);
0240 if (t)
0241 t->clear();
0242 ref_ = KeyRefProd();
0243 }
0244
0245 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0246 inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::swap(self& other) {
0247 data_.swap(other.data_);
0248 other.transientVector_.store(
0249 transientVector_.exchange(other.transientVector_.load(std::memory_order_acquire), std::memory_order_acq_rel),
0250 std::memory_order_release);
0251 ref_.swap(other.ref_);
0252 }
0253
0254 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0255 inline void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::fixup() const {
0256 if (nullptr == transientVector_.load(std::memory_order_acquire)) {
0257 std::unique_ptr<transient_vector_type> newT{new transient_vector_type(size())};
0258 for (size_type i = 0; i != size(); ++i) {
0259 (*newT)[i] = std::make_pair(KeyRef(ref_, i), data_[i]);
0260 }
0261 transient_vector_type* expected = nullptr;
0262 if (transientVector_.compare_exchange_strong(expected, newT.get())) {
0263 newT.release();
0264 }
0265 }
0266 }
0267
0268 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0269 void AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>::fillView(
0270 ProductID const& id, std::vector<void const*>& pointers, FillViewHelperVector& helpers) const {
0271 detail::reallyFillView(*this, id, pointers, helpers);
0272
0273
0274
0275
0276
0277 }
0278
0279 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0280 inline void swap(AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>& a,
0281 AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper>& b) {
0282 a.swap(b);
0283 }
0284
0285
0286
0287
0288
0289 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0290 inline void fillView(AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> const& obj,
0291 ProductID const& id,
0292 std::vector<void const*>& pointers,
0293 FillViewHelperVector& helpers) {
0294 obj.fillView(id, pointers, helpers);
0295 }
0296
0297 template <typename KeyRefProd, typename CVal, typename KeyRef, typename SizeType, typename KeyReferenceHelper>
0298 struct has_fillView<AssociationVector<KeyRefProd, CVal, KeyRef, SizeType, KeyReferenceHelper> > {
0299 static bool const value = true;
0300 };
0301
0302 }
0303
0304 #endif