The Gaudi Framework  master (3c045658)
Loading...
Searching...
No Matches
KeyedObjectManager.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
13#include <GaudiKernel/HashMap.h>
14#include <GaudiKernel/Kernel.h>
16#include <map>
17#include <vector>
18
19namespace Containers {
20 struct hashmap {
23 std::vector<void*> v;
24 bool insert( void* obj, long key ) {
25 auto p = m.insert( map_type::value_type( key, obj ) );
26 return p.second;
27 }
28 hashmap() = default;
29 hashmap( hashmap&& ) = default;
30 };
31 struct map {
32 typedef std::map<long, void*> map_type;
34 std::vector<void*> v;
35 bool insert( void* obj, long key ) {
36 auto p = m.insert( map_type::value_type( key, obj ) );
37 return p.second;
38 }
39 map() = default;
40 map( map&& ) = default;
41 };
42 struct array {
43 typedef std::vector<long> map_type;
45 std::vector<long> m_idx;
47 std::vector<void*> v;
48 struct decrement {
49 long m_min;
50 decrement( long m ) : m_min( m ) {}
51 bool operator()( long& j ) const {
52 if ( j > m_min ) --j;
53 return true;
54 }
55 };
56 array() = default;
57 array( array&& ) = default;
58 };
59 struct vector {
60 typedef std::vector<void*> map_type;
62 std::vector<void*> v;
63 vector() = default;
64 vector( vector&& ) = default;
65 };
66
67 template <class CONT>
68 class find {
69 const void* m_obj;
70 typedef typename CONT::value_type v_type;
71
72 public:
73 find( const void* o ) : m_obj( o ) {}
74 bool operator()( const void* cmp ) const { return cmp == m_obj; }
75 bool operator()( const v_type& cmp ) const { return ( *this )( cmp.second ); }
76 };
77} // namespace Containers
79 throw GaudiException( "Cannot assign key to keyed object! Object already has a key.", "KeyedObject",
81}
83 throw GaudiException( "Cannot insert element to Keyed Container!", "KeyedContainer", StatusCode::FAILURE );
84}
85
87 throw GaudiException( "Keyed Container structures are inconsistent - severe problem!", "KeyedContainer",
89}
90
92 throw GaudiException( "Keyed Container cannot satisfy request - severe problem!", "KeyedContainer",
94}
95
96template <class T>
98 if ( sizeof( typename T::map_type ) > sizeof( m_setup.buffer ) ) {
99 throw GaudiException( "Basic STL contaier sizes are incompatible", "KeyedContainer", StatusCode::FAILURE );
100 }
101 m_setup.s = ::new ( m_setup.buffer + sizeof( m_setup.s ) ) T();
102 m_keyCtxt = -1;
103}
104
105template <class T>
107 : m_seq( nullptr ), m_direct( other.m_direct ), m_keyCtxt( other.m_keyCtxt ) {
108 m_setup.s = ::new ( m_setup.buffer + sizeof( m_setup.s ) ) T( std::move( *other.m_setup.s ) );
109
110 other.m_keyCtxt = -1;
111 other.m_seq = nullptr;
112 other.m_direct = 0;
113}
114
115// the usage of namespace here is only to avoid a clang11/12 compiler warning
116// due to a miswording in the specification of C++ and fixed in C++20, see
117// https://stackoverflow.com/questions/68751682/is-a-class-templates-name-in-scope-for-a-qualified-out-of-line-destructors-def
118namespace Containers {
119 template <class T>
123} // namespace Containers
124
126template <class T>
127void Containers::KeyedObjectManager<T>::setup( void* seq, void** rndm ) {
128 m_seq = (seq_type*)seq;
129 *rndm = &m_setup.s->v;
130}
131
132template <class T>
134 m_direct = 1;
135 auto& s = *m_setup.s;
136 long i = 0;
137 for ( auto p : s.v ) s.insert( p, i++ );
138 s.v.clear();
139}
140
141template <class T>
143 long* key ) {
144 *key = ++m_keyCtxt;
145 return insert( pBase, pObject, obj, *key );
146}
147
148template <class T>
150 long key ) {
152 if ( key > m_keyCtxt ) { m_keyCtxt = key; }
153 if ( 1 == m_direct ) {
154 if ( m_setup.s->insert( obj, key ) ) {
155 if ( !pObject->parent() ) { pObject->setParent( pBase ); }
156 m_seq->push_back( obj );
157 return OBJ_INSERTED;
158 }
159 } else if ( key == long( m_setup.s->v.size() ) ) {
160 m_setup.s->v.push_back( obj );
161 if ( !pObject->parent() ) { pObject->setParent( pBase ); }
162 m_seq->push_back( obj );
163 return OBJ_INSERTED;
164 } else {
165 // Document is dirty now...
166 // need to copy all pointers from the vector to the map
167 onDirty();
168 return insert( pBase, pObject, obj, key );
169 }
171 return OBJ_CANNOT_INSERT;
172}
173
174template <class T>
176 long key ) {
178 if ( key > m_keyCtxt ) { m_keyCtxt = key; }
179 if ( 1 == m_direct ) {
180 if ( m_setup.s->insert( obj, key ) ) {
181 if ( !pObject->parent() ) { pObject->setParent( pBase ); }
182 return OBJ_INSERTED;
183 }
184 } else if ( key == long( m_setup.s->v.size() ) ) {
185 m_setup.s->v.push_back( obj );
186 if ( !pObject->parent() ) { pObject->setParent( pBase ); }
187 return OBJ_INSERTED;
188 } else {
189 // Document is dirty now...
190 // need to copy all pointers from the vector to the map
191 onDirty();
192 return insertDirect( pBase, pObject, obj, key );
193 }
195 return OBJ_CANNOT_INSERT;
196}
197
198// Remove object from container
199template <class T>
200void* Containers::KeyedObjectManager<T>::erase( long key, const void* obj ) {
201 typedef typename T::map_type MTYP;
202 typedef find<MTYP> FND;
203 if ( 1 == m_direct ) {
204 auto& m = m_setup.s->m;
205 auto i = ( obj ? std::find_if( m.begin(), m.end(), FND( obj ) ) : m_setup.s->m.find( key ) );
206 if ( i != m_setup.s->m.end() ) {
207 void* o = i->second;
208 auto j = std::find( m_seq->begin(), m_seq->end(), o );
209 if ( j != m_seq->end() ) {
210 m_seq->erase( j );
211 m_setup.s->m.erase( i );
212 return o;
213 }
214 }
216 }
217 onDirty();
218 return erase( key, obj );
219}
220
221template <class T>
223 if ( 0 == m_direct ) onDirty();
224 auto i = m_setup.s->m.find( key );
225 if ( i != m_setup.s->m.end() ) return ( *i ).second;
226 return nullptr;
227}
228
229template <class T>
231 switch ( m_direct ) {
232 case 1:
233 break;
234 case 0:
235 m_setup.s->v.reserve( len );
236 break;
237 default:
238 break;
239 }
240 m_seq->reserve( len );
241}
242
243template <class T>
248
249template <class T>
251 switch ( m_direct ) {
252 case 1:
253 m_setup.s->m.clear();
254 break;
255 case 0:
256 m_setup.s->v.clear();
257 break;
258 default:
259 break;
260 }
261 m_direct = 0;
262 m_keyCtxt = -1;
263}
264
265// Remove object by sequential iterators
266template <class T>
267long Containers::KeyedObjectManager<T>::erase( seq_type::iterator beg, seq_type::iterator end ) {
268 typedef typename T::map_type MTYP;
269 typedef find<MTYP> FND;
270 if ( 0 == m_direct ) {
271 onDirty();
272 return erase( beg, end );
273 }
274 if ( beg == m_seq->begin() && end == m_seq->end() ) {
275 clear();
276 } else {
277 for ( auto j = beg; j != end; ++j ) {
278 // auto& m = m_setup.s->m;
279 auto i = std::find_if( m_setup.s->m.begin(), m_setup.s->m.end(), FND( *j ) );
280 if ( i != m_setup.s->m.end() ) {
281 m_setup.s->m.erase( i );
282 continue;
283 }
285 }
286 m_seq->erase( beg, end );
287 }
288 return OBJ_ERASED;
289}
290
291namespace Containers {
292
293 /* First specialize static methods and then instantiate templated class to appear as symbols in the library
294 This order in needed for gcc 4.0 (MacOSX) */
295
296 template <>
298 return CLID_ObjectVector + 0x00030000;
299 }
300 template <>
302 return CLID_ObjectVector + 0x00040000;
303 }
304
307} // namespace Containers
308
309/*
310 *
311 *
312 * Inline code for indirection array implementation
313 *
314 */
316
317namespace Containers {
318
319 //__forceinline
320 template <>
321 void* KeyedObjectManager<__A>::object( long value ) const {
322#ifdef CHECK_KEYED_CONTAINER
323 unsigned long siz = m_setup.s->m_idx.size();
324 if ( value >= 0 && size_t( value ) < siz ) {
325 long ent = *( m_setup.s->m_idx.begin() + value );
326 if ( ent >= 0 ) { return *( m_setup.s->v.begin() + ent ); }
327 }
328 return nullptr;
329#else
330 return *( m_setup.s->v.begin() + ( *( m_setup.s->m_idx.begin() + value ) ) );
331#endif
332 }
333
334 template <>
336 m_direct = 1;
337 m_setup.s->m_idx.reserve( m_setup.s->v.size() + 1 );
338 for ( size_t i = 0, stop = m_setup.s->v.size(); i < stop; ++i ) {
339 if ( !m_setup.s->v[i] ) { containerIsInconsistent(); }
340 m_setup.s->m_idx.push_back( i );
341 }
342 }
343
344 // Insert new object into container
345 template <>
347 // auto key creation only possible for direct access!
348 if ( 0 == m_direct ) {
349 m_seq->push_back( o );
350 m_setup.s->v.push_back( o );
351 if ( !c->parent() ) c->setParent( b );
352 *k = ++m_keyCtxt;
353 return OBJ_INSERTED;
354 }
356 return OBJ_CANNOT_INSERT;
357 }
358
359 // Insert new object into container
360 template <>
362 if ( 0 == m_direct ) {
363 if ( k == m_keyCtxt + 1 ) { return insert( b, c, o, &k ); }
364 onDirty();
365 return insert( b, c, o, k );
366 }
368 if ( k > m_keyCtxt ) m_keyCtxt = k;
370 if ( k + 1 > long( m_setup.s->m_idx.size() ) ) { m_setup.s->m_idx.resize( k + 1, -1 ); }
371 auto idx = m_setup.s->m_idx.begin() + k;
372 if ( *idx == -1 ) {
373 *idx = m_setup.s->v.size();
374 m_setup.s->v.push_back( o );
375 m_seq->push_back( o );
376 if ( !c->parent() ) c->setParent( b );
377 return OBJ_INSERTED;
378 }
380 return OBJ_CANNOT_INSERT;
381 }
382
383 // Insert new object into container
384 template <>
386 if ( 0 == m_direct ) {
387 if ( k == m_keyCtxt + 1 ) {
388 m_setup.s->v.push_back( o );
389 if ( !c->parent() ) c->setParent( b );
390 ++m_keyCtxt;
391 return OBJ_INSERTED;
392 }
393 onDirty();
394 return insertDirect( b, c, o, k );
395 }
397 if ( k > m_keyCtxt ) m_keyCtxt = k;
399 if ( k + 1 > long( m_setup.s->m_idx.size() ) ) { m_setup.s->m_idx.resize( k + 1, -1 ); }
400 auto idx = m_setup.s->m_idx.begin() + k;
401 if ( *idx == -1 ) {
402 *idx = m_setup.s->v.size();
403 m_setup.s->v.push_back( o );
404 if ( !c->parent() ) c->setParent( b );
405 return OBJ_INSERTED;
406 }
408 return OBJ_CANNOT_INSERT;
409 }
410
411 // Clear content of the vector
412 template <>
414 m_setup.s->v.clear();
415 m_setup.s->m_idx.clear();
416 m_direct = 0;
417 m_keyCtxt = -1;
418 }
419
420 // Remove object from container (very inefficient if key is invalid)
421 template <>
422 void* KeyedObjectManager<__A>::erase( long key, const void* obj ) {
423 if ( 0 == m_direct ) {
424 onDirty();
425 return erase( key, obj );
426 }
427 if ( obj ) {
428 auto& idx = m_setup.s->m_idx;
429 for ( auto& elem : idx ) {
430 auto j = m_setup.s->v.begin() + ( elem );
431 auto k = std::find( m_seq->begin(), m_seq->end(), *j );
432 if ( *j == obj ) {
433 void* o = *j;
434 m_seq->erase( k );
435 m_setup.s->v.erase( j );
436 std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( elem ) );
437 elem = -1;
438 return o;
439 }
440 }
441 } else if ( key >= 0 && key < long( m_setup.s->m_idx.size() ) ) {
442 auto idx = m_setup.s->m_idx.begin() + key;
443 if ( *idx != -1 ) {
444 auto i = m_setup.s->v.begin() + ( *idx );
445 if ( i == m_setup.s->v.end() ) { containerIsInconsistent(); }
446 void* o = *i;
447 auto j = std::find( m_seq->begin(), m_seq->end(), o );
448 if ( j == m_seq->end() ) { containerIsInconsistent(); }
449 m_seq->erase( j );
450 m_setup.s->v.erase( i );
451 std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( *idx ) );
452 *idx = -1;
453 return o;
454 }
455 }
457 return nullptr;
458 }
459
460 // Remove object by sequential iterators
461 template <>
462 long KeyedObjectManager<__A>::erase( seq_type::iterator beg, seq_type::iterator end ) {
463 if ( beg == m_seq->begin() && end == m_seq->end() ) {
464 clear();
465 return OBJ_ERASED;
466 } else if ( 0 == m_direct ) {
467 onDirty();
468 return erase( beg, end );
469 } else {
470 long cnt = 0, nobj = end - beg;
471 auto& idx = m_setup.s->m_idx;
472 for ( auto& elem : idx ) {
473 auto j = m_setup.s->v.begin() + ( elem );
474 auto k = std::find( beg, end, *j );
475 if ( k != end ) {
476 m_setup.s->v.erase( j );
477 std::for_each( m_setup.s->m_idx.begin(), m_setup.s->m_idx.end(), array::decrement( elem ) );
478 elem = -1;
479 cnt++;
480 if ( cnt == nobj ) break;
481 }
482 }
483 m_seq->erase( beg, end );
484 if ( cnt != nobj ) { containerIsInconsistent(); }
485 return OBJ_ERASED;
486 }
487 // cannot reach this point
488 }
489
490 template <>
492 return CLID_ObjectVector + 0x00050000;
493 }
494} // namespace Containers
496/*
497 *
498 *
499 * Implementation for objects with vector like access
500 *
501 *
502 **/
504
505namespace Containers {
506 // Access single entry by long(integer) key
507 template <>
508 void* KeyedObjectManager<__V>::object( long /* value */ ) const {
510 return nullptr;
511 }
512
513 template <>
517
518 // Insert new object into container
519 template <>
521 m_seq->push_back( o );
522 m_setup.s->v.push_back( o );
523 if ( !c->parent() ) c->setParent( b );
524 *k = ( m_setup.s->v.size() - 1 );
525 return OBJ_INSERTED;
526 }
527
528 // Insert new object into container
529 template <>
531 if ( k == long( m_setup.s->v.size() ) ) { return insert( b, c, o, &k ); }
533 return OBJ_CANNOT_INSERT;
534 }
535
536 // Insert new object into container
537 template <>
539 if ( k == long( m_setup.s->v.size() ) ) {
540 m_setup.s->v.push_back( o );
541 if ( !c->parent() ) c->setParent( b );
542 return OBJ_INSERTED;
543 }
545 return OBJ_CANNOT_INSERT;
546 }
547
548 // Clear content of the vector
549 template <>
551 m_setup.s->v.clear();
552 m_direct = 0;
553 m_keyCtxt = -1;
554 }
555
556 // Remove object from container (very inefficient if key is invalid)
557 template <>
558 void* KeyedObjectManager<__V>::erase( long /* key */, const void* /* obj */ ) {
560 return nullptr;
561 }
562
563 // Remove object by sequential iterators
564 template <>
565 long KeyedObjectManager<__V>::erase( seq_type::iterator beg, seq_type::iterator end ) {
566 if ( beg == m_seq->begin() && end == m_seq->end() ) {
567 clear();
568 return OBJ_ERASED;
569 }
571 return OBJ_ERASED;
572 }
573
574 template <>
576 return CLID_ObjectVector + 0x00060000;
577 }
578} // namespace Containers
unsigned int CLID
Class ID definition.
Definition ClassID.h:16
Containers::array __A
Containers::vector __V
All classes that their objects may be contained in an LHCb ObjectContainer (e.g.
void setParent(ObjectContainerBase *value)
Update parent member.
const ObjectContainerBase * parent() const
Access to parent object.
KeyedObjectManager Class to manage keyed objects.
static CLID classID()
Access CLID for this type of container.
void onDirty() const
Callback when the container becomes dirty.
void * erase(long key, const void *obj)
Remove object from container (very inefficient if key is invalid).
void setup(void *seq, void **rndm)
Setup of the Map and the parent object.
virtual ~KeyedObjectManager()
Standard Destructor.
void clearDirect()
Clear all direct access fields.
void * object(long key) const
Retrieve object identified by a key from the container.
KeyedObjectManager()
Standard Constructor.
union Containers::KeyedObjectManager::@010153222074056071241275200334232161065316116020 m_setup
seq_type * m_seq
Container holding array like container.
void reserve(long size)
Reserve buffer space.
void clear()
Clear content of the vector.
long insert(ObjectContainerBase *b, ContainedObject *c, void *o, long *k)
Insert new object into container.
long insertDirect(ObjectContainerBase *b, ContainedObject *c, void *o, long k)
Insert element into direct access map.
bool operator()(const v_type &cmp) const
bool operator()(const void *cmp) const
CONT::value_type v_type
Define general base for Gaudi exception.
Common class providing an architecture-independent hash map.
Definition HashMap.h:80
ObjectContainerBase is the base class for Gaudi container classes.
constexpr static const auto FAILURE
Definition StatusCode.h:100
GAUDI_API void containerIsInconsistent()
Function to be called to indicate that the container is found to be inconsistent.
@ OBJ_INSERTED
Object was inserted into the container.
Definition KeyedTraits.h:33
@ OBJ_ERASED
Object was removed, but not deleted.
Definition KeyedTraits.h:32
@ OBJ_CANNOT_INSERT
Cannot insert object into container.
Definition KeyedTraits.h:34
GAUDI_API void cannotAssignObjectKey()
Function to be called when an object key cannot be assigned.
GAUDI_API void cannotInsertToContainer()
Function to be called to indicate that an object cannot be inserted to the container.
GAUDI_API void invalidContainerOperation()
Function to be called to indicate that an operation should be performed on the container or it's cont...
std::vector< void * > v
Direct access array.
std::vector< long > map_type
std::vector< long > m_idx
Indirection array.
array(array &&)=default
std::vector< void * > v
hashmap(hashmap &&)=default
GaudiUtils::HashMap< long, void * > map_type
bool insert(void *obj, long key)
map(map &&)=default
bool insert(void *obj, long key)
std::map< long, void * > map_type
std::vector< void * > v
std::vector< void * > map_type
vector(vector &&)=default
std::vector< void * > v
Direct access array.