ATLAS Offline Software
ObjContainer.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3  */
4 /* Dear emacs, this is -*-c++-*- */
5 #ifndef TRKEXTOOLS_OBJCONTAINER_H
6 #define TRKEXTOOLS_OBJCONTAINER_H
7 #include <vector>
8 #include <utility>
9 #include <limits>
10 #include <sstream>
11 #include <iostream>
12 #include <cassert>
13 #include <memory>
14 
16 
29 template<class T_Obj>
31 
32 template<class T_Obj>
33 class ObjPtr;
34 
35 
36 class ObjRef;
37 
40 template<class T_Obj>
41 T_Obj*
42 cloneObj(const T_Obj* obj)
43 {
44  return (obj ? new T_Obj(*obj) : obj);
45 }
46 
47 template<class T_Obj>
48 std::unique_ptr<T_Obj>
49 uniqueClone(const T_Obj* obj)
50 {
51  return std::unique_ptr<T_Obj>(cloneObj(obj));
52 }
53 
54 
55 
61 class ObjRef {
62  template <class T_Obj_>
63  friend class ObjContainer;
64  template <class T_Obj_>
65  friend class ObjPtr;
66 
67 public:
68  ObjRef() = default;
69 
70  ObjRef(unsigned short idx) : m_index(idx) {}
71 
72  ObjRef(const ObjRef &ref) = default;
73 
74  ObjRef( ObjRef &&ref) : m_index(ref.m_index) {ref.m_index=invalid(); }
75 
79  bool isValid() const { return m_index != invalid(); }
80 
83  operator bool() const { return isValid(); }
84 
85  ObjRef &operator=(const ObjRef &ref) = default;
86 
88  if (this != &ref) {
89  m_index=ref.m_index;
90  ref.m_index = invalid();
91  }
92  return *this;
93  }
94 
95  bool operator==(const ObjRef &obj) const {
96  return obj.idx() == idx();
97  }
98 
99  bool operator!=(const ObjRef &obj) const {
100  return obj.idx() != idx();
101  }
102 
103 private:
104  unsigned short idx() const { return m_index; };
105 
106  static constexpr unsigned short invalid() { return std::numeric_limits<unsigned short>::max(); }
107  unsigned short m_index = invalid();
108 };
109 
114  template <class T_Obj_>
115  friend class ObjPtr;
116 
117 protected:
118  static void throwNoContainer() {
119  throw std::logic_error("No object container.");
120  }
121 
122  static void throwMaximumCapacitiyExceeded(size_t max_objs) {
123  std::stringstream msg;
124  msg << "Maximum object container capacity exceeded (" << max_objs << "). Bail out.";
125  throw std::runtime_error(msg.str());
126  }
127 
128  static void throwMaximumNumberOfSharesExceeded(size_t max_shares) {
129  std::stringstream msg;
130  msg << "Maximum number of shares exceeded (" << max_shares << "). Bail out.";
131  throw std::runtime_error(msg.str());
132  }
133 
134  static void throwInvalidObject( size_t idx, size_t n_objs) {
135  std::stringstream msg;
136  msg << "Invalid object reference. Index " << idx << " not in allowed range [0.." << n_objs << "). Bail out.";
137  throw std::logic_error(msg.str());
138  }
139 
140  static void throwObjectAlreadyDeleted(size_t idx) {
141  std::stringstream msg;
142  msg << "Object " << idx << " already deleted. Bail out.";
143  throw std::logic_error(msg.str());
144  }
145 
146  static void throwObjectExistsAlready(const void *ptr) {
147  std::stringstream msg;
148  msg << "Object " << ptr << " already registered. Bail out.";
149  throw std::logic_error(msg.str());
150  }
151 
152  static void throwObjectStillAlive(const void *ptr, size_t cnt) {
153  std::stringstream msg;
154  msg << "Managed object " << ptr << " still has " << cnt << " references, but the container is now being destructed.";
155  throw std::logic_error(msg.str());
156  }
157 
158  static void warnShareDropAfterRelease(size_t idx) {
159  (void) idx;
160  }
161 };
162 
209 template <class T_Obj>
210 class ObjContainer : public ObjContainerBase
211 {
212  template <class T_Obj_>
213  friend class ObjPtr;
214 public:
215  ObjContainer(unsigned int min_size=0) { m_objs.reserve(min_size); }
216 
217  ~ObjContainer() noexcept(false) {
218  for (std::pair<T_Obj *, short> &elm : m_objs) {
219  if (elm.second>0) {
220  this->throwObjectStillAlive(elm.first,static_cast<size_t>(elm.second));
221  }
222  if (elm.first && elm.second>0) {
223  this->throwObjectStillAlive(elm.first,static_cast<size_t>(elm.second));
224  }
225  }
226  }
227 
228  bool isValid( ObjRef ref) const {
229  return ref.idx() < m_objs.size() && m_objs[ref.idx()].first; // @TODO the latter test should not be necessary
230  }
231 
232  // debug :
233  std::pair<short, bool > search(T_Obj *obj) const {
234  ObjRef ref(find(obj));
235  return std::make_pair( ref ? m_objs[ref.idx()].second : short{}, ref.isValid() );
236  }
237 
241  unsigned short size() const { return static_cast<unsigned short>(m_objs.size()); }
242 protected:
248  return registerObj(&obj, s_externalObj);
249  }
250 
256  return registerObj(obj, 0);
257  }
258 
264  switch(m_objs[ref.idx()].second) {
265  case s_externalObj: { return ref; }
266 
267  case s_releasedObj: { this->warnShareDropAfterRelease( ref.idx() );
268 
269  return ref; }
270 
271  case 0: if (!m_objs[ref.idx()].first) {this->throwObjectAlreadyDeleted( ref.idx());}
272  [[fallthrough]]; // throws exception
273 
274  default: { break; }
275  }
276 
277  if (m_objs[ref.idx()].second >= std::numeric_limits<short>::max()) {
278  this->throwMaximumNumberOfSharesExceeded(std::numeric_limits<short>::max()); // clone object and add new slot ?
279  }
280  ++(m_objs[ref.idx()].second);
281 
282  return ref;
283  }
284 
289  void drop( ObjRef &ref) {
291  switch(m_objs[ref.idx()].second) {
292  case s_externalObj: { return ; }
293 
294  case s_releasedObj: { this->warnShareDropAfterRelease( ref.idx() );
295  return ; }
296 
297  case 0: this->throwObjectAlreadyDeleted( ref.idx());
298  [[fallthrough]]; // throws exception
299 
300  default: { break; }
301  }
302 
303  if (--(m_objs[ref.idx()].second) == 0) {
304  T_Obj *obj=m_objs[ref.idx()].first;
305  delete obj;
306  m_objs[ref.idx()].first=nullptr;
307  assert(!find(obj)); // Ensure that deleted objects are not referenced anymore
309  m_freeIdx=ref.idx();
310  }
311  ref= ObjRef();
312  }
313  }
314 
319  const T_Obj *get( ObjRef ref) const {
320  ensureExists(ref);
321  return m_objs[ref.idx()].first;
322  }
323 
328  T_Obj *get( ObjRef ref) {
329  ensureExists(ref);
330  return m_objs[ref.idx()].first;
331  }
332 
341  T_Obj *release( ObjRef ref) {
343  switch (m_objs[ref.idx() ].second) {
344  case 0: this->throwObjectAlreadyDeleted( ref.idx());
345  [[fallthrough]]; // will not fall through, because of exception
346  case s_releasedObj:
347  [[fallthrough]]; // indeed, should also clone the object
348  case s_externalObj: return cloneObj(m_objs[ref.idx()].first);
349  default:
350  m_objs[ref.idx()].second = s_releasedObj;
351 
352  return m_objs[ref.idx()].first;
353  }
354  }
355 
358  bool isOwned( ObjRef ref) const {
359  return count(ref) == 1;
360  }
361 
364  bool isShared( ObjRef ref) const {
365  return count(ref) > 1;
366  }
367 
370  bool isExtern( ObjRef ref) const {
371  return count(ref) == s_externalObj;
372  }
373 
374  short count( ObjRef ref) const{
375  return m_objs[ref.idx() ].second;
376  }
377 
378 protected:
382  ObjRef find( T_Obj *obj) const {
383  for (typename std::vector< std::pair<T_Obj *, short> >::const_reverse_iterator
384  iter =m_objs.rbegin();
385  iter != m_objs.rend();
386  ++iter) {
387  if (iter->first == obj) {
388  assert( m_objs.at(m_objs.rend()-iter-1).first == obj);
389  ObjRef ref( static_cast<unsigned short>(m_objs.rend()-iter-1) ); // @TODO std::distance ?
391  return ref;
392  }
393  }
394  return ObjRef();
395  }
396 
399  void ensureValidity( ObjRef ref) const {
400  if (!isValid(ref)) this->throwInvalidObject( ref.idx(), m_objs.size());
401  }
402 
405  void ensureExists( ObjRef ref) const {
407  if (m_objs[ref.idx() ].second == 0) { this->throwObjectAlreadyDeleted( ref.idx()); }
408  }
409 
412  void checkCapacity() {
414  this->throwMaximumCapacitiyExceeded(m_objs.size());
415  }
416  }
417 
420  ObjRef registerObj(T_Obj *obj, short initial_count) {
421  if (!obj) return ObjRef{};
422  checkCapacity();
423 
424  ObjRef ref = find(obj);
425  if (isValid(ref)) {
426  switch(m_objs.at(ref.idx()).second) {
427  case 0: {
428  break;
429  }
430  case s_releasedObj:
431  if (initial_count == s_externalObj) {
432  break;
433  }
434  [[fallthrough]];
435  default:
436  this->throwObjectExistsAlready( obj);
437  }
438  // return ref;
439  }
440  if (m_freeIdx == std::numeric_limits<unsigned short>::max() && m_objs.size() >= m_objs.capacity()) {
441  for (typename std::vector< std::pair<T_Obj *, short> >::const_reverse_iterator
442  iter =m_objs.rbegin();
443  iter != m_objs.rend();
444  ++iter) {
445  if (iter->second==0) {
446  m_freeIdx=m_objs.rend()-iter-1;
447  }
448  }
449  }
451  ref=ObjRef(static_cast<unsigned short>(m_objs.size()));
452  m_objs.push_back(std::make_pair(obj, initial_count));
453  } else {
454  m_objs[m_freeIdx] = std::make_pair( obj,initial_count);
457  }
459  return ref;
460  }
461 
462  constexpr static short s_externalObj = -2;
463  constexpr static short s_releasedObj = -1;
464 
465  std::vector< std::pair<T_Obj *, short> > m_objs;
467 };
468 
471 template <class T_Obj>
472 class ObjPtr {
473 public:
474  ObjPtr() = default;
475  ObjPtr(ObjPtr &&obj_ptr) = default;
476 
477  ObjPtr(const ObjPtr &obj_ptr)
478  : m_container(obj_ptr.m_container)
479  {
480  shareAndSet(obj_ptr.index());
481  }
482 
488  ObjPtr(ObjContainer<T_Obj>& container, const T_Obj& obj)
489  : m_container(&container)
490  , m_ref(m_container->registerObj(obj))
491  {}
492 
493 
501  ObjPtr(ObjContainer<T_Obj>& container, std::unique_ptr<T_Obj> obj)
502  : ObjPtr(container, container.registerObj(obj.release()))
503  {}
504 
510  : m_container(&container)
511  , m_ref(ref ? container.share(ref) : ref)
512  {}
513 
514  ~ObjPtr() noexcept(false){
515  if (m_ref) {
516  m_container->drop(m_ref);
517  }
518  }
519 
522  operator bool() const { return m_container && m_container->isValid(m_ref); }
523 
525  if (obj.m_ref != m_ref) {
526  if (*this) {
527  m_container->drop(m_ref);
528  }
529  if (obj.m_container) {
530  assert( !m_container || m_container == obj.m_container);
531  m_container = obj.m_container;
532  }
533  shareAndSet(obj.index());
534  }
535  return *this;
536  }
537 
539  if (&obj != this) {
540  if (*this) {
541  m_container->drop(m_ref);
542  }
543  m_ref = std::move(obj.m_ref);
544  if (obj.m_container) {
545  assert( !m_container || m_container == obj.m_container);
546  m_container = obj.m_container;
547  }
548  }
549  return *this;
550  }
551 
553  if (ref != m_ref) {
554  if (*this) {
555  m_container->drop(m_ref);
556  }
557  if (!m_container) {
559  }
560  shareAndSet(ref);
561  }
562  return *this;
563  }
564 
567  bool operator==(const ObjPtr &obj) const {
568  return obj.m_ref == m_ref;
569  }
570 
573  bool operator!=(const ObjPtr &obj) const {
574  return obj.m_ref != m_ref;
575  }
576 
577  T_Obj &operator*() {
578  return *m_container->get(m_ref);
579  }
580 
581  T_Obj *operator->() {
582  return get();
583  }
584 
588  T_Obj *get() {
589  if (!m_ref) return nullptr;
590  else return m_container->get(m_ref);
591  }
592 
593  // @TODO useful ? the container does not really allow for const-access.
594 
598  const T_Obj *get() const {
599  if (!m_ref) return nullptr;
600  else return std::as_const(*m_container).get(m_ref);
601  }
602 
610  T_Obj *release() {
611  if (!m_ref) return nullptr;
612  else return m_container->release(m_ref);
613  }
614 
622  std::unique_ptr<T_Obj> to_unique() {
623  return std::unique_ptr<T_Obj>(release());
624  }
625 
629  ObjRef index() const { return m_ref; }
630 
631  protected:
632 
636  if (ref) {
637  assert(m_container);
638  m_ref=m_container->share(ref);
639  }
640  else {
641  m_ref=ref;
642  }
643  }
644 
645  public:
648  bool isOwned() const {
649  return m_container->isOwned(m_ref);
650  }
651 
654  bool isShared() const {
655  return m_container->isShared(m_ref);
656  }
657 
660  bool isExtern() const {
661  return m_container->isExtern(m_ref);
662  }
663 
664 
665 private:
668 };
669 #endif
ObjRef::ObjRef
ObjRef()=default
ObjPtr::ObjPtr
ObjPtr(const ObjPtr &obj_ptr)
Definition: ObjContainer.h:477
ObjPtr::isOwned
bool isOwned() const
Return true if the object is managed and owned by the container.
Definition: ObjContainer.h:648
ObjPtr::operator!=
bool operator!=(const ObjPtr &obj) const
Test whether two pointer point to different objects.
Definition: ObjContainer.h:573
ObjPtr::release
T_Obj * release()
Release the object this pointer points to from the container.
Definition: ObjContainer.h:610
ObjRef::operator==
bool operator==(const ObjRef &obj) const
Definition: ObjContainer.h:95
ObjContainer::s_externalObj
constexpr static short s_externalObj
"share count" of external objects
Definition: ObjContainer.h:462
ObjContainerBase
Object container base class.
Definition: ObjContainer.h:113
max
#define max(a, b)
Definition: cfImp.cxx:41
ObjContainer::drop
void drop(ObjRef &ref)
Decrease the share count of the referenced object and eventually destroy it.
Definition: ObjContainer.h:289
ObjContainer::get
T_Obj * get(ObjRef ref)
Get a pointer to a managed object.
Definition: ObjContainer.h:328
ObjRef::operator=
ObjRef & operator=(ObjRef &&ref)
Definition: ObjContainer.h:87
ObjContainerBase::throwNoContainer
static void throwNoContainer()
Definition: ObjContainer.h:118
ObjRef::ObjRef
ObjRef(ObjRef &&ref)
Definition: ObjContainer.h:74
ObjPtr::ObjPtr
ObjPtr()=default
ObjContainer::get
const T_Obj * get(ObjRef ref) const
Get a pointer to a managed object.
Definition: ObjContainer.h:319
ObjContainerBase::throwObjectStillAlive
static void throwObjectStillAlive(const void *ptr, size_t cnt)
Definition: ObjContainer.h:152
ObjContainerBase::throwMaximumNumberOfSharesExceeded
static void throwMaximumNumberOfSharesExceeded(size_t max_shares)
Definition: ObjContainer.h:128
ObjRef::m_index
unsigned short m_index
Definition: ObjContainer.h:107
ObjPtr::ObjPtr
ObjPtr(ObjPtr &&obj_ptr)=default
cloneObj
T_Obj * cloneObj(const T_Obj *obj)
Template to be specialised if object cloning is not handled by the copy operator of the container obj...
Definition: ObjContainer.h:42
ObjContainer::s_releasedObj
constexpr static short s_releasedObj
"share count" of released objects
Definition: ObjContainer.h:463
uniqueClone
std::unique_ptr< T_Obj > uniqueClone(const T_Obj *obj)
Definition: ObjContainer.h:49
ObjContainer::isOwned
bool isOwned(ObjRef ref) const
Return true if this container owns the object.
Definition: ObjContainer.h:358
ObjPtr::ObjPtr
ObjPtr(ObjContainer< T_Obj > &container, ObjRef ref=ObjRef())
Share the referred object managed by the given container.
Definition: ObjContainer.h:509
ObjContainer::ensureValidity
void ensureValidity(ObjRef ref) const
Will throw an exception if the reference is not valid.
Definition: ObjContainer.h:399
ObjContainer::release
T_Obj * release(ObjRef ref)
Remove ownership over the given object from the container.
Definition: ObjContainer.h:341
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
ObjContainer::checkCapacity
void checkCapacity()
Will throw an exception if the maximum capacity of the container is exceeded.
Definition: ObjContainer.h:412
ObjContainer::m_freeIdx
unsigned short m_freeIdx
Definition: ObjContainer.h:466
ObjRef::operator=
ObjRef & operator=(const ObjRef &ref)=default
ObjContainer::isShared
bool isShared(ObjRef ref) const
Return true if the object is referred to by more than one ObjPtr.
Definition: ObjContainer.h:364
ObjRef::idx
unsigned short idx() const
Definition: ObjContainer.h:104
ObjContainer::registerObj
ObjRef registerObj(T_Obj &obj)
Manage an external object.
Definition: ObjContainer.h:247
ObjContainer::isValid
bool isValid(ObjRef ref) const
Definition: ObjContainer.h:228
ObjPtr::isShared
bool isShared() const
Return true if the object is managed by the container and if there are more than one instances of Obj...
Definition: ObjContainer.h:654
ObjContainerBase::throwObjectAlreadyDeleted
static void throwObjectAlreadyDeleted(size_t idx)
Definition: ObjContainer.h:140
ObjPtr::operator->
T_Obj * operator->()
Definition: ObjContainer.h:581
ObjRef::isValid
bool isValid() const
Return true if this class refers to an object which used to exist in the container.
Definition: ObjContainer.h:79
ObjPtr::ObjPtr
ObjPtr(ObjContainer< T_Obj > &container, const T_Obj &obj)
Store an external object in the container.
Definition: ObjContainer.h:488
ObjPtr::m_container
ObjContainer< T_Obj > * m_container
pointer to the conainer
Definition: ObjContainer.h:666
ObjContainerBase::throwMaximumCapacitiyExceeded
static void throwMaximumCapacitiyExceeded(size_t max_objs)
Definition: ObjContainer.h:122
ObjContainer::size
unsigned short size() const
Return the current number of slots on the container.
Definition: ObjContainer.h:241
ObjContainer::m_objs
std::vector< std::pair< T_Obj *, short > > m_objs
The storage for the object pointers.
Definition: ObjContainer.h:465
ObjContainer::registerObj
ObjRef registerObj(T_Obj *obj, short initial_count)
Register an object with a given state (external, released, shared)
Definition: ObjContainer.h:420
ObjPtr::isExtern
bool isExtern() const
Return true if the object is an external object i.e.
Definition: ObjContainer.h:660
ObjContainer::search
std::pair< short, bool > search(T_Obj *obj) const
Definition: ObjContainer.h:233
ObjPtr::get
const T_Obj * get() const
Get a const pointer to a valid manged object.
Definition: ObjContainer.h:598
ObjPtr::ObjPtr
ObjPtr(ObjContainer< T_Obj > &container, std::unique_ptr< T_Obj > obj)
Pass a unique_ptr to the container The Unique_ptr becomes an Owned object i.e has count 1.
Definition: ObjContainer.h:501
ObjPtr::operator*
T_Obj & operator*()
Definition: ObjContainer.h:577
ObjContainer::find
ObjRef find(T_Obj *obj) const
Search for an object in the container.
Definition: ObjContainer.h:382
ObjContainer::registerObj
ObjRef registerObj(T_Obj *obj)
manage a new object.
Definition: ObjContainer.h:255
ObjPtr::shareAndSet
void shareAndSet(ObjRef ref)
Helper method to increase the share count of the referenced object and point to that object.
Definition: ObjContainer.h:635
ObjPtr
Pointer to objects managed by ObjContainer.
Definition: ObjContainer.h:33
ObjContainerBase::throwObjectExistsAlready
static void throwObjectExistsAlready(const void *ptr)
Definition: ObjContainer.h:146
ObjPtr::operator==
bool operator==(const ObjPtr &obj) const
Test whether two pointer point to the same object.
Definition: ObjContainer.h:567
ObjPtr::operator=
ObjPtr & operator=(const ObjPtr &obj)
Definition: ObjContainer.h:524
ObjRef::ObjRef
ObjRef(unsigned short idx)
Definition: ObjContainer.h:70
ObjRef
Helper class to refer to objects in the container ObjContainer.
Definition: ObjContainer.h:61
ObjPtr::operator=
ObjPtr & operator=(ObjRef ref)
Definition: ObjContainer.h:552
trigbs_pickEvents.cnt
cnt
Definition: trigbs_pickEvents.py:71
ObjPtr::get
T_Obj * get()
Get a pointer to a valid manged object.
Definition: ObjContainer.h:588
ref
const boost::regex ref(r_ef)
ObjPtr::to_unique
std::unique_ptr< T_Obj > to_unique()
Release the object this pointer points to from the container.
Definition: ObjContainer.h:622
ObjPtr::~ObjPtr
~ObjPtr() noexcept(false)
Definition: ObjContainer.h:514
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
ObjContainer::count
short count(ObjRef ref) const
Definition: ObjContainer.h:374
ObjContainerBase::warnShareDropAfterRelease
static void warnShareDropAfterRelease(size_t idx)
Definition: ObjContainer.h:158
ObjContainer::ensureExists
void ensureExists(ObjRef ref) const
Will throw an exception if the referenced object does not exist.
Definition: ObjContainer.h:405
ObjContainer::isExtern
bool isExtern(ObjRef ref) const
Return true if the object is external i.e.
Definition: ObjContainer.h:370
ObjRef::ObjRef
ObjRef(const ObjRef &ref)=default
ObjContainer::~ObjContainer
~ObjContainer() noexcept(false)
Definition: ObjContainer.h:217
ObjPtr::operator=
ObjPtr & operator=(ObjPtr &&obj)
Definition: ObjContainer.h:538
ObjContainerBase::throwInvalidObject
static void throwInvalidObject(size_t idx, size_t n_objs)
Definition: ObjContainer.h:134
checker_macros.h
Define macros for attributes used to control the static checker.
python.PyAthena.obj
obj
Definition: PyAthena.py:132
ObjRef::operator!=
bool operator!=(const ObjRef &obj) const
Definition: ObjContainer.h:99
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
ObjContainer::share
ObjRef share(ObjRef ref)
Increase the share count of a given object.
Definition: ObjContainer.h:262
ObjPtr::m_ref
ObjRef m_ref
a valid reference to an object stored in the container or an invalid reference.
Definition: ObjContainer.h:667
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
ObjContainer::ObjContainer
ObjContainer(unsigned int min_size=0)
Definition: ObjContainer.h:215
ObjRef::invalid
static constexpr unsigned short invalid()
Definition: ObjContainer.h:106
ObjPtr::index
ObjRef index() const
Get a light-weight reference to the object pointed to by this pointer The returned light-weight refer...
Definition: ObjContainer.h:629
ObjContainer
Helper classes to manage shared objects in a scope.
Definition: ObjContainer.h:30