Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:11:27

0001 /// \cond ROOFIT_INTERNAL
0002 
0003 // Author: Stephan Hageboeck, CERN, 12/2018
0004 /*****************************************************************************
0005  * Project: RooFit                                                           *
0006  * Authors:                                                                  *
0007  *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
0008  *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
0009  *                                                                           *
0010  * Copyright (c) 2000-2005, Regents of the University of California          *
0011  *                          and Stanford University. All rights reserved.    *
0012  *                                                                           *
0013  * Redistribution and use in source and binary forms,                        *
0014  * with or without modification, are permitted according to the terms        *
0015  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
0016  *****************************************************************************/
0017 
0018 #ifndef ROOFIT_ROOFITCORE_INC_ROOSTLREFCOUNTLIST_H_
0019 #define ROOFIT_ROOFITCORE_INC_ROOSTLREFCOUNTLIST_H_
0020 
0021 #include "RooNameReg.h"
0022 
0023 #include "Rtypes.h"
0024 
0025 #include <vector>
0026 #include <string>
0027 #include <algorithm>
0028 #include <cassert>
0029 
0030 class RooLinkedList;
0031 
0032 /**
0033  * \class RooSTLRefCountList
0034  * The RooSTLRefCountList is a simple collection of **pointers** to the template objects with
0035  * reference counters.
0036  * The pointees are not owned, hence not deleted when removed from the collection.
0037  * Objects can be searched for either by pointer or by name (confusion possible when
0038  * objects with same name are present). This replicates the behaviour of the RooRefCountList.
0039  */
0040 
0041 template <class T>
0042 class RooSTLRefCountList {
0043   public:
0044     using Container_t = std::vector<T*>;
0045 
0046     static constexpr std::size_t minSizeForNamePointerOrdering = 7;
0047 
0048     RooSTLRefCountList() {
0049       // The static _renameCounter member gets connected to the RooNameReg as
0050       // soon as the first RooSTLRefCountList instance is constructed.
0051       if(_renameCounter == nullptr) _renameCounter =
0052         &RooNameReg::renameCounter();
0053     }
0054     RooSTLRefCountList(const RooSTLRefCountList&) = default;
0055     RooSTLRefCountList& operator=(const RooSTLRefCountList&) = default;
0056     RooSTLRefCountList& operator=(RooSTLRefCountList&&) = default;
0057 
0058     virtual ~RooSTLRefCountList() {}
0059 
0060     ///Add an object or increase refCount if it is already present. Only compares
0061     ///pointers to check for existing objects
0062     void Add(T * obj, std::size_t initialCount = 1) {
0063       // Nothing to add because `refCount` would be zero.
0064       if(initialCount == 0) return;
0065 
0066       auto foundItem = findByPointer(obj);
0067 
0068       if (foundItem != _storage.end()) {
0069         _refCount[foundItem - _storage.begin()] += initialCount;
0070       }
0071       else {
0072         if(!_orderedStorage.empty()) {
0073           _orderedStorage.insert(lowerBoundByNamePointer(obj), obj);
0074         }
0075         _storage.push_back(obj);
0076         _refCount.push_back(initialCount);
0077       }
0078     }
0079 
0080 
0081     ///Return ref count of item that iterator points to.
0082     std::size_t refCount(typename Container_t::const_iterator item) const {
0083       assert(_storage.size() == _refCount.size());
0084 
0085       return item != _storage.end() ? _refCount[item - _storage.begin()] : 0;
0086     }
0087 
0088 
0089     ///Return ref count of item with given address.
0090     template<typename Obj_t>
0091     std::size_t refCount(const Obj_t * obj) const {
0092       return refCount(findByPointer(obj));
0093     }
0094 
0095     ///Iterator over contained objects.
0096     typename Container_t::const_iterator begin() const {
0097       return _storage.begin();
0098     }
0099 
0100     ///End of contained objects.
0101     typename Container_t::const_iterator end() const {
0102       return _storage.end();
0103     }
0104 
0105     /// Retrieve an element from the list.
0106     typename Container_t::value_type operator[](std::size_t index) const {
0107       return _storage[index];
0108     }
0109 
0110 
0111     ///Direct reference to container of objects held by this list.
0112     const Container_t& containedObjects() const {
0113       return _storage;
0114     }
0115 
0116 
0117     ///Number of contained objects (neglecting the ref count).
0118     std::size_t size() const {
0119       assert(_storage.size() == _refCount.size());
0120 
0121       return _storage.size();
0122     }
0123 
0124     void reserve(std::size_t amount) {
0125       _storage.reserve(amount);
0126       _refCount.reserve(amount);
0127       _orderedStorage.reserve(amount);
0128     }
0129 
0130 
0131     ///Check if empty.
0132     bool empty() const {
0133       return _storage.empty();
0134     }
0135 
0136 
0137     ///Find an item by comparing its address.
0138     template<typename Obj_t>
0139     typename Container_t::const_iterator findByPointer(const Obj_t * item) const {
0140       return std::find(_storage.begin(), _storage.end(), item);
0141     }
0142 
0143 
0144     ///Find an item by comparing strings returned by RooAbsArg::GetName()
0145     typename Container_t::const_iterator findByName(const char * name) const {
0146       //If this turns out to be a bottleneck,
0147       //one could use the RooNameReg to obtain the pointer to the arg's name and compare these
0148       const std::string theName(name);
0149       auto byName = [&theName](const T * element) {
0150         return element->GetName() == theName;
0151       };
0152 
0153       return std::find_if(_storage.begin(), _storage.end(), byName);
0154     }
0155 
0156 
0157     ///Find an item by comparing RooAbsArg::namePtr() addresses.
0158     inline T* findByNamePointer(const T * item) const {
0159       return findByNamePointer(item->namePtr());
0160     }
0161 
0162     T* findByNamePointer(TNamed const* namePtr) const {
0163       if(size() < minSizeForNamePointerOrdering) {
0164         auto byNamePointer = [namePtr](const T * element) {
0165           return element->namePtr() == namePtr;
0166         };
0167 
0168         auto found = std::find_if(_storage.begin(), _storage.end(), byNamePointer);
0169         return found != _storage.end() ? *found : nullptr;
0170       } else {
0171         //As the collection is guaranteed to be sorted by namePtr() address, we
0172         //can use a binary search to look for `item` in this collection.
0173         auto first = lowerBoundByNamePointer(namePtr);
0174         if(first == _orderedStorage.end()) return nullptr;
0175         if(namePtr != (*first)->namePtr()) return nullptr;
0176         return *first;
0177       }
0178     }
0179 
0180 
0181     ///Check if list contains an item using findByPointer().
0182     template<typename Obj_t>
0183     bool containsByPointer(const Obj_t * obj) const {
0184       return findByPointer(obj) != _storage.end();
0185     }
0186 
0187 
0188     ///Check if list contains an item using findByNamePointer().
0189     bool containsByNamePtr(const T * obj) const {
0190       return findByNamePointer(obj);
0191     }
0192 
0193 
0194     ///Check if list contains an item using findByName().
0195     bool containsSameName(const char * name) const {
0196       return findByName(name) != _storage.end();
0197     }
0198 
0199 
0200     ///Decrease ref count of given object. Shrink list if ref count reaches 0.
0201     ///\param obj Decrease ref count of given object. Compare by pointer.
0202     ///\param force If true, remove irrespective of ref count.
0203     ///Returns by how much the `refCount` for the element to be removed was
0204     ///decreased (zero if nothing was removed). If `force == false`, it can
0205     ///only be zero or one, if `force == true`, it can be the full `refCount`
0206     ///for that element.
0207     int Remove(const T * obj, bool force = false) {
0208       auto item = findByPointer(obj);
0209 
0210       if (item != _storage.end()) {
0211         const std::size_t pos = item - _storage.begin();
0212 
0213         const UInt_t origRefCount = _refCount[pos];
0214 
0215         if (force || --_refCount[pos] == 0) {
0216           //gcc4.x doesn't know how to erase at the position of a const_iterator
0217           //Therefore, erase at begin + pos instead of 'item'
0218           _storage.erase(_storage.begin() + pos);
0219           _refCount.erase(_refCount.begin() + pos);
0220           if(!_orderedStorage.empty()) {
0221             // For the ordered storage, we could find by name pointer address
0222             // with binary search, but this will not work anymore if one of the
0223             // object pointers in this collection is dangling (can happen in
0224             // RooFit...). However, the linear search by object address is
0225             // acceptable, because we already do a linear search through
0226             // _storage at the beginning of Remove().
0227             _orderedStorage.erase(std::find(_orderedStorage.begin(), _orderedStorage.end(), obj));
0228           }
0229           return origRefCount;
0230         }
0231         return 1;
0232       }
0233 
0234       return 0;
0235     }
0236 
0237 
0238     ///Replace an element with a new value, keeping the same `refCount`. Will
0239     ///return the `refCount` for that element if the replacement succeeded,
0240     ///otherwise returns zero in case the `oldObj` could not be found in the
0241     ///collection.
0242     int Replace(const T * oldObj, T * newObj) {
0243       auto item = findByPointer(oldObj);
0244 
0245       if (item != _storage.end()) {
0246         const std::size_t pos = item - _storage.begin();
0247         _storage[pos] = newObj;
0248         // The content has changed, so the ordered-by-name storage was invalidated.
0249         _orderedStorage.clear();
0250         return _refCount[pos];
0251       }
0252 
0253       return 0;
0254     }
0255 
0256 
0257     ///Remove from list irrespective of ref count.
0258     void RemoveAll(const T * obj) {
0259       Remove(obj, true);
0260     }
0261 
0262     static RooSTLRefCountList<T> convert(const RooLinkedList& old);
0263 
0264   private:
0265     //Return an iterator to the last element in this sorted collection with a
0266     //RooAbsArg::namePtr() address smaller than for `item`.
0267     inline typename std::vector<T*>::const_iterator lowerBoundByNamePointer(const T * item) const {
0268       return lowerBoundByNamePointer(item->namePtr());
0269     }
0270 
0271     typename std::vector<T*>::const_iterator lowerBoundByNamePointer(TNamed const* namePtr) const {
0272 
0273       //If the _orderedStorage has not been initialized yet or needs resorting
0274       //for other reasons, (re-)initialize it now.
0275       if(orderedStorageNeedsSorting() || _orderedStorage.size() != _storage.size()) initializeOrderedStorage();
0276 
0277       return std::lower_bound(_orderedStorage.begin(), _orderedStorage.end(), namePtr,
0278              [](const auto& x, TNamed const* npt) -> bool {
0279                 return x->namePtr() < npt;
0280               });
0281     }
0282 
0283     bool orderedStorageNeedsSorting() const {
0284       //If an RooAbsArg in this collection was renamed, the collection might
0285       //not be sorted correctly anymore! The solution: every time any RooAbsArg
0286       //is renamed, the RooNameReg::renameCounter gets incremented. The
0287       //RooSTLRefCountList keeps track at which value of the counter it has
0288       //been sorted last. If the counter increased in the meantime, a
0289       //re-sorting is due.
0290       return _renameCounterForLastSorting != *_renameCounter;
0291     }
0292 
0293     void initializeOrderedStorage() const {
0294       _orderedStorage.clear();
0295       _orderedStorage.reserve(_storage.size());
0296       for(std::size_t i = 0; i < _storage.size(); ++i) {
0297         _orderedStorage.push_back(_storage[i]);
0298       }
0299       std::sort(_orderedStorage.begin(), _orderedStorage.end(),
0300               [](auto& a, auto& b) {
0301                 return a->namePtr() != b->namePtr() ? a->namePtr() < b->namePtr() : a < b;
0302               });
0303       _renameCounterForLastSorting = *_renameCounter;
0304     }
0305 
0306     Container_t _storage;
0307     std::vector<UInt_t> _refCount;
0308     mutable std::vector<T*> _orderedStorage; //!
0309     mutable unsigned long _renameCounterForLastSorting = 0; ///<!
0310 
0311     // It is expensive to access the RooNameReg instance to get the counter for
0312     // the renaming operations. That's why we have out own static pointer to
0313     // the counter.
0314     static std::size_t const* _renameCounter;
0315 
0316     ClassDef(RooSTLRefCountList<T>,3);
0317 };
0318 
0319 template<class T>
0320 std::size_t const* RooSTLRefCountList<T>::_renameCounter = nullptr;
0321 
0322 #endif /* ROOFIT_ROOFITCORE_INC_ROOSTLREFCOUNTLIST_H_ */
0323 
0324 /// \endcond