Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:00:33

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2019 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   typename seq_type::iterator i = m_sequential.begin();
0510   typename seq_type::iterator s = m_sequential.end();
0511   for ( ; i != s; i++ ) {
0512     typename seq_type::value_type v = *i;
0513     if ( v ) {
0514       if ( !v->hasKey() ) {
0515         traits::setKey( v, v->key() );
0516         traits::addRef( v );
0517       }
0518       long k0 = traits::hash( v->key() );
0519       if ( m_cont.insertDirect( this, v, v, k0 ) == Containers::OBJ_INSERTED ) {}
0520     } else {
0521       ++count;
0522     }
0523   }
0524   if ( count > 0 ) { Containers::cannotInsertToContainer(); }
0525   return StatusCode::SUCCESS;
0526 }
0527 
0528 // Retrieve the full content of the object container by reference.
0529 template <class DATATYPE, class MAPPING>
0530 inline const std::vector<const ContainedObject*>* KeyedContainer<DATATYPE, MAPPING>::containedObjects() const {
0531   return (const std::vector<const ContainedObject*>*)( ( 0 == m_cont.isDirect() ) ? m_random : &m_sequential );
0532 }
0533 
0534 template <class DATATYPE, class MAPPING>
0535 inline const typename KeyedContainer<DATATYPE, MAPPING>::key_type&
0536 KeyedContainer<DATATYPE, MAPPING>::insert( const value_type val, const key_type& kval ) {
0537   if ( val ) {
0538     long k0 = traits::hash( kval );
0539     if ( !val->hasKey() || ( traits::hash( val->key() ) == k0 ) ) {
0540       if ( m_cont.insert( this, val, val, k0 ) == Containers::OBJ_INSERTED ) {
0541         if ( !val->hasKey() ) traits::setKey( val, kval );
0542         traits::addRef( val );
0543         return val->key();
0544       }
0545     }
0546   }
0547   // Cannot insert object...indicate bad object insertion...
0548   Containers::cannotInsertToContainer();
0549   return val->key();
0550 }
0551 
0552 // Insert object
0553 template <class DATATYPE, class MAPPING> // inline
0554 const typename KeyedContainer<DATATYPE, MAPPING>::key_type&
0555 KeyedContainer<DATATYPE, MAPPING>::insert( const value_type val ) {
0556   if ( 0 != val ) {
0557     if ( val->hasKey() ) {
0558       if ( m_cont.insert( this, val, val, traits::hash( val->key() ) ) == Containers::OBJ_INSERTED ) {
0559         traits::addRef( val );
0560         return val->key();
0561       }
0562     }
0563     long k0;
0564     if ( m_cont.insert( this, val, val, &k0 ) == Containers::OBJ_INSERTED ) {
0565       traits::setKey( val, traits::makeKey( k0 ) );
0566       traits::addRef( val );
0567       return val->key();
0568     }
0569   }
0570   // Cannot insert object...indicate bad object insertion...
0571   Containers::cannotInsertToContainer();
0572   return val->key();
0573 }
0574 
0575 template <class DATATYPE, class MAPPING>
0576 inline long KeyedContainer<DATATYPE, MAPPING>::index( const ContainedObject* p ) const {
0577   const contained_type* ptr = dynamic_cast<const contained_type*>( p );
0578   if ( ptr ) return traits::identifier( ptr->key() );
0579   return -1;
0580 }
0581 
0582 // Retrieve the full content of the object container.
0583 template <class DATATYPE, class MAPPING>
0584 inline typename KeyedContainer<DATATYPE, MAPPING>::size_type
0585 KeyedContainer<DATATYPE, MAPPING>::containedObjects( std::vector<ContainedObject*>& vec ) const {
0586   typename seq_type::const_iterator i = m_sequential.begin();
0587   typename seq_type::const_iterator s = m_sequential.end();
0588   vec.clear();
0589   vec.reserve( size() );
0590   for ( ; i != s; i++ ) {
0591     ContainedObject* p = const_cast<typename seq_type::value_type>( *i );
0592     vec.push_back( p );
0593   }
0594   return vec.size();
0595 }
0596 
0597 // ObjectContainerBase overload: Add an object to the container.
0598 template <class DATATYPE, class MAPPING>
0599 inline long KeyedContainer<DATATYPE, MAPPING>::add( ContainedObject* pObject ) {
0600   return traits::identifier( insert( dynamic_cast<typename seq_type::value_type>( pObject ) ) );
0601 }
0602 
0603 // ObjectContainerBase overload: Remove an object from the container.
0604 template <class DATATYPE, class MAPPING>
0605 inline long KeyedContainer<DATATYPE, MAPPING>::remove( ContainedObject* p ) {
0606   contained_type* p1 = dynamic_cast<contained_type*>( p );
0607   if ( p1 ) { // Normal case; object still fully intact
0608     return this->erase( p1 );
0609   } else if ( p ) {
0610     const ObjectContainerBase* par = p->parent();
0611     // The following should never occur: object is in a funny state,
0612     // Because the parent was explicitly set to NULL in the
0613     // KeyeObject destructor.
0614     // - It cannot be a KeyedObject:  It would not have a parent
0615     // - Still the parent is present: We are not in the destructor
0616     //                                of KeyedObject
0617     if ( par ) { Containers::invalidContainerOperation(); }
0618     return m_cont.erase( 0, p ) == 0 ? (long)Containers::OBJ_ERASED : (long)Containers::OBJ_NOT_FOUND;
0619   }
0620   return (long)Containers::OBJ_NOT_FOUND;
0621 }
0622 
0623 template <class DATATYPE, class MAPPING>
0624 inline void KeyedContainer<DATATYPE, MAPPING>::erase( iterator start_pos, iterator stop_pos, bool use_tmp ) {
0625   bool is_start = start_pos == m_sequential.begin();
0626   bool is_stop  = stop_pos == m_sequential.end();
0627   if ( is_start && is_stop ) {
0628     // Nothing special. Taken care of by Keyed object manager
0629   } else if ( is_start || is_stop || use_tmp ) {
0630     std::vector<DATATYPE*> tmp( m_sequential.begin(), start_pos );
0631     tmp.insert( tmp.end(), stop_pos, m_sequential.end() );
0632     std::for_each( tmp.begin(), tmp.end(), traits::addRef );
0633     this->erase( m_sequential.begin(), m_sequential.end() );
0634     std::for_each( tmp.begin(), tmp.end(), _InsertRelease( this ) );
0635     return;
0636   }
0637   std::for_each( start_pos, stop_pos, _RemoveRelease( this ) );
0638   seq_type*                    sptr = &m_sequential; // avoid problems with strict-aliasing rules
0639   std::vector<void*>*          v    = (std::vector<void*>*)sptr;
0640   std::vector<void*>::iterator i1   = v->begin() + std::distance( m_sequential.begin(), start_pos );
0641   std::vector<void*>::iterator i2   = v->begin() + std::distance( m_sequential.begin(), stop_pos );
0642   m_cont.erase( i1, i2 );
0643 }
0644 
0645 #undef FORCE_INLINE
0646 #endif // GAUDIKERNEL_KEYEDCONTAINER_H