Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  struct hashmap {
13  map_type m;
15  bool insert( void* obj, long key ) {
16  auto p = m.insert( map_type::value_type( key, obj ) );
17  return p.second;
18  }
19  hashmap() = default;
20  hashmap( hashmap&& ) = default;
21  };
22  struct map {
24  map_type m;
26  bool insert( void* obj, long key ) {
27  auto p = m.insert( map_type::value_type( key, obj ) );
28  return p.second;
29  }
30  map() = default;
31  map( map&& ) = default;
32  };
33  struct array {
39  struct decrement {
40  long m_min;
41  decrement( long m ) : m_min( m ) {}
42  bool operator()( long& j ) const {
43  if ( j > m_min ) --j;
44  return true;
45  }
46  };
47  array() = default;
48  array( array&& ) = default;
49  };
50  struct vector {
54  vector() = default;
55  vector( vector&& ) = default;
56  };
57 
58  template <class CONT>
59  class find {
60  const void* m_obj;
61  typedef typename CONT::value_type v_type;
62 
63  public:
64  find( const void* o ) : m_obj( o ) {}
65  bool operator()( const void* cmp ) const { return cmp == m_obj; }
66  bool operator()( const v_type& cmp ) const { return ( *this )( cmp.second ); }
67  };
68 } // namespace Containers
70  throw GaudiException( "Cannot assign key to keyed object! Object already has a key.", "KeyedObject",
72 }
74  throw GaudiException( "Cannot insert element to Keyed Container!", "KeyedContainer", StatusCode::FAILURE );
75 }
76 
78  throw GaudiException( "Keyed Container structures are inconsistent - severe problem!", "KeyedContainer",
80 }
81 
83  throw GaudiException( "Keyed Container cannot satisfy request - severe problem!", "KeyedContainer",
85 }
86 
87 template <class T>
88 Containers::KeyedObjectManager<T>::KeyedObjectManager() : m_seq( nullptr ), m_direct( 0 ) {
89  if ( sizeof( typename T::map_type ) > sizeof( m_setup.buffer ) ) {
90  throw GaudiException( "Basic STL contaier sizes are incompatible", "KeyedContainer", StatusCode::FAILURE );
91  }
92  m_setup.s = ::new ( m_setup.buffer + sizeof( m_setup.s ) ) T();
93  m_keyCtxt = -1;
94 }
95 
96 template <class T>
98  : m_seq( nullptr ), m_direct( other.m_direct ), m_keyCtxt( other.m_keyCtxt ) {
99  m_setup.s = ::new ( m_setup.buffer + sizeof( m_setup.s ) ) T( std::move( *other.m_setup.s ) );
100 
101  other.m_keyCtxt = -1;
102  other.m_seq = nullptr;
103  other.m_direct = 0;
104 }
105 
106 template <class T>
108  m_setup.s->~T();
109 }
110 
112 template <class T>
113 void Containers::KeyedObjectManager<T>::setup( void* seq, void** rndm ) {
114  m_seq = (seq_type*)seq;
115  *rndm = &m_setup.s->v;
116 }
117 
118 template <class T>
120  m_direct = 1;
121  auto& s = *m_setup.s;
122  long i = 0;
123  for ( auto p : s.v ) s.insert( p, i++ );
124  s.v.clear();
125 }
126 
127 template <class T>
129  long* key ) {
130  *key = ++m_keyCtxt;
131  return insert( pBase, pObject, obj, *key );
132 }
133 
134 template <class T>
136  long key ) {
138  if ( key > m_keyCtxt ) { m_keyCtxt = key; }
139  if ( 1 == m_direct ) {
140  if ( m_setup.s->insert( obj, key ) ) {
141  if ( !pObject->parent() ) { pObject->setParent( pBase ); }
142  m_seq->push_back( obj );
143  return OBJ_INSERTED;
144  }
145  } else if ( key == long( m_setup.s->v.size() ) ) {
146  m_setup.s->v.push_back( obj );
147  if ( !pObject->parent() ) { pObject->setParent( pBase ); }
148  m_seq->push_back( obj );
149  return OBJ_INSERTED;
150  } else {
151  // Document is dirty now...
152  // need to copy all pointers from the vector to the map
153  onDirty();
154  return insert( pBase, pObject, obj, key );
155  }
157  return OBJ_CANNOT_INSERT;
158 }
159 
160 template <class T>
162  long key ) {
164  if ( key > m_keyCtxt ) { m_keyCtxt = key; }
165  if ( 1 == m_direct ) {
166  if ( m_setup.s->insert( obj, key ) ) {
167  if ( !pObject->parent() ) { pObject->setParent( pBase ); }
168  return OBJ_INSERTED;
169  }
170  } else if ( key == long( m_setup.s->v.size() ) ) {
171  m_setup.s->v.push_back( obj );
172  if ( !pObject->parent() ) { pObject->setParent( pBase ); }
173  return OBJ_INSERTED;
174  } else {
175  // Document is dirty now...
176  // need to copy all pointers from the vector to the map
177  onDirty();
178  return insertDirect( pBase, pObject, obj, key );
179  }
181  return OBJ_CANNOT_INSERT;
182 }
183 
184 // Remove object from container
185 template <class T>
186 void* Containers::KeyedObjectManager<T>::erase( long key, const void* obj ) {
187  typedef typename T::map_type MTYP;
188  typedef find<MTYP> FND;
189  if ( 1 == m_direct ) {
190  auto& m = m_setup.s->m;
191  auto i = ( obj ? std::find_if( m.begin(), m.end(), FND( obj ) ) : m_setup.s->m.find( key ) );
192  if ( i != m_setup.s->m.end() ) {
193  void* o = i->second;
194  auto j = std::find( m_seq->begin(), m_seq->end(), o );
195  if ( j != m_seq->end() ) {
196  m_seq->erase( j );
197  m_setup.s->m.erase( i );
198  return o;
199  }
200  }
202  }
203  onDirty();
204  return erase( key, obj );
205 }
206 
207 template <class T>
209  if ( 0 == m_direct ) onDirty();
210  auto i = m_setup.s->m.find( key );
211  if ( i != m_setup.s->m.end() ) return ( *i ).second;
212  return nullptr;
213 }
214 
215 template <class T>
217  switch ( m_direct ) {
218  case 1:
219  break;
220  case 0:
221  m_setup.s->v.reserve( len );
222  break;
223  default:
224  break;
225  }
226  m_seq->reserve( len );
227 }
228 
229 template <class T>
231  clearDirect();
232  m_seq->clear();
233 }
234 
235 template <class T>
237  switch ( m_direct ) {
238  case 1:
239  m_setup.s->m.clear();
240  break;
241  case 0:
242  m_setup.s->v.clear();
243  break;
244  default:
245  break;
246  }
247  m_direct = 0;
248  m_keyCtxt = -1;
249 }
250 
251 // Remove object by sequential iterators
252 template <class T>
253 long Containers::KeyedObjectManager<T>::erase( seq_type::iterator beg, seq_type::iterator end ) {
254  typedef typename T::map_type MTYP;
255  typedef find<MTYP> FND;
256  if ( 0 == m_direct ) {
257  onDirty();
258  return erase( beg, end );
259  }
260  if ( beg == m_seq->begin() && end == m_seq->end() ) {
261  clear();
262  } else {
263  for ( auto j = beg; j != end; ++j ) {
264  // auto& m = m_setup.s->m;
265  auto i = std::find_if( m_setup.s->m.begin(), m_setup.s->m.end(), FND( *j ) );
266  if ( i != m_setup.s->m.end() ) {
267  m_setup.s->m.erase( i );
268  continue;
269  }
271  }
272  m_seq->erase( beg, end );
273  }
274  return OBJ_ERASED;
275 }
276 
277 namespace Containers {
278 
279  /* First specialize static methods and then instantiate templated class to appear as symbols in the library
280  This order in needed for gcc 4.0 (MacOSX) */
281 
282  template <>
284  return CLID_ObjectVector + 0x00030000;
285  }
286  template <>
288  return CLID_ObjectVector + 0x00040000;
289  }
290 
293 } // namespace Containers
294 
295 /*
296  *
297  *
298  * Inline code for indirection array implementation
299  *
300  */
302 
303 namespace Containers {
304 
305  //__forceinline
306  template <>
307  void* KeyedObjectManager<__A>::object( long value ) const {
308 #ifdef CHECK_KEYED_CONTAINER
309  unsigned long siz = m_setup.s->m_idx.size();
310  if ( value >= 0 && size_t( value ) < siz ) {
311  long ent = *( m_setup.s->m_idx.begin() + value );
312  if ( ent >= 0 ) { return *( m_setup.s->v.begin() + ent ); }
313  }
314  return nullptr;
315 #else
316  return *( m_setup.s->v.begin() + ( *( m_setup.s->m_idx.begin() + value ) ) );
317 #endif
318  }
319 
320  template <>
322  m_direct = 1;
323  m_setup.s->m_idx.reserve( m_setup.s->v.size() + 1 );
324  for ( int i = 0, stop = m_setup.s->v.size(); i < stop; ++i ) {
325  if ( !m_setup.s->v[i] ) { containerIsInconsistent(); }
326  m_setup.s->m_idx.push_back( i );
327  }
328  }
329 
330  // Insert new object into container
331  template <>
333  // auto key creation only possible for direct access!
334  if ( 0 == m_direct ) {
335  m_seq->push_back( o );
336  m_setup.s->v.push_back( o );
337  if ( !c->parent() ) c->setParent( b );
338  *k = ++m_keyCtxt;
339  return OBJ_INSERTED;
340  }
342  return OBJ_CANNOT_INSERT;
343  }
344 
345  // Insert new object into container
346  template <>
348  if ( 0 == m_direct ) {
349  if ( k == m_keyCtxt + 1 ) { return insert( b, c, o, &k ); }
350  onDirty();
351  return insert( b, c, o, k );
352  }
354  if ( k > m_keyCtxt ) m_keyCtxt = k;
356  if ( k + 1 > long( m_setup.s->m_idx.size() ) ) { m_setup.s->m_idx.resize( k + 1, -1 ); }
357  auto idx = m_setup.s->m_idx.begin() + k;
358  if ( *idx == -1 ) {
359  *idx = m_setup.s->v.size();
360  m_setup.s->v.push_back( o );
361  m_seq->push_back( o );
362  if ( !c->parent() ) c->setParent( b );
363  return OBJ_INSERTED;
364  }
366  return OBJ_CANNOT_INSERT;
367  }
368 
369  // Insert new object into container
370  template <>
372  if ( 0 == m_direct ) {
373  if ( k == m_keyCtxt + 1 ) {
374  m_setup.s->v.push_back( o );
375  if ( !c->parent() ) c->setParent( b );
376  ++m_keyCtxt;
377  return OBJ_INSERTED;
378  }
379  onDirty();
380  return insertDirect( b, c, o, k );
381  }
383  if ( k > m_keyCtxt ) m_keyCtxt = k;
385  if ( k + 1 > long( m_setup.s->m_idx.size() ) ) { m_setup.s->m_idx.resize( k + 1, -1 ); }
386  auto idx = m_setup.s->m_idx.begin() + k;
387  if ( *idx == -1 ) {
388  *idx = m_setup.s->v.size();
389  m_setup.s->v.push_back( o );
390  if ( !c->parent() ) c->setParent( b );
391  return OBJ_INSERTED;
392  }
394  return OBJ_CANNOT_INSERT;
395  }
396 
397  // Clear content of the vector
398  template <>
400  m_setup.s->v.clear();
401  m_setup.s->m_idx.clear();
402  m_direct = 0;
403  m_keyCtxt = -1;
404  }
405 
406  // Remove object from container (very inefficient if key is invalid)
407  template <>
408  void* KeyedObjectManager<__A>::erase( long key, const void* obj ) {
409  if ( 0 == m_direct ) {
410  onDirty();
411  return erase( key, obj );
412  }
413  if ( obj ) {
414  auto& idx = m_setup.s->m_idx;
415  for ( auto& elem : idx ) {
416  auto j = m_setup.s->v.begin() + ( elem );
417  auto k = std::find( m_seq->begin(), m_seq->end(), *j );
418  if ( *j == obj ) {
419  void* o = *j;
420  m_seq->erase( k );
421  m_setup.s->v.erase( j );
422  std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( elem ) );
423  elem = -1;
424  return o;
425  }
426  }
427  } else if ( key >= 0 && key < long( m_setup.s->m_idx.size() ) ) {
428  auto idx = m_setup.s->m_idx.begin() + key;
429  if ( *idx != -1 ) {
430  auto i = m_setup.s->v.begin() + ( *idx );
431  if ( i == m_setup.s->v.end() ) { containerIsInconsistent(); }
432  void* o = *i;
433  auto j = std::find( m_seq->begin(), m_seq->end(), o );
434  if ( j == m_seq->end() ) { containerIsInconsistent(); }
435  m_seq->erase( j );
436  m_setup.s->v.erase( i );
437  std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( *idx ) );
438  *idx = -1;
439  return o;
440  }
441  }
443  return nullptr;
444  }
445 
446  // Remove object by sequential iterators
447  template <>
448  long KeyedObjectManager<__A>::erase( seq_type::iterator beg, seq_type::iterator end ) {
449  if ( beg == m_seq->begin() && end == m_seq->end() ) {
450  clear();
451  return OBJ_ERASED;
452  } else if ( 0 == m_direct ) {
453  onDirty();
454  return erase( beg, end );
455  } else {
456  long cnt = 0, nobj = end - beg;
457  auto& idx = m_setup.s->m_idx;
458  for ( auto& elem : idx ) {
459  auto j = m_setup.s->v.begin() + ( elem );
460  auto k = std::find( beg, end, *j );
461  if ( k != end ) {
462  m_setup.s->v.erase( j );
463  std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( elem ) );
464  elem = -1;
465  cnt++;
466  if ( cnt == nobj ) break;
467  }
468  }
469  m_seq->erase( beg, end );
470  if ( cnt != nobj ) { containerIsInconsistent(); }
471  return OBJ_ERASED;
472  }
473  // cannot reach this point
474  }
475 
476  template <>
478  return CLID_ObjectVector + 0x00050000;
479  }
480 } // namespace Containers
482 /*
483  *
484  *
485  * Implementation for objects with vector like access
486  *
487  *
488  **/
490 
491 namespace Containers {
492  // Access single entry by long(integer) key
493  template <>
494  void* KeyedObjectManager<__V>::object( long /* value */ ) const {
496  return nullptr;
497  }
498 
499  template <>
502  }
503 
504  // Insert new object into container
505  template <>
507  m_seq->push_back( o );
508  m_setup.s->v.push_back( o );
509  if ( !c->parent() ) c->setParent( b );
510  *k = ( m_setup.s->v.size() - 1 );
511  return OBJ_INSERTED;
512  }
513 
514  // Insert new object into container
515  template <>
517  if ( k == long( m_setup.s->v.size() ) ) { return insert( b, c, o, &k ); }
519  return OBJ_CANNOT_INSERT;
520  }
521 
522  // Insert new object into container
523  template <>
525  if ( k == long( m_setup.s->v.size() ) ) {
526  m_setup.s->v.push_back( o );
527  if ( !c->parent() ) c->setParent( b );
528  return OBJ_INSERTED;
529  }
531  return OBJ_CANNOT_INSERT;
532  }
533 
534  // Clear content of the vector
535  template <>
537  m_setup.s->v.clear();
538  m_direct = 0;
539  m_keyCtxt = -1;
540  }
541 
542  // Remove object from container (very inefficient if key is invalid)
543  template <>
544  void* KeyedObjectManager<__V>::erase( long /* key */, const void* /* obj */ ) {
546  return nullptr;
547  }
548 
549  // Remove object by sequential iterators
550  template <>
551  long KeyedObjectManager<__V>::erase( seq_type::iterator beg, seq_type::iterator end ) {
552  if ( beg == m_seq->begin() && end == m_seq->end() ) {
553  clear();
554  return OBJ_ERASED;
555  }
557  return OBJ_ERASED;
558  }
559 
560  template <>
562  return CLID_ObjectVector + 0x00060000;
563  }
564 } // namespace Containers
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
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.
Object was inserted into the container.
Definition: KeyedTraits.h:26
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:168
void reserve(long size)
Reserve buffer space.
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:92
GaudiUtils::HashMap< long, void * > map_type
T erase(T...args)
void onDirty() const
Callback when the container becomes dirty.
Object was removed, but not deleted.
Definition: KeyedTraits.h:25
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)
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)
Cannot insert object into container.
Definition: KeyedTraits.h:27
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.
constexpr static const auto FAILURE
Definition: StatusCode.h:86
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.
union Containers::KeyedObjectManager::@2 m_setup