| The Gaudi Framework v32r1 (f65d50dc)

KeyedContainer.h
Go to the documentation of this file.
1 #ifndef GAUDIKERNEL_KEYEDCONTAINER_H
2 #define GAUDIKERNEL_KEYEDCONTAINER_H
3
4 // Include files
5 #include <algorithm>
6 #include <iterator>
7
8 namespace GaudiDict {
9 template <class T>
10 struct KeyedContainerDict;
11 }
12
13 // Framework include files
14 #include "GaudiKernel/KeyedObject.h"
15 #include "GaudiKernel/KeyedObjectManager.h"
16 #include "GaudiKernel/ObjectContainerBase.h"
17
18 // Forward declarations
19 // template <class T, class M> class KeyedContainer;
20
21 #ifdef WIN32
22 # define FORCE_INLINE __forceinline
23 #else
24 # define FORCE_INLINE inline
25 #endif
26
63 template <class DATATYPE, class MAPPING = Containers::HashMap>
64 class GAUDI_API KeyedContainer : public ObjectContainerBase {
65 friend struct GaudiDict::KeyedContainerDict<DATATYPE>;
66
67 public:
69 typedef DATATYPE contained_type;
71 typedef MAPPING container_type;
72
79 typedef typename std::vector<contained_type*> seq_type;
82 typedef typename contained_type::key_type key_type;
84 typedef typename seq_type::value_type value_type;
86 typedef typename seq_type::reference reference;
88 typedef typename seq_type::const_reference const_reference;
90 typedef typename seq_type::iterator iterator;
92 typedef typename seq_type::const_iterator const_iterator;
94 typedef typename seq_type::reverse_iterator reverse_iterator;
98 typedef typename seq_type::const_reverse_iterator const_reverse_iterator;
100 private:
104 typedef typename Containers::traits<container_type, contained_type> traits;
105
109 container_type m_cont;
112 seq_type m_sequential;
114 seq_type* m_random;
115
117 #ifdef CHECK_KEYED_CONTAINER
118 value_type i_object( const key_type& k ) const {
119 if ( 0 == m_cont.isDirect() ) {
120 if ( traits::checkBounds( m_random, k ) ) {
121 value_type p = *( m_random->begin() + traits::hash( k ) );
122 if ( traits::checkKey( p, k ) ) { return p; }
123 }
124 return 0;
125 }
126 value_type p = value_type( m_cont.object( traits::hash( k ) ) );
127 return traits::checkKey( p, k ) ? p : 0;
128 }
129 #else
130 FORCE_INLINE value_type i_object( const key_type& k ) const {
131 return 0 == m_cont.isDirect() ? value_type( *( m_random->begin() + traits::hash( k ) ) )
132 : value_type( m_cont.object( traits::hash( k ) ) );
133 }
134 #endif
135 long i_erase( const_reference v, const key_type& k ) {
137 value_type p = value_type( m_cont.erase( traits::hash( k ), v ) );
138 if ( p ) {
139 if ( p->parent() == this ) { p->setParent( 0 ); }
140 }
141 return traits::release( p ) <= 0 ? (long)Containers::OBJ_ERASED : (long)Containers::OBJ_DELETED;
142 }
143
145 struct _InsertRelease {
146 KeyedContainer<DATATYPE, MAPPING>* m_obj;
147 _InsertRelease( KeyedContainer<DATATYPE, MAPPING>* p ) : m_obj( p ) {}
148 void operator()( value_type p ) {
149 m_obj->insert( p );
150 traits::release( p );
151 }
152 };
153
155 struct _RemoveRelease {
156 ObjectContainerBase* m_obj;
157 _RemoveRelease( ObjectContainerBase* p ) : m_obj( p ) {}
158 void operator()( value_type p ) {
159 const ObjectContainerBase* par = p->parent();
160 if ( par == m_obj ) { p->setParent( 0 ); }
161 traits::release( p );
162 }
163 };
165
166 public:
170 KeyedContainer( void ) {
172 // avoid problems with strict-aliasing rules
173 seq_type** rptr = &m_random;
174 seq_type* sptr = &m_sequential;
175 m_cont.setup( (void*)sptr, (void**)rptr );
176 }
177 KeyedContainer( KeyedContainer&& other )
178 : ObjectContainerBase( std::move( other ) )
179 , m_cont( std::move( other.m_cont ) )
180 , m_sequential( std::move( other.m_sequential ) ) {
181 m_cont.setup( (void*)&m_sequential, (void**)&m_random );
182 std::for_each( begin(), end(), [this]( ContainedObject* obj ) { obj->setParent( this ); } );
183
184 other.m_cont.setup( (void*)&other.m_sequential, (void**)&other.m_random );
185 }
186 KeyedContainer( const KeyedContainer& ) = delete;
188 ~KeyedContainer() override;
190
196 const CLID& clID() const override { return this->classID(); }
199 static const CLID& classID() {
200 static CLID clid = contained_type::classID() + container_type::classID();
201 return clid;
202 }
204
221 size_type numberOfObjects() const override { return m_sequential.size(); }
234 long add( ContainedObject* pObject ) override;
235
248 long remove( ContainedObject* pObject ) override;
249
253 ContainedObject* containedObject( long key_value ) override { return i_object( traits::makeKey( key_value ) ); }
254 ContainedObject const* containedObject( long key_value ) const override {
255 return i_object( traits::makeKey( key_value ) );
256 }
260 long index( const ContainedObject* p ) const override;
266 virtual size_type containedObjects( std::vector<ContainedObject*>& v ) const;
268
274 size_type size() const { return m_sequential.size(); }
277 bool empty() const { return m_sequential.empty(); }
279 void reserve( size_type value ) { m_cont.reserve( value ); }
281 void clear() { erase( begin(), end() ); }
287 virtual const std::vector<const ContainedObject*>* containedObjects() const;
292 StatusCode update() override;
294
308 iterator begin() { return m_sequential.begin(); }
311 const_iterator begin() const { return m_sequential.begin(); }
313 iterator end() { return m_sequential.end(); }
315 const_iterator end() const { return m_sequential.end(); }
317 reverse_iterator rbegin() { return m_sequential.rbegin(); }
319 const_reverse_iterator rbegin() const { return m_sequential.rbegin(); }
321 reverse_iterator rend() { return m_sequential.rend(); }
323 const_reverse_iterator rend() const { return m_sequential.rend(); }
325
343 value_type object( const key_type& kval ) const { return i_object( kval ); }
344
354 value_type operator()( const key_type& kval ) const { return i_object( kval ); }
356
379 long erase( const key_type& kval ) { return i_erase( 0, kval ); }
380
401 long erase( const value_type val ) { return ( val ) ? i_erase( val, val->key() ) : (long)Containers::OBJ_NOT_FOUND; }
402
423 long erase( iterator pos ) { return erase( *pos ); }
424
433 void erase( iterator pos_start, iterator pos_stop, bool use_temp = false );
434
453 const key_type& insert( const value_type val, const key_type& kval );
454
476 const key_type& insert( const value_type val );
478 };
479
487 // Destructor
488 template <class DATATYPE, class MAPPING>
489 inline KeyedContainer<DATATYPE, MAPPING>::~KeyedContainer() {
490 clear();
491 m_cont.clear();
492 }
493
494 // Configure direct access
495 template <class DATATYPE, class MAPPING>
496 inline StatusCode KeyedContainer<DATATYPE, MAPPING>::update() {
497 int count = 0;
498 m_cont.clearDirect();
499 typename seq_type::iterator i = m_sequential.begin();
500 typename seq_type::iterator s = m_sequential.end();
501 for ( ; i != s; i++ ) {
502 typename seq_type::value_type v = *i;
503 if ( v ) {
504 if ( !v->hasKey() ) {
505 traits::setKey( v, v->key() );
506 traits::addRef( v );
507 }
508 long k0 = traits::hash( v->key() );
509 if ( m_cont.insertDirect( this, v, v, k0 ) == Containers::OBJ_INSERTED ) {}
510 } else {
511 ++count;
512 }
513 }
514 if ( count > 0 ) { Containers::cannotInsertToContainer(); }
515 return StatusCode::SUCCESS;
516 }
517
518 // Retrieve the full content of the object container by reference.
519 template <class DATATYPE, class MAPPING>
520 inline const std::vector<const ContainedObject*>* KeyedContainer<DATATYPE, MAPPING>::containedObjects() const {
521 return (const std::vector<const ContainedObject*>*)( ( 0 == m_cont.isDirect() ) ? m_random : &m_sequential );
522 }
523
524 template <class DATATYPE, class MAPPING>
525 inline const typename KeyedContainer<DATATYPE, MAPPING>::key_type&
526 KeyedContainer<DATATYPE, MAPPING>::insert( const value_type val, const key_type& kval ) {
527 if ( val ) {
528 long k0 = traits::hash( kval );
529 if ( !val->hasKey() || ( traits::hash( val->key() ) == k0 ) ) {
530 if ( m_cont.insert( this, val, val, k0 ) == Containers::OBJ_INSERTED ) {
531 if ( !val->hasKey() ) traits::setKey( val, kval );
532 traits::addRef( val );
533 return val->key();
534 }
535 }
536 }
537 // Cannot insert object...indicate bad object insertion...
538 Containers::cannotInsertToContainer();
539 return val->key();
540 }
541
542 // Insert object
543 template <class DATATYPE, class MAPPING> // inline
544 const typename KeyedContainer<DATATYPE, MAPPING>::key_type&
545 KeyedContainer<DATATYPE, MAPPING>::insert( const value_type val ) {
546 if ( 0 != val ) {
547 if ( val->hasKey() ) {
548 if ( m_cont.insert( this, val, val, traits::hash( val->key() ) ) == Containers::OBJ_INSERTED ) {
549 traits::addRef( val );
550 return val->key();
551 }
552 }
553 long k0;
554 if ( m_cont.insert( this, val, val, &k0 ) == Containers::OBJ_INSERTED ) {
555 traits::setKey( val, traits::makeKey( k0 ) );
556 traits::addRef( val );
557 return val->key();
558 }
559 }
560 // Cannot insert object...indicate bad object insertion...
561 Containers::cannotInsertToContainer();
562 return val->key();
563 }
564
565 template <class DATATYPE, class MAPPING>
566 inline long KeyedContainer<DATATYPE, MAPPING>::index( const ContainedObject* p ) const {
567 const contained_type* ptr = dynamic_cast<const contained_type*>( p );
568 if ( ptr ) return traits::identifier( ptr->key() );
569 return -1;
570 }
571
572 // Retrieve the full content of the object container.
573 template <class DATATYPE, class MAPPING>
574 inline typename KeyedContainer<DATATYPE, MAPPING>::size_type
575 KeyedContainer<DATATYPE, MAPPING>::containedObjects( std::vector<ContainedObject*>& vec ) const {
576 typename seq_type::const_iterator i = m_sequential.begin();
577 typename seq_type::const_iterator s = m_sequential.end();
578 vec.clear();
579 vec.reserve( size() );
580 for ( ; i != s; i++ ) {
581 ContainedObject* p = const_cast<typename seq_type::value_type>( *i );
582 vec.push_back( p );
583 }
584 return vec.size();
585 }
586
587 // ObjectContainerBase overload: Add an object to the container.
588 template <class DATATYPE, class MAPPING>
589 inline long KeyedContainer<DATATYPE, MAPPING>::add( ContainedObject* pObject ) {
590 return traits::identifier( insert( dynamic_cast<typename seq_type::value_type>( pObject ) ) );
591 }
592
593 // ObjectContainerBase overload: Remove an object from the container.
594 template <class DATATYPE, class MAPPING>
595 inline long KeyedContainer<DATATYPE, MAPPING>::remove( ContainedObject* p ) {
596 contained_type* p1 = dynamic_cast<contained_type*>( p );
597 if ( p1 ) { // Normal case; object still fully intact
598 return this->erase( p1 );
599 } else if ( p ) {
600 const ObjectContainerBase* par = p->parent();
601 // The following should never occur: object is in a funny state,
602 // Because the parent was explicitly set to NULL in the
603 // KeyeObject destructor.
604 // - It cannot be a KeyedObject: It would not have a parent
605 // - Still the parent is present: We are not in the destructor
606 // of KeyedObject
607 if ( par ) { Containers::invalidContainerOperation(); }
608 return m_cont.erase( 0, p ) == 0 ? (long)Containers::OBJ_ERASED : (long)Containers::OBJ_NOT_FOUND;
609 }
610 return (long)Containers::OBJ_NOT_FOUND;
611 }
612
613 template <class DATATYPE, class MAPPING>
614 inline void KeyedContainer<DATATYPE, MAPPING>::erase( iterator start_pos, iterator stop_pos, bool use_tmp ) {
615 bool is_start = start_pos == m_sequential.begin();
616 bool is_stop = stop_pos == m_sequential.end();
617 if ( is_start && is_stop ) {
618 // Nothing special. Taken care of by Keyed object manager
619 } else if ( is_start || is_stop || use_tmp ) {
620 std::vector<DATATYPE*> tmp( m_sequential.begin(), start_pos );
621 tmp.insert( tmp.end(), stop_pos, m_sequential.end() );
622 std::for_each( tmp.begin(), tmp.end(), traits::addRef );
623 this->erase( m_sequential.begin(), m_sequential.end() );
624 std::for_each( tmp.begin(), tmp.end(), _InsertRelease( this ) );
625 return;
626 }
627 std::for_each( start_pos, stop_pos, _RemoveRelease( this ) );
628 seq_type* sptr = &m_sequential; // avoid problems with strict-aliasing rules
629 std::vector<void*>* v = (std::vector<void*>*)sptr;
630 std::vector<void*>::iterator i1 = v->begin() + std::distance( m_sequential.begin(), start_pos );
631 std::vector<void*>::iterator i2 = v->begin() + std::distance( m_sequential.begin(), stop_pos );
632 m_cont.erase( i1, i2 );
633 }
634
635 #undef FORCE_INLINE
636 #endif // GAUDIKERNEL_KEYEDCONTAINER_H
GaudiDict::KeyedContainerDict
Definition: KeyedContainer.h:10
details::size
constexpr auto size(const T &, Args &&...) noexcept
Definition: AnyDataWrapper.h:14
KeyedContainer::_InsertRelease::operator()
void operator()(value_type p)
Definition: KeyedContainer.h:148
KeyedContainer::rbegin
reverse_iterator rbegin()
reverse_iterator returns the beginning of the reversed container
Definition: KeyedContainer.h:317
DataObject::update
virtual StatusCode update()
Provide empty placeholder for internal object reconfiguration callback.
Definition: DataObject.cpp:65
KeyedContainer::reverse_iterator
seq_type::reverse_iterator reverse_iterator
Sequential access: reverse iterator type used in sequential container.
Definition: KeyedContainer.h:94
std::vector::empty
T empty(T... args)
Containers::traits
Container traits class.
Definition: KeyedTraits.h:34
KeyedContainer::const_reference
seq_type::const_reference const_reference
Sequential access: const reference type used in sequential container.
Definition: KeyedContainer.h:88
KeyedContainer::reserve
void reserve(size_type value)
Reserve place for "value" objects in the container.
Definition: KeyedContainer.h:279
std::distance
T distance(T... args)
DataObject::classID
static const CLID & classID()
Retrieve reference to class definition structure (static access)
Definition: DataObject.cpp:59
KeyedContainer::rend
const_reverse_iterator rend() const
const reverse_iterator pointing to the end of the reversed container
Definition: KeyedContainer.h:323
KeyedContainer::erase
long erase(iterator pos)
Remove/erase object (identified by iterator) from the container.
Definition: KeyedContainer.h:423
KeyedContainer::add
long add(ContainedObject *pObject) override
ObjectContainerBase overload: Add an object to the container.
Definition: KeyedContainer.h:589
ObjectContainerBase::size_type
size_t size_type
size_type, to conform the STL container interface
Definition: ObjectContainerBase.h:29
KeyedContainer::containedObject
ContainedObject const * containedObject(long key_value) const override
Pointer to an object of a given distance.
Definition: KeyedContainer.h:254
std::vector::rend
T rend(T... args)
KeyedContainer::i_object
FORCE_INLINE value_type i_object(const key_type &k) const
Internal function to access objects within the container.
Definition: KeyedContainer.h:130
KeyedContainer::m_sequential
seq_type m_sequential
Array to allow sequential access to the object (can be ordered).
Definition: KeyedContainer.h:112
KeyedContainer::reference
seq_type::reference reference
Sequential access: reference type used in sequential container.
Definition: KeyedContainer.h:86
ObjectContainerBase::numberOfObjects
virtual size_type numberOfObjects() const =0
Number of objects in the container.
Gaudi::Functional::details::insert
constexpr struct Gaudi::Functional::details::insert_t insert
KeyedContainer::containedObject
ContainedObject * containedObject(long key_value) override
ObjectContainerBase overload: Retrieve the object by reference given the long integer representation ...
Definition: KeyedContainer.h:253
Containers::OBJ_NOT_FOUND
Object not present in the container.
Definition: KeyedTraits.h:23
KeyedContainer::_RemoveRelease::m_obj
ObjectContainerBase * m_obj
Definition: KeyedContainer.h:156
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:85
KeyedContainer
template class KeyedContainer, KeyedContainer.h
Definition: KeyedContainer.h:64
std
STL namespace.
ObjectContainerBase.h
KeyedContainer::erase
long erase(const key_type &kval)
Remove/erase object (identified by key) from the container.
Definition: KeyedContainer.h:379
KeyedContainer::remove
long remove(ContainedObject *pObject) override
ObjectContainerBase overload: Remove an object from the container.
Definition: KeyedContainer.h:595
std::vector::end
T end(T... args)
KeyedContainer::traits
Containers::traits< container_type, contained_type > traits
Traits class definition.
Definition: KeyedContainer.h:104
KeyedContainer::classID
static const CLID & classID()
Retrieve class ID.
Definition: KeyedContainer.h:199
KeyedContainer::iterator
seq_type::iterator iterator
Sequential access: iterator type used in sequential container.
Definition: KeyedContainer.h:90
ObjectContainerBase::add
virtual long add(ContainedObject *pObject)=0
Virtual functions (forwards to the concrete container definitions) Add an object to the container.
KeyedContainer::_InsertRelease
Internal functor for insertion of objects.
Definition: KeyedContainer.h:145
KeyedContainer::contained_type
DATATYPE contained_type
Definition of the contained object type.
Definition: KeyedContainer.h:69
KeyedContainer::rbegin
const_reverse_iterator rbegin() const
const reverse_iterator returns the beginning of the reversed container
Definition: KeyedContainer.h:319
Containers::OBJ_INSERTED
Object was inserted into the container.
Definition: KeyedTraits.h:26
KeyedContainer::insert
const key_type & insert(const value_type val, const key_type &kval)
Insert entry to the container with a valid key.
Definition: KeyedContainer.h:526
KeyedContainer::_InsertRelease::m_obj
KeyedContainer< DATATYPE, MAPPING > * m_obj
Definition: KeyedContainer.h:146
Containers::cannotInsertToContainer
GAUDI_API void cannotInsertToContainer()
Function to be called to indicate that an object cannot be inserted to the container.
Definition: KeyedObjectManager.cpp:73
KeyedContainer::begin
const_iterator begin() const
Retrieve start const iterator.
Definition: KeyedContainer.h:311
std::vector::push_back
T push_back(T... args)
KeyedContainer::rend
reverse_iterator rend()
reverse_iterator pointing to the end of the reversed container
Definition: KeyedContainer.h:321
KeyedContainer::_RemoveRelease::_RemoveRelease
_RemoveRelease(ObjectContainerBase *p)
Definition: KeyedContainer.h:157
compareOutputFiles.par
string par
Definition: compareOutputFiles.py:465
Containers::invalidContainerOperation
GAUDI_API void invalidContainerOperation()
Function to be called to indicate that an operation should be performed on the container or it's cont...
Definition: KeyedObjectManager.cpp:82
KeyedContainer::KeyedContainer
KeyedContainer(KeyedContainer &&other)
Definition: KeyedContainer.h:177
KeyedContainer::containedObjects
virtual const std::vector< const ContainedObject * > * containedObjects() const
Retrieve the full content of the object container by reference.
Definition: KeyedContainer.h:520
KeyedContainer::update
StatusCode update() override
Reconfigure direct access to elements (Needed by POOL data loading) This function reuses the "update"...
Definition: KeyedContainer.h:496
StatusCode
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:50
KeyedContainer::operator()
value_type operator()(const key_type &kval) const
STL algorithms support for object access.
Definition: KeyedContainer.h:354
KeyedContainer::value_type
seq_type::value_type value_type
Sequential access: definition of type stored in sequential container.
Definition: KeyedContainer.h:84
Containers::OBJ_ERASED
Object was removed, but not deleted.
Definition: KeyedTraits.h:25
IOTest.end
def end
Definition: IOTest.py:112
KeyedContainer::const_iterator
seq_type::const_iterator const_iterator
Sequential access: const iterator type used in sequential container.
Definition: KeyedContainer.h:92
CLID
unsigned int CLID
Class ID definition.
Definition: ClassID.h:8
std::vector::clear
T clear(T... args)
FORCE_INLINE
#define FORCE_INLINE
Definition: KeyedContainer.h:24
std::vector::insert
T insert(T... args)
KeyedObject.h
KeyedContainer::~KeyedContainer
~KeyedContainer() override
Destructor.
Definition: KeyedContainer.h:489
ContainedObject
All classes that their objects may be contained in an LHCb ObjectContainer (e.g.
Definition: ContainedObject.h:31
std::vector::size
T size(T... args)
KeyedContainer::object
value_type object(const key_type &kval) const
Object access by key.
Definition: KeyedContainer.h:343
std::vector< contained_type * >
DataObject::clID
virtual const CLID & clID() const
Retrieve reference to class definition structure.
Definition: DataObject.cpp:56
std::vector::begin
T begin(T... args)
KeyedContainer::erase
long erase(const value_type val)
Remove/erase object (identified by pointer value) from the container.
Definition: KeyedContainer.h:401
KeyedContainer::_InsertRelease::_InsertRelease
_InsertRelease(KeyedContainer< DATATYPE, MAPPING > *p)
Definition: KeyedContainer.h:147
KeyedContainer::empty
bool empty() const
For consistency with STL: check if container is empty.
Definition: KeyedContainer.h:277
KeyedContainer::end
iterator end()
Retrieve terminating iterator.
Definition: KeyedContainer.h:313
ObjectContainerBase::index
virtual long index(const ContainedObject *obj) const =0
Distance of a given object from the beginning of its container.
ContainedObject::setParent
void setParent(ObjectContainerBase *value)
Update parent member.
Definition: ContainedObject.h:53
KeyedContainer::key_type
contained_type::key_type key_type
Definition of the key type: re-use definition of contained type.
Definition: KeyedContainer.h:82
KeyedContainer::_RemoveRelease
Internal functor for insertion of objects.
Definition: KeyedContainer.h:155
gaudirun.s
string s
Definition: gaudirun.py:316
ObjectContainerBase::remove
virtual long remove(ContainedObject *value)=0
Release object from the container (the pointer will be removed from the container,...
ContainedObject::parent
const ObjectContainerBase * parent() const
Access to parent object.
Definition: ContainedObject.h:51
ObjectContainerBase
ObjectContainerBase is the base class for Gaudi container classes.
Definition: ObjectContainerBase.h:19
KeyedContainer::_RemoveRelease::operator()
void operator()(value_type p)
Definition: KeyedContainer.h:158
KeyedContainer::const_reverse_iterator
seq_type::const_reverse_iterator const_reverse_iterator
Sequential access: const reverse iterator type used in sequential container.
Definition: KeyedContainer.h:98
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:120
KeyedObjectManager.h
KeyedContainer::index
long index(const ContainedObject *p) const override
ObjectContainerBase overload: Retrieve the full long integer representation of the object's key from ...
Definition: KeyedContainer.h:566
std::for_each
T for_each(T... args)
GaudiDict
Definition: KeyedContainer.h:8
GAUDI_API
#define GAUDI_API
Definition: Kernel.h:71
Containers::OBJ_DELETED
Object was removed from the container and deleted.
Definition: KeyedTraits.h:24
KeyedContainer::end
const_iterator end() const
Retrieve terminating const iterator.
Definition: KeyedContainer.h:315
KeyedContainer::container_type
MAPPING container_type
Definition of the implementing container type.
Definition: KeyedContainer.h:71
KeyedContainer::m_random
seq_type * m_random
Array to allow random access to objects (not exposed)
Definition: KeyedContainer.h:114
std::vector::reserve
T reserve(T... args)
KeyedContainer::clear
void clear()
Clear the entire content and erase the objects from the container.
Definition: KeyedContainer.h:281
std::vector::rbegin
T rbegin(T... args)