The Gaudi Framework  v29r0 (ff2e7097)
KeyedObjectManager.cpp
Go to the documentation of this file.
1 // Include files
5 #include "GaudiKernel/HashMap.h"
6 #include "GaudiKernel/Kernel.h"
7 #include <algorithm>
8 #include <map>
9 
10 namespace Containers
11 {
12  struct hashmap {
14  map_type m;
16  bool insert( void* obj, long key )
17  {
18  auto p = m.insert( map_type::value_type( key, obj ) );
19  return p.second;
20  }
21  hashmap() = default;
22  hashmap( hashmap&& ) = default;
23  };
24  struct map {
26  map_type m;
28  bool insert( void* obj, long key )
29  {
30  auto p = m.insert( map_type::value_type( key, obj ) );
31  return p.second;
32  }
33  map() = default;
34  map( map&& ) = default;
35  };
36  struct array {
42  struct decrement {
43  long m_min;
44  decrement( long m ) : m_min( m ) {}
45  bool operator()( long& j ) const
46  {
47  if ( j > m_min ) --j;
48  return true;
49  }
50  };
51  array() = default;
52  array( array&& ) = default;
53  };
54  struct vector {
58  vector() = default;
59  vector( vector&& ) = default;
60  };
61 
62  template <class CONT>
63  class find
64  {
65  const void* m_obj;
66  typedef typename CONT::value_type v_type;
67 
68  public:
69  find( const void* o ) : m_obj( o ) {}
70  bool operator()( const void* cmp ) const { return cmp == m_obj; }
71  bool operator()( const v_type& cmp ) const { return ( *this )( cmp.second ); }
72  };
73 }
75 {
76  throw GaudiException( "Cannot assign key to keyed object! Object already has a key.", "KeyedObject", 0 );
77 }
79 {
80  throw GaudiException( "Cannot insert element to Keyed Container!", "KeyedContainer", 0 );
81 }
82 
84 {
85  throw GaudiException( "Keyed Container structures are inconsistent - severe problem!", "KeyedContainer", 0 );
86 }
87 
89 {
90  throw GaudiException( "Keyed Container cannot satisfy request - severe problem!", "KeyedContainer", 0 );
91 }
92 
93 template <class T>
94 Containers::KeyedObjectManager<T>::KeyedObjectManager() : m_seq( nullptr ), m_direct( 0 )
95 {
96  if ( sizeof( typename T::map_type ) > sizeof( m_setup.buffer ) ) {
97  throw GaudiException( "Basic STL contaier sizes are incompatible", "KeyedContainer", 0 );
98  }
99  m_setup.s = ::new ( m_setup.buffer + sizeof( m_setup.s ) ) T();
100  m_keyCtxt = -1;
101 }
102 
103 template <class T>
105  : m_seq( nullptr ), m_direct( other.m_direct ), m_keyCtxt( other.m_keyCtxt )
106 {
107  m_setup.s = ::new ( m_setup.buffer + sizeof( m_setup.s ) ) T( std::move( *other.m_setup.s ) );
108 
109  other.m_keyCtxt = -1;
110  other.m_seq = nullptr;
111  other.m_direct = 0;
112 }
113 
114 template <class T>
116 {
117  m_setup.s->~T();
118 }
119 
121 template <class T>
123 {
124  m_seq = (seq_type*)seq;
125  *rndm = &m_setup.s->v;
126 }
127 
128 template <class T>
130 {
131  m_direct = 1;
132  auto& s = *m_setup.s;
133  long i = 0;
134  for ( auto p : s.v ) s.insert( p, i++ );
135  s.v.clear();
136 }
137 
138 template <class T>
140  long* key )
141 {
142  *key = ++m_keyCtxt;
143  return insert( pBase, pObject, obj, *key );
144 }
145 
146 template <class T>
148  long key )
149 {
151  if ( key > m_keyCtxt ) {
152  m_keyCtxt = key;
153  }
154  if ( 1 == m_direct ) {
155  if ( m_setup.s->insert( obj, key ) ) {
156  if ( !pObject->parent() ) {
157  pObject->setParent( pBase );
158  }
159  m_seq->push_back( obj );
160  return OBJ_INSERTED;
161  }
162  } else if ( key == long( m_setup.s->v.size() ) ) {
163  m_setup.s->v.push_back( obj );
164  if ( !pObject->parent() ) {
165  pObject->setParent( pBase );
166  }
167  m_seq->push_back( obj );
168  return OBJ_INSERTED;
169  } else {
170  // Document is dirty now...
171  // need to copy all pointers from the vector to the map
172  onDirty();
173  return insert( pBase, pObject, obj, key );
174  }
176  return OBJ_CANNOT_INSERT;
177 }
178 
179 template <class T>
181  long key )
182 {
184  if ( key > m_keyCtxt ) {
185  m_keyCtxt = key;
186  }
187  if ( 1 == m_direct ) {
188  if ( m_setup.s->insert( obj, key ) ) {
189  if ( !pObject->parent() ) {
190  pObject->setParent( pBase );
191  }
192  return OBJ_INSERTED;
193  }
194  } else if ( key == long( m_setup.s->v.size() ) ) {
195  m_setup.s->v.push_back( obj );
196  if ( !pObject->parent() ) {
197  pObject->setParent( pBase );
198  }
199  return OBJ_INSERTED;
200  } else {
201  // Document is dirty now...
202  // need to copy all pointers from the vector to the map
203  onDirty();
204  return insertDirect( pBase, pObject, obj, key );
205  }
207  return OBJ_CANNOT_INSERT;
208 }
209 
210 // Remove object from container
211 template <class T>
212 void* Containers::KeyedObjectManager<T>::erase( long key, const void* obj )
213 {
214  typedef typename T::map_type MTYP;
215  typedef find<MTYP> FND;
216  if ( 1 == m_direct ) {
217  auto& m = m_setup.s->m;
218  auto i = ( obj ? std::find_if( m.begin(), m.end(), FND( obj ) ) : m_setup.s->m.find( key ) );
219  if ( i != m_setup.s->m.end() ) {
220  void* o = i->second;
221  auto j = std::find( m_seq->begin(), m_seq->end(), o );
222  if ( j != m_seq->end() ) {
223  m_seq->erase( j );
224  m_setup.s->m.erase( i );
225  return o;
226  }
227  }
229  }
230  onDirty();
231  return erase( key, obj );
232 }
233 
234 template <class T>
236 {
237  if ( 0 == m_direct ) onDirty();
238  auto i = m_setup.s->m.find( key );
239  if ( i != m_setup.s->m.end() ) return ( *i ).second;
240  return nullptr;
241 }
242 
243 template <class T>
245 {
246  switch ( m_direct ) {
247  case 1:
248  break;
249  case 0:
250  m_setup.s->v.reserve( len );
251  break;
252  default:
253  break;
254  }
255  m_seq->reserve( len );
256 }
257 
258 template <class T>
260 {
261  clearDirect();
262  m_seq->clear();
263 }
264 
265 template <class T>
267 {
268  switch ( m_direct ) {
269  case 1:
270  m_setup.s->m.clear();
271  break;
272  case 0:
273  m_setup.s->v.clear();
274  break;
275  default:
276  break;
277  }
278  m_direct = 0;
279  m_keyCtxt = -1;
280 }
281 
282 // Remove object by sequential iterators
283 template <class T>
284 long Containers::KeyedObjectManager<T>::erase( seq_type::iterator beg, seq_type::iterator end )
285 {
286  typedef typename T::map_type MTYP;
287  typedef find<MTYP> FND;
288  if ( 0 == m_direct ) {
289  onDirty();
290  return erase( beg, end );
291  }
292  if ( beg == m_seq->begin() && end == m_seq->end() ) {
293  clear();
294  } else {
295  for ( auto j = beg; j != end; ++j ) {
296  // auto& m = m_setup.s->m;
297  auto i = std::find_if( m_setup.s->m.begin(), m_setup.s->m.end(), FND( *j ) );
298  if ( i != m_setup.s->m.end() ) {
299  m_setup.s->m.erase( i );
300  continue;
301  }
303  }
304  m_seq->erase( beg, end );
305  }
306  return OBJ_ERASED;
307 }
308 
309 namespace Containers
310 {
311 
312  /* First specialize static methods and then instantiate templated class to appear as symbols in the library
313  This order in needed for gcc 4.0 (MacOSX) */
314 
315  template <>
317  {
318  return CLID_ObjectVector + 0x00030000;
319  }
320  template <>
322  {
323  return CLID_ObjectVector + 0x00040000;
324  }
325 
328 }
329 
330 /*
331  *
332  *
333  * Inline code for indirection array implementation
334  *
335  */
337 
338 namespace Containers
339 {
340 
341  //__forceinline
342  template <>
343  void* KeyedObjectManager<__A>::object( long value ) const
344  {
345 #ifdef CHECK_KEYED_CONTAINER
346  unsigned long siz = m_setup.s->m_idx.size();
347  if ( value >= 0 && size_t( value ) < siz ) {
348  long ent = *( m_setup.s->m_idx.begin() + value );
349  if ( ent >= 0 ) {
350  return *( m_setup.s->v.begin() + ent );
351  }
352  }
353  return nullptr;
354 #else
355  return *( m_setup.s->v.begin() + ( *( m_setup.s->m_idx.begin() + value ) ) );
356 #endif
357  }
358 
359  template <>
361  {
362  m_direct = 1;
363  m_setup.s->m_idx.reserve( m_setup.s->v.size() + 1 );
364  for ( int i = 0, stop = m_setup.s->v.size(); i < stop; ++i ) {
365  if ( !m_setup.s->v[i] ) {
367  }
368  m_setup.s->m_idx.push_back( i );
369  }
370  }
371 
372  // Insert new object into container
373  template <>
375  {
376  // auto key creation only possible for direct access!
377  if ( 0 == m_direct ) {
378  m_seq->push_back( o );
379  m_setup.s->v.push_back( o );
380  if ( !c->parent() ) c->setParent( b );
381  *k = ++m_keyCtxt;
382  return OBJ_INSERTED;
383  }
385  return OBJ_CANNOT_INSERT;
386  }
387 
388  // Insert new object into container
389  template <>
391  {
392  if ( 0 == m_direct ) {
393  if ( k == m_keyCtxt + 1 ) {
394  return insert( b, c, o, &k );
395  }
396  onDirty();
397  return insert( b, c, o, k );
398  }
400  if ( k > m_keyCtxt ) m_keyCtxt = k;
402  if ( k + 1 > long( m_setup.s->m_idx.size() ) ) {
403  m_setup.s->m_idx.resize( k + 1, -1 );
404  }
405  auto idx = m_setup.s->m_idx.begin() + k;
406  if ( *idx == -1 ) {
407  *idx = m_setup.s->v.size();
408  m_setup.s->v.push_back( o );
409  m_seq->push_back( o );
410  if ( !c->parent() ) c->setParent( b );
411  return OBJ_INSERTED;
412  }
414  return OBJ_CANNOT_INSERT;
415  }
416 
417  // Insert new object into container
418  template <>
420  {
421  if ( 0 == m_direct ) {
422  if ( k == m_keyCtxt + 1 ) {
423  m_setup.s->v.push_back( o );
424  if ( !c->parent() ) c->setParent( b );
425  ++m_keyCtxt;
426  return OBJ_INSERTED;
427  }
428  onDirty();
429  return insertDirect( b, c, o, k );
430  }
432  if ( k > m_keyCtxt ) m_keyCtxt = k;
434  if ( k + 1 > long( m_setup.s->m_idx.size() ) ) {
435  m_setup.s->m_idx.resize( k + 1, -1 );
436  }
437  auto idx = m_setup.s->m_idx.begin() + k;
438  if ( *idx == -1 ) {
439  *idx = m_setup.s->v.size();
440  m_setup.s->v.push_back( o );
441  if ( !c->parent() ) c->setParent( b );
442  return OBJ_INSERTED;
443  }
445  return OBJ_CANNOT_INSERT;
446  }
447 
448  // Clear content of the vector
449  template <>
451  {
452  m_setup.s->v.clear();
453  m_setup.s->m_idx.clear();
454  m_direct = 0;
455  m_keyCtxt = -1;
456  }
457 
458  // Remove object from container (very inefficient if key is invalid)
459  template <>
460  void* KeyedObjectManager<__A>::erase( long key, const void* obj )
461  {
462  typedef std::vector<long> id_type;
463  if ( 0 == m_direct ) {
464  onDirty();
465  return erase( key, obj );
466  }
467  if ( obj ) {
468  id_type& idx = m_setup.s->m_idx;
469  for ( auto& elem : idx ) {
470  auto j = m_setup.s->v.begin() + ( elem );
471  auto k = std::find( m_seq->begin(), m_seq->end(), *j );
472  if ( *j == obj ) {
473  void* o = *j;
474  m_seq->erase( k );
475  m_setup.s->v.erase( j );
476  std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( elem ) );
477  elem = -1;
478  return o;
479  }
480  }
481  } else if ( key >= 0 && key < long( m_setup.s->m_idx.size() ) ) {
482  auto idx = m_setup.s->m_idx.begin() + key;
483  if ( *idx != -1 ) {
484  auto i = m_setup.s->v.begin() + ( *idx );
485  if ( i == m_setup.s->v.end() ) {
487  }
488  void* o = *i;
489  auto j = std::find( m_seq->begin(), m_seq->end(), o );
490  if ( j == m_seq->end() ) {
492  }
493  m_seq->erase( j );
494  m_setup.s->v.erase( i );
495  std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( *idx ) );
496  *idx = -1;
497  return o;
498  }
499  }
501  return nullptr;
502  }
503 
504  // Remove object by sequential iterators
505  template <>
506  long KeyedObjectManager<__A>::erase( seq_type::iterator beg, seq_type::iterator end )
507  {
508  typedef std::vector<long> id_type;
509  if ( beg == m_seq->begin() && end == m_seq->end() ) {
510  clear();
511  return OBJ_ERASED;
512  } else if ( 0 == m_direct ) {
513  onDirty();
514  return erase( beg, end );
515  } else {
516  long cnt = 0, nobj = end - beg;
517  id_type& idx = m_setup.s->m_idx;
518  for ( auto& elem : idx ) {
519  auto j = m_setup.s->v.begin() + ( elem );
520  auto k = std::find( beg, end, *j );
521  if ( k != end ) {
522  m_setup.s->v.erase( j );
523  std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( elem ) );
524  elem = -1;
525  cnt++;
526  if ( cnt == nobj ) break;
527  }
528  }
529  m_seq->erase( beg, end );
530  if ( cnt != nobj ) {
532  }
533  return OBJ_ERASED;
534  }
535  // cannot reach this point
536  }
537 
538  template <>
540  {
541  return CLID_ObjectVector + 0x00050000;
542  }
543 }
545 /*
546  *
547  *
548  * Implementation for objects with vector like access
549  *
550  *
551  **/
553 
554 namespace Containers
555 {
556  // Access single entry by long(integer) key
557  template <>
558  void* KeyedObjectManager<__V>::object( long /* value */ ) const
559  {
561  return nullptr;
562  }
563 
564  template <>
566  {
568  }
569 
570  // Insert new object into container
571  template <>
573  {
574  m_seq->push_back( o );
575  m_setup.s->v.push_back( o );
576  if ( !c->parent() ) c->setParent( b );
577  *k = ( m_setup.s->v.size() - 1 );
578  return OBJ_INSERTED;
579  }
580 
581  // Insert new object into container
582  template <>
584  {
585  if ( k == long( m_setup.s->v.size() ) ) {
586  return insert( b, c, o, &k );
587  }
589  return OBJ_CANNOT_INSERT;
590  }
591 
592  // Insert new object into container
593  template <>
595  {
596  if ( k == long( m_setup.s->v.size() ) ) {
597  m_setup.s->v.push_back( o );
598  if ( !c->parent() ) c->setParent( b );
599  return OBJ_INSERTED;
600  }
602  return OBJ_CANNOT_INSERT;
603  }
604 
605  // Clear content of the vector
606  template <>
608  {
609  m_setup.s->v.clear();
610  m_direct = 0;
611  m_keyCtxt = -1;
612  }
613 
614  // Remove object from container (very inefficient if key is invalid)
615  template <>
616  void* KeyedObjectManager<__V>::erase( long /* key */, const void* /* obj */ )
617  {
619  return nullptr;
620  }
621 
622  // Remove object by sequential iterators
623  template <>
624  long KeyedObjectManager<__V>::erase( seq_type::iterator beg, seq_type::iterator end )
625  {
626  if ( beg == m_seq->begin() && end == m_seq->end() ) {
627  clear();
628  return OBJ_ERASED;
629  }
631  return OBJ_ERASED;
632  }
633 
634  template <>
636  {
637  return CLID_ObjectVector + 0x00060000;
638  }
639 }
Object was inserted into the container.
Definition: KeyedTraits.h:27
Containers::vector __V
Define general base for Gaudi exception.
std::vector< void * > v
std::vector< void * > map_type
virtual ~KeyedObjectManager()
Standard Destructor.
void clear()
Clear content of the vector.
CONT::value_type v_type
std::vector< long > map_type
union Containers::KeyedObjectManager::@6 m_setup
GAUDI_API void containerIsInconsistent()
Function to be called to indicate that the container is found to be inconsistent. ...
struct GAUDI_API vector
Parametrisation class for vector-like implementation.
void clearDirect()
Clear all direct access fields.
T end(T...args)
std::vector< long > m_idx
Indirection array.
void * object(long key) const
Retrieve object identified by a key from the container.
void * erase(long key, const void *obj)
Remove object from container (very inefficient if key is invalid)
std::map< long, void * > map_type
Containers namespace.
const ObjectContainerBase * parent() const
Access to parent object.
bool insert(void *obj, long key)
GAUDI_API void cannotInsertToContainer()
Function to be called to indicate that an object cannot be inserted to the container.
std::vector< void * > v
Direct access array.
T push_back(T...args)
std::pair< iterator, bool > insert(ValueType &&val)
Definition: Map.h:174
void reserve(long size)
Reserve buffer space.
Cannot insert object into container.
Definition: KeyedTraits.h:28
GAUDI_API void invalidContainerOperation()
Function to be called to indicate that an operation should be performed on the container or it&#39;s cont...
struct GAUDI_API map
Parametrisation class for map-like implementation.
constexpr double m
Definition: SystemOfUnits.h:94
GaudiUtils::HashMap< long, void * > map_type
T erase(T...args)
void onDirty() const
Callback when the container becomes dirty.
auto end(reverse_wrapper< T > &w)
Definition: reverse.h:64
long insert(ObjectContainerBase *b, ContainedObject *c, void *o, long *k)
Insert new object into container.
unsigned int CLID
Class ID definition.
Definition: ClassID.h:8
T clear(T...args)
T move(T...args)
bool operator()(const v_type &cmp) const
T insert(T...args)
Object was removed, but not deleted.
Definition: KeyedTraits.h:26
All classes that their objects may be contained in an LHCb ObjectContainer (e.g.
T find_if(T...args)
struct GAUDI_API array
Parametrisation class for redirection array - like implementation.
GAUDI_API void cannotAssignObjectKey()
Function to be called when an object key cannot be assigned.
T begin(T...args)
KeyedObjectManager Class to manage keyed objects.
std::vector< void * > v
Direct access array.
void setParent(ObjectContainerBase *value)
Update parent member.
static CLID classID()
Access CLID for this type of container.
void setup(void *seq, void **rndm)
Setup of the Map and the parent object.
Containers::array __A
std::vector< void * > v
ObjectContainerBase is the base class for Gaudi container classes.
KeyedObjectManager()
Standard Constructor.
T for_each(T...args)
bool operator()(const void *cmp) const
bool insert(void *obj, long key)
seq_type * m_seq
Container holding array like container.
T reserve(T...args)
long insertDirect(ObjectContainerBase *b, ContainedObject *c, void *o, long k)
Insert element into direct access map.