The Gaudi Framework  master (b9786168)
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 };
67 template <class CONT>
68 class find {
69 const void* m_obj;
70 typedef typename CONT::value_type v_type;
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",
83 throw GaudiException( "Cannot insert element to Keyed Container!", "KeyedContainer", StatusCode::FAILURE );
84}
87 throw GaudiException( "Keyed Container structures are inconsistent - severe problem!", "KeyedContainer",
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.
Definition KeyedTraits.h:45
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.