Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:13:44

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
0010 \***********************************************************************************/
0011 #ifndef GAUDIKERNEL_KEYEDCONTAINER_H
0012 #define GAUDIKERNEL_KEYEDCONTAINER_H
0013 
0014 // Include files
0015 #include <algorithm>
0016 #include <iterator>
0017 
0018 namespace GaudiDict {
0019   template <class T>
0020   struct KeyedContainerDict;
0021 }
0022 
0023 // Framework include files
0024 #include <GaudiKernel/KeyedObject.h>
0025 #include <GaudiKernel/KeyedObjectManager.h>
0026 #include <GaudiKernel/ObjectContainerBase.h>
0027 
0028 // Forward declarations
0029 // template <class T, class M> class KeyedContainer;
0030 
0031 #ifdef WIN32
0032 #  define FORCE_INLINE __forceinline
0033 #else
0034 #  define FORCE_INLINE inline
0035 #endif
0036 
0037 /** template class KeyedContainer, KeyedContainer.h
0038  *
0039  *  This class represents a container, where the contained objects
0040  *  are accessed by a key. Such a key can be any class, which is able
0041  *  to convert to and from a 32-bit (long) integer.
0042  *
0043  *  To insert objects into the container, this implementation
0044  *  determines the key in the following way:
0045  *  - If the object is already keyed, the object's key is kept
0046  *    and cannot be modified.
0047  *  - If the object is NOT keyed, and a key is supplied,
0048  *    this key is used to register the object in the map and
0049  *    the same key is given to the object.
0050  *  - If the object is NOT keyed, and NO key is supplied,
0051  *    a key is generated by the map implementation and this
0052  *    key is given to the object.
0053  *
0054  *  - It is not possible to insert two objects with the same key
0055  *    into the same container. This causes an exception.
0056  *
0057  *  Access to objects is given two-fold:
0058  *  - Using iterators. This access is very efficient. The container
0059  *    however, may not be manipulated: No objects may not be
0060  *    inserted or removed using iterators.
0061  *  - Using object keys: This access patterns provides random
0062  *    access to objects.
0063  *
0064  *  The KeyedContainer class uses for further specialization a traits
0065  *  class. By specializing these traits extra behaviour can be
0066  *  forced on request for special containers or special keys.
0067  *
0068  *
0069  *  @author   M.Frank CERN/LHCb
0070  *  @version  1.0
0071  *
0072  */
0073 template <class DATATYPE, class MAPPING = Containers::HashMap>
0074 class GAUDI_API KeyedContainer : public ObjectContainerBase {
0075   friend struct GaudiDict::KeyedContainerDict<DATATYPE>;
0076 
0077 public:
0078   /// Definition of the contained object type
0079   typedef DATATYPE contained_type;
0080   /// Definition of the implementing container type
0081   typedef MAPPING container_type;
0082 
0083   /** General container specific type definitions.
0084       The following type definitions are generic to most STL containers
0085       and are also presented by the KeyedContainer class.
0086       These forward declarations typically are used by STL algorithms.
0087   */
0088   //@{
0089   /// Definition of the STL sequential access type
0090   typedef typename std::vector<contained_type*> seq_type;
0091   /// Definition of the key type: re-use definition of contained type
0092   typedef typename contained_type::key_type key_type;
0093   /// Sequential access: definition of type stored in sequential container
0094   typedef typename seq_type::value_type value_type;
0095   /// Sequential access: reference type used in sequential container
0096   typedef typename seq_type::reference reference;
0097   /// Sequential access: const reference type used in sequential container
0098   typedef typename seq_type::const_reference const_reference;
0099   /// Sequential access: iterator type used in sequential container
0100   typedef typename seq_type::iterator iterator;
0101   /// Sequential access: const iterator type used in sequential container
0102   typedef typename seq_type::const_iterator const_iterator;
0103   /// Sequential access: reverse iterator type used in sequential container
0104   typedef typename seq_type::reverse_iterator reverse_iterator;
0105   /** Sequential access: const reverse iterator type used in
0106       sequential container.
0107   */
0108   typedef typename seq_type::const_reverse_iterator const_reverse_iterator;
0109   //@}
0110 private:
0111   /** Traits class definition. Specializing traits allows to specialize the
0112    *  container implementation for special needs.
0113    */
0114   typedef typename Containers::traits<container_type, contained_type> traits;
0115 
0116   /**@name Implementation helpers.
0117    */
0118   //@{
0119   /// Map container to facilitate object access by key.
0120   container_type m_cont;
0121   /// Array to allow sequential access to the object (can be ordered).
0122   seq_type m_sequential;
0123   /// Array to allow random access to objects (not exposed)
0124   seq_type* m_random;
0125 
0126 /// Internal function to access objects within the container
0127 #ifdef CHECK_KEYED_CONTAINER
0128   value_type i_object( const key_type& k ) const {
0129     if ( 0 == m_cont.isDirect() ) {
0130       if ( traits::checkBounds( m_random, k ) ) {
0131         value_type p = *( m_random->begin() + traits::hash( k ) );
0132         if ( traits::checkKey( p, k ) ) { return p; }
0133       }
0134       return 0;
0135     }
0136     value_type p = value_type( m_cont.object( traits::hash( k ) ) );
0137     return traits::checkKey( p, k ) ? p : 0;
0138   }
0139 #else
0140   FORCE_INLINE value_type i_object( const key_type& k ) const {
0141     return 0 == m_cont.isDirect() ? value_type( *( m_random->begin() + traits::hash( k ) ) )
0142                                   : value_type( m_cont.object( traits::hash( k ) ) );
0143   }
0144 #endif
0145   /// Internal function to erase an object from the container
0146   long i_erase( const_reference v, const key_type& k ) {
0147     value_type p = value_type( m_cont.erase( traits::hash( k ), v ) );
0148     if ( p ) {
0149       if ( p->parent() == this ) { p->setParent( 0 ); }
0150     }
0151     return traits::release( p ) <= 0 ? (long)Containers::OBJ_ERASED : (long)Containers::OBJ_DELETED;
0152   }
0153 
0154   /// Internal functor for insertion of objects
0155   struct _InsertRelease {
0156     KeyedContainer<DATATYPE, MAPPING>* m_obj;
0157     _InsertRelease( KeyedContainer<DATATYPE, MAPPING>* p ) : m_obj( p ) {}
0158     void operator()( value_type p ) {
0159       m_obj->insert( p );
0160       traits::release( p );
0161     }
0162   };
0163 
0164   /// Internal functor for insertion of objects
0165   struct _RemoveRelease {
0166     ObjectContainerBase* m_obj;
0167     _RemoveRelease( ObjectContainerBase* p ) : m_obj( p ) {}
0168     void operator()( value_type p ) {
0169       const ObjectContainerBase* par = p->parent();
0170       if ( par == m_obj ) { p->setParent( 0 ); }
0171       traits::release( p );
0172     }
0173   };
0174   //@}
0175 
0176 public:
0177   /**@name Constructors/Destructors
0178    */
0179   //@{
0180   /// Standard Constructor
0181   KeyedContainer( void ) {
0182     // avoid problems with strict-aliasing rules
0183     seq_type** rptr = &m_random;
0184     seq_type*  sptr = &m_sequential;
0185     m_cont.setup( (void*)sptr, (void**)rptr );
0186   }
0187   KeyedContainer( KeyedContainer&& other )
0188       : ObjectContainerBase( std::move( other ) )
0189       , m_cont( std::move( other.m_cont ) )
0190       , m_sequential( std::move( other.m_sequential ) ) {
0191     m_cont.setup( (void*)&m_sequential, (void**)&m_random );
0192     std::for_each( begin(), end(), [this]( ContainedObject* obj ) { obj->setParent( this ); } );
0193 
0194     other.m_cont.setup( (void*)&other.m_sequential, (void**)&other.m_random );
0195   }
0196   KeyedContainer( const KeyedContainer& ) = delete;
0197   /// Destructor
0198   ~KeyedContainer() override;
0199   //@}
0200 
0201   /**@name DataObject virtual function overloads.
0202    *  The implementation of these methods is required by the DataObject
0203    *  base class and determines the persistent run-time-type information.
0204    */
0205   //@{
0206   /// Retrieve class ID
0207   const CLID& clID() const override { return this->classID(); }
0208   /// Retrieve class ID
0209   static const CLID& classID() {
0210     static CLID clid = contained_type::classID() + container_type::classID();
0211     return clid;
0212   }
0213   //@}
0214 
0215   /**@name NOT FOR GENERAL USE ObjectContainerBase function overloads.
0216    *
0217    *  The implementation of these methods ensure the behaviour
0218    *  of the class as a type of class ObjectContainerBase. This
0219    *  base class and its behaviour are only used by "generic"
0220    *  object handlers. These classes collaborate with several
0221    *  classes such as the
0222    *
0223    *    - SmartRef classes.
0224    *    - Generic converters.
0225    *    - Interfaces for interactivity (e.g. Python)
0226    *
0227    *  For this reason, the entry points in this section are reserved
0228    *  for "generic" object handling and should NOT be used in public.
0229    */
0230   //@{
0231   /// ObjectContainerBase overload: Number of objects in the container
0232   size_type numberOfObjects() const override { return m_sequential.size(); }
0233   /** ObjectContainerBase overload: Add an object to the container.
0234    *  Plese see the documentation of the member function
0235    *
0236    *  const key_type& insert(DATATYPE* pObject)
0237    *
0238    *  for further details.
0239    *
0240    *  @param   pObject   Pointer to the object to be inserted into the
0241    *                     container.
0242    *  @return            long integer representation of the key value.
0243    */
0244   long add( ContainedObject* pObject ) override;
0245 
0246   /** ObjectContainerBase overload: Remove an object from the container.
0247    *  Because this function is also called from the destructor of
0248    *  The ContainedObject class, it is no longer possible to deduce
0249    *  the key from the object itself. It is hence necessary to relay
0250    *  on the **NON-EXISTENCE** of virtual inheritance, ie.
0251    *  (void*)pObject = (void*)(contained_object).
0252    *  If the virtual object table is still intact, the normal erase
0253    *  is called.
0254    *
0255    *  @param   pObject   Pointer to the object to be removed from the
0256    *                     container.
0257    */
0258   long remove( ContainedObject* pObject ) override;
0259 
0260   /** ObjectContainerBase overload: Retrieve the object by reference
0261    *  given the long integer representation of the object's key.
0262    */
0263   ContainedObject*       containedObject( long key_value ) override { return i_object( traits::makeKey( key_value ) ); }
0264   ContainedObject const* containedObject( long key_value ) const override {
0265     return i_object( traits::makeKey( key_value ) );
0266   }
0267   /** ObjectContainerBase overload: Retrieve the full long integer
0268    *  representation of the object's key from the object base class pointer.
0269    */
0270   long index( const ContainedObject* p ) const override;
0271   /** Retrieve the full content of the object container.
0272    *  @param   v          Vector of contained objects, which will host
0273    *                      all objects contained in this container.
0274    *  @return             Number of objects returned in v.
0275    */
0276   virtual size_type containedObjects( std::vector<ContainedObject*>& v ) const;
0277   //@}
0278 
0279   /**@name Container related implementation.
0280    *  These methods allow to manipulate the container as a whole and to
0281    *  retrieve information about the internal behaviour of the container.
0282    */
0283   //@{
0284   /// Number of objects in the container
0285   size_type size() const { return m_sequential.size(); }
0286   /// For consistency with STL: check if container is empty
0287   bool empty() const { return m_sequential.empty(); }
0288   /// Reserve place for "value" objects in the container.
0289   void reserve( size_type value ) { m_cont.reserve( value ); }
0290   /// Clear the entire content and erase the objects from the container
0291   void clear() { erase( begin(), end() ); }
0292   /** Retrieve the full content of the object container by reference.
0293    *  Returned is the random access container if in sequntial direct
0294    *  access mode. Otherwise the sequential access container is returned
0295    *  @return             Reference to sequencal access container.
0296    */
0297   virtual const std::vector<const ContainedObject*>* containedObjects() const;
0298   /** Reconfigure direct access to elements (Needed by POOL data loading)
0299    *  This function reuses the "update" callback of the generic DataObject
0300    *  base class.
0301    */
0302   StatusCode update() override;
0303   //@}
0304 
0305   /**@name Sequential array access to objects using iterators.
0306    *
0307    *  Sequential object access using iterators is much faster then object
0308    *  access by key. In case all objects of the container should be
0309    *  addressed, use iterators rather than direct object access.
0310    *
0311    * - If the container is accessed through the iterators defined below,
0312    *   the elements may be sorted according to the user needs.
0313    * - The container can be accesses in both const and non-const mode.
0314    * - Iterations are supported in both directions: From the beginning to
0315    *   the end and the reverse.
0316    */
0317   //@{
0318   /// Retrieve start iterator
0319   iterator begin() { return m_sequential.begin(); }
0320   /// Retrieve start const iterator
0321   const_iterator begin() const { return m_sequential.begin(); }
0322   /// Retrieve terminating iterator
0323   iterator end() { return m_sequential.end(); }
0324   /// Retrieve terminating const iterator
0325   const_iterator end() const { return m_sequential.end(); }
0326   /// reverse_iterator returns the beginning of the reversed container
0327   reverse_iterator rbegin() { return m_sequential.rbegin(); }
0328   /// const reverse_iterator returns the beginning of the reversed container
0329   const_reverse_iterator rbegin() const { return m_sequential.rbegin(); }
0330   /// reverse_iterator pointing to the end of the reversed container
0331   reverse_iterator rend() { return m_sequential.rend(); }
0332   /// const reverse_iterator pointing to the end of the reversed container
0333   const_reverse_iterator rend() const { return m_sequential.rend(); }
0334   //@}
0335 
0336   /**@name Random access to objects in the container.
0337    *       Access to objects is given by Key.
0338    *       Please note, that random object access is nearly in all cases
0339    *       significantly slower than sequential access. If all objects
0340    *       in the contaienr should be addresses sequentially, use iterators
0341    *       rather than direct access. Direct access should only be used
0342    *       for selective retrieval of objects.
0343    */
0344   //@{
0345   /** Object access by key.
0346    *  Access contained objects by key.
0347    *
0348    *  @param kval Key of the object to be returned.
0349    *  @return     Valid reference to the requested object. If the key of the
0350    *              requested object cannot be found in the container a null
0351    *              reference is returned.
0352    */
0353   value_type object( const key_type& kval ) const { return i_object( kval ); }
0354 
0355   /** STL algorithms support for object access.
0356    *  Access contained objects by key using the operator(), which is demanded
0357    *  by STL algorithms.
0358    *
0359    *  @param kval Key of the object to be returned.
0360    *  @return     Valid reference to the requested object. If the key of the
0361    *              requested object cannot be found in the container a null
0362    *              reference is returned.
0363    */
0364   value_type operator()( const key_type& kval ) const { return i_object( kval ); }
0365   //@}
0366 
0367   /**@name Insert/Remove objects from the container.
0368    *  Objects generally are identified by key. Since keys are stored with
0369    *  the objects, insertions and removals are possible by key or by
0370    *  reference.
0371    */
0372   //@{
0373   /** Remove/erase object (identified by key) from the container.
0374    *
0375    *  @param   kval   Key to identify the object within the container.
0376    *  @return         Enumeration value from the Containers namespace:
0377    *                  - OBJ_NOT_FOUND: The indicated object was not found
0378    *                                   in the container
0379    *                  - OBJ_ERASED:    The indicated object was found
0380    *                                   and removed from the container.
0381    *                                   The object was not yet deleted,
0382    *                                   because its reference count was
0383    *                                   non zero.
0384    *                  - OBJ_DELETED    The indicated object was found
0385    *                                   and removed from the container.
0386    *                                   The object was deleted, because
0387    *                                   its reference count was zero.
0388    */
0389   long erase( const key_type& kval ) { return i_erase( 0, kval ); }
0390 
0391   /** Remove/erase object (identified by pointer value) from the container.
0392    *  This member function removes an object, which is identified by its
0393    *  reference from the container. No key value is supplied. To identify
0394    *  the object within the container, the key of the object is used as
0395    *  it can be retrieved using the KeyedObject::key() method.
0396    *
0397    *  @param    val   Reference to object to be removed from the container.
0398    *  @return         Enumeration value from the Containers namespace:
0399    *                  - OBJ_NOT_FOUND: The indicated object was not found
0400    *                                   in the container
0401    *                  - OBJ_ERASED:    The indicated object was found
0402    *                                   and removed from the container.
0403    *                                   The object was not yet deleted,
0404    *                                   because its reference count was
0405    *                                   non zero.
0406    *                  - OBJ_DELETED    The indicated object was found
0407    *                                   and removed from the container.
0408    *                                   The object was deleted, because
0409    *                                   its reference count was zero.
0410    */
0411   long erase( const value_type val ) { return ( val ) ? i_erase( val, val->key() ) : (long)Containers::OBJ_NOT_FOUND; }
0412 
0413   /** Remove/erase object (identified by iterator) from the container.
0414    *  This member function removes an object, which is identified by its
0415    *  reference from the container. No key value is supplied. To identify
0416    *  the object within the container, the key of the object is used as
0417    *  it can be retrieved using the KeyedObject::key() method.
0418    *
0419    *  @param    val   Reference to object to be removed from the container.
0420    *  @return         Enumeration value from the Containers namespace:
0421    *                  - OBJ_NOT_FOUND: The indicated object was not found
0422    *                                   in the container
0423    *                  - OBJ_ERASED:    The indicated object was found
0424    *                                   and removed from the container.
0425    *                                   The object was not yet deleted,
0426    *                                   because its reference count was
0427    *                                   non zero.
0428    *                  - OBJ_DELETED    The indicated object was found
0429    *                                   and removed from the container.
0430    *                                   The object was deleted, because
0431    *                                   its reference count was zero.
0432    */
0433   long erase( iterator pos ) { return erase( *pos ); }
0434 
0435   /** Remove/erase objects by iterator range.
0436    *  This member function removes all objects, which are within
0437    *  the sequential iterator range [pos_start, pos_stop[.
0438    *
0439    *  @param    pos_start   Starting iterator of the range to be removed.
0440    *  @param    pos_stop    Starting iterator of the range to be removed.
0441    *  @param    use_temp    Flag to indicate that a temporary arry should be used.
0442    */
0443   void erase( iterator pos_start, iterator pos_stop, bool use_temp = false );
0444 
0445   /** Insert entry to the container with a valid key.
0446    *  This member function inserts an element, which is identified by its
0447    *  reference to the container. The element will be inserted using the
0448    *  specified key. If the object is already keyed, the long
0449    *  representations of the supplied key and the object's key must agree.
0450    *
0451    *  The object will not be inserted and an exception will be raised
0452    *  under the following conditions:
0453    *    - The supplied key does not agree with the object's key.
0454    *    - An object with the supplied key is already present in the container.
0455    *
0456    *  @param    val   Reference to object to be inserted into the container.
0457    *                  The object reference may NOT be NULL.
0458    *  @param   kval   Key to identify the object within the container.
0459    *  @return         Key, which was used to index the object within the
0460    *                  container. If the operation is not
0461    *                  successful, an exception is thrown.
0462    */
0463   const key_type& insert( const value_type val, const key_type& kval );
0464 
0465   /** Insert entry to the container with automatic key assignment.
0466    *  This member function inserts an element, which is identified by its
0467    *  reference to the container. No key value is supplied. The key
0468    *  used to insert the object is retrieved from the element itself.
0469    *  In the event the object already has a key, the assigned key of
0470    *  the object is used. If no key was assigned to the object,
0471    *  (i.e. the object's key is equal to the invalid key),
0472    *  a key is generated according to the number of objects present in
0473    *  the container.
0474    *
0475    *  The object will not be inserted and an exception will be raised
0476    *  under the following conditions:
0477    *    - A key was already assigned to the object, but
0478    *      another object with the same key is already present
0479    *      in the container.
0480    *
0481    *  @param    val   Reference to object to be inserted into the container.
0482    *  @return         Key, which was used to index the object within the
0483    *                  container. If the operation is not
0484    *                  successful, an exception is thrown.
0485    */
0486   const key_type& insert( const value_type val );
0487   //@}
0488 };
0489 
0490 /**
0491  *
0492  *
0493  *  Inline code for keyed container class
0494  *
0495  */
0496 
0497 // Destructor
0498 template <class DATATYPE, class MAPPING>
0499 inline KeyedContainer<DATATYPE, MAPPING>::~KeyedContainer() {
0500   clear();
0501   m_cont.clear();
0502 }
0503 
0504 // Configure direct access
0505 template <class DATATYPE, class MAPPING>
0506 inline StatusCode KeyedContainer<DATATYPE, MAPPING>::update() {
0507   int count = 0;
0508   m_cont.clearDirect();
0509   for ( typename seq_type::value_type v : m_sequential ) {
0510     if ( v ) {
0511       if ( !v->hasKey() ) {
0512         traits::setKey( v, v->key() );
0513         traits::addRef( v );
0514       }
0515       long k0 = traits::hash( v->key() );
0516       if ( m_cont.insertDirect( this, v, v, k0 ) == Containers::OBJ_INSERTED ) {}
0517     } else {
0518       ++count;
0519     }
0520   }
0521   if ( count > 0 ) { Containers::cannotInsertToContainer(); }
0522   return StatusCode::SUCCESS;
0523 }
0524 
0525 // Retrieve the full content of the object container by reference.
0526 template <class DATATYPE, class MAPPING>
0527 inline const std::vector<const ContainedObject*>* KeyedContainer<DATATYPE, MAPPING>::containedObjects() const {
0528   return (const std::vector<const ContainedObject*>*)( ( 0 == m_cont.isDirect() ) ? m_random : &m_sequential );
0529 }
0530 
0531 template <class DATATYPE, class MAPPING>
0532 inline const typename KeyedContainer<DATATYPE, MAPPING>::key_type&
0533 KeyedContainer<DATATYPE, MAPPING>::insert( const value_type val, const key_type& kval ) {
0534   if ( val ) {
0535     long k0 = traits::hash( kval );
0536     if ( !val->hasKey() || ( traits::hash( val->key() ) == k0 ) ) {
0537       if ( m_cont.insert( this, val, val, k0 ) == Containers::OBJ_INSERTED ) {
0538         if ( !val->hasKey() ) traits::setKey( val, kval );
0539         traits::addRef( val );
0540         return val->key();
0541       }
0542     }
0543   }
0544   // Cannot insert object...indicate bad object insertion...
0545   Containers::cannotInsertToContainer();
0546   return val->key();
0547 }
0548 
0549 // Insert object
0550 template <class DATATYPE, class MAPPING> // inline
0551 const typename KeyedContainer<DATATYPE, MAPPING>::key_type&
0552 KeyedContainer<DATATYPE, MAPPING>::insert( const value_type val ) {
0553   if ( 0 != val ) {
0554     if ( val->hasKey() ) {
0555       if ( m_cont.insert( this, val, val, traits::hash( val->key() ) ) == Containers::OBJ_INSERTED ) {
0556         traits::addRef( val );
0557         return val->key();
0558       }
0559     }
0560     long k0;
0561     if ( m_cont.insert( this, val, val, &k0 ) == Containers::OBJ_INSERTED ) {
0562       traits::setKey( val, traits::makeKey( k0 ) );
0563       traits::addRef( val );
0564       return val->key();
0565     }
0566   }
0567   // Cannot insert object...indicate bad object insertion...
0568   Containers::cannotInsertToContainer();
0569   return val->key();
0570 }
0571 
0572 template <class DATATYPE, class MAPPING>
0573 inline long KeyedContainer<DATATYPE, MAPPING>::index( const ContainedObject* p ) const {
0574   const contained_type* ptr = dynamic_cast<const contained_type*>( p );
0575   if ( ptr ) return traits::identifier( ptr->key() );
0576   return -1;
0577 }
0578 
0579 // Retrieve the full content of the object container.
0580 template <class DATATYPE, class MAPPING>
0581 inline typename KeyedContainer<DATATYPE, MAPPING>::size_type
0582 KeyedContainer<DATATYPE, MAPPING>::containedObjects( std::vector<ContainedObject*>& vec ) const {
0583   vec.clear();
0584   vec.reserve( size() );
0585   for ( typename seq_type::value_type v : m_sequential ) {
0586     ContainedObject* p = const_cast<typename seq_type::value_type>( v );
0587     vec.push_back( p );
0588   }
0589   return vec.size();
0590 }
0591 
0592 // ObjectContainerBase overload: Add an object to the container.
0593 template <class DATATYPE, class MAPPING>
0594 inline long KeyedContainer<DATATYPE, MAPPING>::add( ContainedObject* pObject ) {
0595   return traits::identifier( insert( dynamic_cast<typename seq_type::value_type>( pObject ) ) );
0596 }
0597 
0598 // ObjectContainerBase overload: Remove an object from the container.
0599 template <class DATATYPE, class MAPPING>
0600 inline long KeyedContainer<DATATYPE, MAPPING>::remove( ContainedObject* p ) {
0601   contained_type* p1 = dynamic_cast<contained_type*>( p );
0602   if ( p1 ) { // Normal case; object still fully intact
0603     return this->erase( p1 );
0604   } else if ( p ) {
0605     const ObjectContainerBase* par = p->parent();
0606     // The following should never occur: object is in a funny state,
0607     // Because the parent was explicitly set to NULL in the
0608     // KeyeObject destructor.
0609     // - It cannot be a KeyedObject:  It would not have a parent
0610     // - Still the parent is present: We are not in the destructor
0611     //                                of KeyedObject
0612     if ( par ) { Containers::invalidContainerOperation(); }
0613     return m_cont.erase( 0, p ) == 0 ? (long)Containers::OBJ_ERASED : (long)Containers::OBJ_NOT_FOUND;
0614   }
0615   return (long)Containers::OBJ_NOT_FOUND;
0616 }
0617 
0618 template <class DATATYPE, class MAPPING>
0619 inline void KeyedContainer<DATATYPE, MAPPING>::erase( iterator start_pos, iterator stop_pos, bool use_tmp ) {
0620   bool is_start = start_pos == m_sequential.begin();
0621   bool is_stop  = stop_pos == m_sequential.end();
0622   if ( is_start && is_stop ) {
0623     // Nothing special. Taken care of by Keyed object manager
0624   } else if ( is_start || is_stop || use_tmp ) {
0625     std::vector<DATATYPE*> tmp( m_sequential.begin(), start_pos );
0626     tmp.insert( tmp.end(), stop_pos, m_sequential.end() );
0627     std::for_each( tmp.begin(), tmp.end(), traits::addRef );
0628     this->erase( m_sequential.begin(), m_sequential.end() );
0629     std::for_each( tmp.begin(), tmp.end(), _InsertRelease( this ) );
0630     return;
0631   }
0632   std::for_each( start_pos, stop_pos, _RemoveRelease( this ) );
0633   seq_type*                    sptr = &m_sequential; // avoid problems with strict-aliasing rules
0634   std::vector<void*>*          v    = (std::vector<void*>*)sptr;
0635   std::vector<void*>::iterator i1   = v->begin() + std::distance( m_sequential.begin(), start_pos );
0636   std::vector<void*>::iterator i2   = v->begin() + std::distance( m_sequential.begin(), stop_pos );
0637   m_cont.erase( i1, i2 ); // cppcheck-suppress iterators1
0638 }
0639 
0640 #undef FORCE_INLINE
0641 #endif // GAUDIKERNEL_KEYEDCONTAINER_H