From 493dac3e9803f6ed6e9f68c16b7e1504ceb4dc59 Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 11:39:29 +0100 Subject: [PATCH 01/10] first attempt in removing KeyedObjectManager --- .../src/DataSvc/StoreExplorerAlg.cpp | 11 +- GaudiExamples/GaudiExamples/MyTrack.h | 2 +- GaudiExamples/src/IO/dict.xml | 32 +- GaudiKernel/GaudiKernel/KeyedContainer.h | 267 +++---- GaudiKernel/GaudiKernel/KeyedObject.h | 5 - GaudiKernel/GaudiKernel/KeyedObjectManager.h | 102 --- GaudiKernel/GaudiKernel/KeyedTraits.h | 8 +- GaudiKernel/src/Lib/KeyedObjectManager.cpp | 664 ------------------ GaudiKernel/src/Lib/KeyedTraits.cpp | 26 + 9 files changed, 145 insertions(+), 972 deletions(-) delete mode 100644 GaudiKernel/GaudiKernel/KeyedObjectManager.h delete mode 100644 GaudiKernel/src/Lib/KeyedObjectManager.cpp create mode 100644 GaudiKernel/src/Lib/KeyedTraits.cpp diff --git a/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp b/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp index d67e97733b..26e190f759 100644 --- a/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp +++ b/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp @@ -120,6 +120,7 @@ public: const CLID id = p->clID(); log << " [" << numObj << "]"; if ( m_testAccess ) { + using ko_t = KeyedObject<int>; CLID idd = id>>16; switch(idd) { case CLID_ObjectList>>16: /* ObjectList */ @@ -129,14 +130,14 @@ public: access((ObjectVector<ContainedObject>*)base); break; case (CLID_ObjectVector+0x00030000)>>16: /* Keyed Map */ - access((KeyedContainer<KeyedObject<int>,Containers::Map>*)base); + access((KeyedContainer<ko_t,std::map<ko_t::key_type, ko_t*>>*)base); break; case (CLID_ObjectVector+0x00040000)>>16: /* Keyed Hashmap */ - access((KeyedContainer<KeyedObject<int>,Containers::HashMap>*)base); - break; - case (CLID_ObjectVector+0x00050000)>>16: /* Keyed array */ - access((KeyedContainer<KeyedObject<int>,Containers::Array>*)base); + access((KeyedContainer<ko_t,std::unordered_map<ko_t::key_type, ko_t*>>*)base); break; + //case (CLID_ObjectVector+0x00050000)>>16: /* Keyed array */ + // access((KeyedContainer<ko_t,Containers::Array>*)base); + // break; } } } diff --git a/GaudiExamples/GaudiExamples/MyTrack.h b/GaudiExamples/GaudiExamples/MyTrack.h index 684191171c..40bd8b20da 100644 --- a/GaudiExamples/GaudiExamples/MyTrack.h +++ b/GaudiExamples/GaudiExamples/MyTrack.h @@ -56,7 +56,7 @@ namespace Gaudi typedef ObjectVector<MyTrack> Container ; #else /// the actual type of container in TES - typedef KeyedContainer<MyTrack, Containers::HashMap> Container ; + typedef KeyedContainer<MyTrack> Container ; #endif // ====================================================================== protected: diff --git a/GaudiExamples/src/IO/dict.xml b/GaudiExamples/src/IO/dict.xml index 17cf77dd48..dbbe754548 100644 --- a/GaudiExamples/src/IO/dict.xml +++ b/GaudiExamples/src/IO/dict.xml @@ -7,33 +7,33 @@ <class name="Gaudi::Examples::MyVertex" id="00000164-0000-0000-0000-000000000000"/> <class name="SmartRef<Gaudi::Examples::Event>"> - <field name="m_target" transient="true"/> + <field name="m_target" transient="true"/> </class> <class name="SmartRef<Gaudi::Examples::Collision>"> - <field name="m_target" transient="true"/> + <field name="m_target" transient="true"/> </class> <class name="SmartRefVector<Gaudi::Examples::Collision>"> - <field name="m_data" transient="true"/> - <field name="m_contd" transient="true"/> + <field name="m_data" transient="true"/> + <field name="m_contd" transient="true"/> </class> <class name="std::vector<SmartRef<Gaudi::Examples::Collision> >"/> <class name="SmartRef<Gaudi::Examples::MyTrack>"> - <field name="m_target" transient="true"/> + <field name="m_target" transient="true"/> </class> <class name="SmartRefVector<Gaudi::Examples::MyTrack>"> - <field name="m_data" transient="true"/> - <field name="m_contd" transient="true"/> + <field name="m_data" transient="true"/> + <field name="m_contd" transient="true"/> </class> <class name="std::vector<SmartRef<Gaudi::Examples::MyTrack> >"/> <class name="SmartRef<Gaudi::Examples::MyVertex>"> - <field name="m_target" transient="true"/> + <field name="m_target" transient="true"/> </class> <class name="SmartRefVector<Gaudi::Examples::MyVertex>"> - <field name="m_data" transient="true"/> - <field name="m_contd" transient="true"/> + <field name="m_data" transient="true"/> + <field name="m_contd" transient="true"/> </class> <class name="std::vector<SmartRef<Gaudi::Examples::MyVertex> >"/> @@ -45,12 +45,12 @@ <class name="std::vector<KeyedObject<int>* >"/> <!-- <class name="std::vector<KeyedObject<long int>* >"/> --> - <class name="KeyedContainer<Gaudi::Examples::MyTrack,Containers::KeyedObjectManager<Containers::hashmap> >" id="00060163-0000-0000-0000-000000000000"> - <field name="m_cont" transient="true"/> - <field name="m_random" transient="true"/> + <class name="KeyedContainer<Gaudi::Examples::MyTrack>" id="00060163-0000-0000-0000-000000000000"> + <field name="m_random" transient="true"/> + <field name="m_keySeq" transient="true"/> </class> - <class name="KeyedContainer<Gaudi::Examples::MyVertex,Containers::KeyedObjectManager<Containers::hashmap> >" id="00060164-0000-0000-0000-000000000000"> - <field name="m_cont" transient="true"/> - <field name="m_random" transient="true"/> + <class name="KeyedContainer<Gaudi::Examples::MyVertex>" id="00060164-0000-0000-0000-000000000000"> + <field name="m_random" transient="true"/> + <field name="m_keySeq" transient="true"/> </class> </lcgdict> diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index 9560552f6d..5d3f831855 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -4,15 +4,14 @@ // Include files #include <iterator> #include <algorithm> - -namespace GaudiDict { - template <class T> struct KeyedContainerDict; -} +#include <map> +#include <unordered_map> // Framework include files #include "GaudiKernel/ObjectContainerBase.h" -#include "GaudiKernel/KeyedObjectManager.h" +#include "GaudiKernel/KeyedTraits.h" #include "GaudiKernel/KeyedObject.h" +#include "GaudiKernel/GaudiException.h" // Forward declarations // template <class T, class M> class KeyedContainer; @@ -23,6 +22,19 @@ namespace GaudiDict { #define FORCE_INLINE inline #endif +template<typename T> +struct CLID_KC_Vector_Offset {}; + +template <class K, class V> +struct CLID_KC_Vector_Offset<std::map<K,V>> { + constexpr static const CLID value = 0x00030000 + CLID_ObjectVector; +}; + +template <class K, class V> +struct CLID_KC_Vector_Offset<std::unordered_map<K,V>> { + constexpr static const CLID value = 0x00040000 + CLID_ObjectVector; +}; + /** template class KeyedContainer, KeyedContainer.h * * This class represents a container, where the contained objects @@ -59,16 +71,14 @@ namespace GaudiDict { * @version 1.0 * */ -template <class DATATYPE, class MAPPING=Containers::HashMap > +template <class DATATYPE, class MAPPING=std::unordered_map<typename DATATYPE::key_type, DATATYPE*>> class GAUDI_API KeyedContainer: public ObjectContainerBase { - friend struct GaudiDict::KeyedContainerDict<DATATYPE>; - public: /// Definition of the contained object type typedef DATATYPE contained_type; /// Definition of the implementing container type - typedef MAPPING container_type; + typedef MAPPING map_type; /** General container specific type definitions. The following type definitions are generic to most STL containers @@ -101,74 +111,39 @@ private: /** Traits class definition. Specializing traits allows to specialize the * container implementation for special needs. */ - typedef typename Containers::traits<container_type, contained_type> traits; + typedef typename Containers::traits<contained_type> traits; /**@name Implementation helpers. */ //@{ - /// Map container to facilitate object access by key. - container_type m_cont; /// Array to allow sequential access to the object (can be ordered). seq_type m_sequential; - /// Array to allow random access to objects (not exposed) - seq_type* m_random; + /// Map container to facilitate object access by key. + map_type m_random; + + /// Keep track of the highest inserted key (for sparse containers) + key_type m_keySeq{-1}; /// Internal function to access objects within the container -#ifdef CHECK_KEYED_CONTAINER value_type i_object(const key_type& k) const { - if ( 0 == m_cont.isDirect() ) { - if ( traits::checkBounds(m_random, k) ) { - value_type p = *(m_random->begin()+traits::hash(k)); - if ( traits::checkKey(p, k) ) { - return p; - } - } - return 0; - } - value_type p = value_type(m_cont.object(traits::hash(k))); - return traits::checkKey(p, k) ? p : 0; - } -#else - FORCE_INLINE value_type i_object(const key_type& k) const { - return 0==m_cont.isDirect() - ? value_type(*(m_random->begin()+traits::hash(k))) - : value_type(m_cont.object(traits::hash(k))); + auto it = m_random.find(traits::hash(k)); + return it == m_random.end() ? nullptr : it->second; } -#endif + /// Internal function to erase an object from the container - long i_erase(const_reference v, const key_type& k) { - value_type p = value_type(m_cont.erase(traits::hash(k), v)); - if ( p ) { - if ( p->parent() == this ) { - p->setParent(0); - } + long i_erase(const key_type& k, const_reference v=nullptr) { + auto kv = m_random.find(traits::hash(k)); + if (kv != m_random.end() && (v && kv->second == v)) { + auto it = std::find(m_sequential.begin(), m_sequential.end(), kv->second); + m_sequential.erase(it); + auto p = const_cast<reference>(kv->second); + if (p->parent() == this) p->setParent(nullptr); + return traits::release(p) <= 0 ? (long) Containers::OBJ_ERASED + : (long) Containers::OBJ_DELETED; } - return traits::release(p) <= 0 ? (long) Containers::OBJ_ERASED - : (long) Containers::OBJ_DELETED; + return static_cast<long>(Containers::OBJ_NOT_FOUND); } - /// Internal functor for insertion of objects - struct _InsertRelease { - KeyedContainer<DATATYPE,MAPPING>* m_obj; - _InsertRelease(KeyedContainer<DATATYPE,MAPPING>* p) : m_obj(p) {} - void operator()(value_type p) { - m_obj->insert(p); - traits::release(p); - } - }; - - /// Internal functor for insertion of objects - struct _RemoveRelease { - ObjectContainerBase* m_obj; - _RemoveRelease(ObjectContainerBase* p) : m_obj(p) {} - void operator()(value_type p) { - const ObjectContainerBase* par = p->parent(); - if ( par == m_obj ) { - p->setParent(0); - } - traits::release(p); - } - }; //@} public: @@ -176,13 +151,15 @@ public: */ //@{ /// Standard Constructor - KeyedContainer(void) + KeyedContainer() = default; + KeyedContainer(KeyedContainer&& other): + m_sequential(std::move(other.m_sequential)), + m_random(std::move(other.m_random)), + m_keySeq(other.m_keySeq) { - // avoid problems with strict-aliasing rules - seq_type** rptr = &m_random; - seq_type* sptr = &m_sequential; - m_cont.setup((void*)sptr,(void**)rptr); + for(auto obj: m_sequential) obj->setParent(this); } + KeyedContainer(const KeyedContainer&) = delete; /// Destructor virtual ~KeyedContainer(); //@} @@ -195,9 +172,9 @@ public: /// Retrieve class ID virtual const CLID& clID() const { return this->classID(); } /// Retrieve class ID - static const CLID& classID() { - static CLID clid = contained_type::classID() + container_type::classID(); - return clid; + static const CLID& classID() { + static CLID cid= DATATYPE::classID() + CLID_KC_Vector_Offset<MAPPING>::value; + return cid; } //@} @@ -274,9 +251,9 @@ public: /// For consistency with STL: check if container is empty bool empty() const { return m_sequential.empty(); } /// Reserve place for "value" objects in the container. - void reserve(size_type value) { m_cont.reserve(value); } + void reserve(size_type value) { m_sequential.reserve(value); } /// Clear the entire content and erase the objects from the container - void clear() { erase(begin(), end()); } + void clear() { erase(begin(), end()); } /** Retrieve the full content of the object container by reference. * Returned is the random access container if in sequntial direct * access mode. Otherwise the sequential access container is returned @@ -374,7 +351,7 @@ public: * The object was deleted, because * its reference count was zero. */ - long erase(const key_type& kval) { return i_erase(0, kval); } + long erase(const key_type& kval) { return i_erase(kval); } /** Remove/erase object (identified by pointer value) from the container. * This member function removes an object, which is identified by its @@ -397,7 +374,7 @@ public: * its reference count was zero. */ long erase(const value_type val) { - return (val) ? i_erase(val, val->key()) : (long) Containers::OBJ_NOT_FOUND; + return (val) ? i_erase(val->key(), val) : (long) Containers::OBJ_NOT_FOUND; } /** Remove/erase object (identified by iterator) from the container. @@ -430,7 +407,7 @@ public: * @param pos_stop Starting iterator of the range to be removed. * @param use_temp Flag to indicate that a temporary arry should be used. */ - void erase(iterator pos_start, iterator pos_stop, bool use_temp=false); + void erase(iterator pos_start, iterator pos_stop); /** Insert entry to the container with a valid key. * This member function inserts an element, which is identified by its @@ -445,12 +422,12 @@ public: * * @param val Reference to object to be inserted into the container. * The object reference may NOT be NULL. - * @param kval Key to identify the object within the container. + * @param k Key to identify the object within the container. * @return Key, which was used to index the object within the * container. If the operation is not * successful, an exception is thrown. */ - const key_type& insert(const value_type val, const key_type& kval); + const key_type& insert(const value_type val, const key_type& k); /** Insert entry to the container with automatic key assignment. * This member function inserts an element, which is identified by its @@ -489,35 +466,18 @@ public: template <class DATATYPE, class MAPPING> inline KeyedContainer<DATATYPE, MAPPING>::~KeyedContainer() { - erase(begin(), end()); - m_cont.clear(); + clear(); } // Configure direct access template <class DATATYPE, class MAPPING> inline StatusCode KeyedContainer<DATATYPE, MAPPING>::update() { - int count = 0; - m_cont.clearDirect(); - typename seq_type::iterator i = m_sequential.begin(); - typename seq_type::iterator s = m_sequential.end(); - for ( ; i != s; i++ ) { - typename seq_type::value_type v = *i; - if ( v ) { - if ( !v->hasKey() ) { - traits::setKey(v, v->key()); - traits::addRef(v); - } - long k0 = traits::hash(v->key()); - if(m_cont.insertDirect(this, v, v, k0) == Containers::OBJ_INSERTED) { - } - } - else { - ++count; - } - } - if ( count > 0 ) { - Containers::cannotInsertToContainer(); + m_keySeq = -1; + for(auto obj: m_sequential) { + const auto k = obj->key(); + m_random.insert({traits::hash(k), obj}); + if (m_keySeq < k) m_keySeq = k; } return StatusCode::SUCCESS; } @@ -527,28 +487,34 @@ StatusCode KeyedContainer<DATATYPE, MAPPING>::update() template <class DATATYPE, class MAPPING> inline const std::vector<const ContainedObject*>* KeyedContainer<DATATYPE, MAPPING>::containedObjects() const { - return (const std::vector<const ContainedObject*>*) - ((0==m_cont.isDirect()) ? m_random : &m_sequential); + throw GaudiException("Method not implemented", + "KeyedContainer::containedObjects()", + StatusCode::FAILURE); + return nullptr; } template <class DATATYPE, class MAPPING> inline const typename KeyedContainer<DATATYPE, MAPPING>::key_type& KeyedContainer<DATATYPE, MAPPING>::insert(const value_type val, - const key_type& kval) + const key_type& k) { - if ( val ) { - long k0 = traits::hash(kval); - if ( !val->hasKey() || (traits::hash(val->key()) == k0) ) { - if(m_cont.insert(this,val,val,k0) == Containers::OBJ_INSERTED) { - if ( !val->hasKey() ) traits::setKey(val, kval); - traits::addRef(val); - return val->key(); - } + if (val && ((!val->hasKey()) || (val->key() == k))) { + // to attempt an insertion, we need an object either + // without key or with the same key we pass + auto it = m_random.find(traits::hash(k)); + if (it == m_random.end()) { + traits::setKey(val, k); + m_keySeq = std::max(k, m_keySeq); + m_random.insert({traits::hash(k), val}); + m_sequential.push_back(val); + val->setParent(this); + traits::addRef(val); + return k; } } // Cannot insert object...indicate bad object insertion... Containers::cannotInsertToContainer(); - return val->key(); + return k; } // Insert object @@ -556,20 +522,9 @@ template <class DATATYPE, class MAPPING> //inline const typename KeyedContainer<DATATYPE, MAPPING>::key_type& KeyedContainer<DATATYPE, MAPPING>::insert(const value_type val) { - if ( 0 != val ) { - if ( val->hasKey() ) { - if (m_cont.insert(this,val,val,traits::hash(val->key())) - == Containers::OBJ_INSERTED) { - traits::addRef(val); - return val->key(); - } - } - long k0; - if ( m_cont.insert(this, val, val, &k0) == Containers::OBJ_INSERTED ) { - traits::setKey(val, traits::makeKey(k0)); - traits::addRef(val); - return val->key(); - } + if (val) { + return val->hasKey() ? insert(val, val->key()) + : insert(val, ++m_keySeq); } // Cannot insert object...indicate bad object insertion... Containers::cannotInsertToContainer(); @@ -589,14 +544,9 @@ template <class DATATYPE, class MAPPING> inline typename KeyedContainer<DATATYPE, MAPPING>::size_type KeyedContainer<DATATYPE, MAPPING>::containedObjects (std::vector<ContainedObject*>& vec) const { - typename seq_type::const_iterator i = m_sequential.begin(); - typename seq_type::const_iterator s = m_sequential.end(); vec.clear(); vec.reserve(size()); - for ( ; i != s; i++ ) { - ContainedObject* p = const_cast<typename seq_type::value_type>(*i); - vec.push_back(p); - } + for (auto o: m_sequential) vec.push_back(o); return vec.size(); } @@ -612,54 +562,23 @@ template <class DATATYPE, class MAPPING> inline long KeyedContainer<DATATYPE, MAPPING>::remove(ContainedObject* p) { contained_type* p1 = dynamic_cast<contained_type*>(p); - if ( p1 ) { // Normal case; object still fully intact - return this->erase(p1); - } - else if ( p ) { - const ObjectContainerBase* par = p->parent(); - // The following should never occur: object is in a funny state, - // Because the parent was explicitly set to NULL in the - // KeyeObject destructor. - // - It cannot be a KeyedObject: It would not have a parent - // - Still the parent is present: We are not in the destructor - // of KeyedObject - if ( par ) { - Containers::invalidContainerOperation(); - } - return m_cont.erase(0, p)==0 ? (long) Containers::OBJ_ERASED - : (long) Containers::OBJ_NOT_FOUND; - } - return (long) Containers::OBJ_NOT_FOUND; + return p1 ? this->erase(p1) : (long) Containers::OBJ_NOT_FOUND; } template <class DATATYPE, class MAPPING> inline void KeyedContainer<DATATYPE, MAPPING>::erase(iterator start_pos, - iterator stop_pos, - bool use_tmp) + iterator stop_pos) { - bool is_start = start_pos == m_sequential.begin(); - bool is_stop = stop_pos == m_sequential.end(); - if ( is_start && is_stop ) { - // Nothing special. Taken care of by Keyed object manager - } - else if ( is_start || is_stop || use_tmp ) { - std::vector<DATATYPE*> tmp(m_sequential.begin(), start_pos); - tmp.insert(tmp.end(), stop_pos, m_sequential.end()); - std::for_each(tmp.begin(), tmp.end(), traits::addRef); - this->erase(m_sequential.begin(), m_sequential.end()); - std::for_each(tmp.begin(), tmp.end(), _InsertRelease(this)); - return; - } - std::for_each(start_pos, stop_pos, _RemoveRelease(this)); - seq_type *sptr = &m_sequential; // avoid problems with strict-aliasing rules - std::vector<void*>* v = (std::vector<void*>*)sptr; - std::vector<void*>::iterator i1 = - v->begin() + std::distance(m_sequential.begin(), start_pos); - std::vector<void*>::iterator i2 = - v->begin() + std::distance(m_sequential.begin(), stop_pos); - m_cont.erase(i1, i2); + std::for_each(start_pos, stop_pos, + [this](value_type &v) { + m_random.erase(v->key()); + if (v->parent() == this) v->setParent(nullptr); + traits::release(v); + }); + m_sequential.erase(start_pos, stop_pos); } + #undef FORCE_INLINE #endif // GAUDIKERNEL_KEYEDCONTAINER_H diff --git a/GaudiKernel/GaudiKernel/KeyedObject.h b/GaudiKernel/GaudiKernel/KeyedObject.h index 1ac071527f..f5ec001be2 100644 --- a/GaudiKernel/GaudiKernel/KeyedObject.h +++ b/GaudiKernel/GaudiKernel/KeyedObject.h @@ -1,10 +1,6 @@ #ifndef GAUDIKERNEL_KEYEDOBJECT_H #define GAUDIKERNEL_KEYEDOBJECT_H -namespace GaudiDict { - template <class T> struct KeyedObjectDict; -} - // Framework include files #include "GaudiKernel/ContainedObject.h" #include "GaudiKernel/KeyedTraits.h" @@ -26,7 +22,6 @@ namespace GaudiDict { */ template < class KEY > class GAUDI_API KeyedObject: public ContainedObject { - friend struct GaudiDict::KeyedObjectDict<KEY>; public: /// Definition of the key-type to access object typedef KEY key_type; diff --git a/GaudiKernel/GaudiKernel/KeyedObjectManager.h b/GaudiKernel/GaudiKernel/KeyedObjectManager.h deleted file mode 100644 index f62931e820..0000000000 --- a/GaudiKernel/GaudiKernel/KeyedObjectManager.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef GAUDIKERNEL_KEYEDOBJECTMANAGER_H -#define GAUDIKERNEL_KEYEDOBJECTMANAGER_H - -// Framework include files -#include "GaudiKernel/Kernel.h" -#include "GaudiKernel/ClassID.h" -#include "GaudiKernel/KeyedTraits.h" - -// STL includes -#include <vector> - -// Forward declarations -class ObjectContainerBase; -class ContainedObject; - -/** Containers namespace -*/ -namespace Containers { - - /// Object manipulator type definition - typedef long (*MANIPULATOR)(void*); - /// Parametrisation class for hashmap-like implementation. - struct GAUDI_API hashmap; - /// Parametrisation class for map-like implementation. - struct GAUDI_API map; - /// Parametrisation class for redirection array - like implementation. - struct GAUDI_API array; - /// Parametrisation class for vector-like implementation. - struct GAUDI_API vector; - - /** KeyedObjectManager - * Class to manage keyed objects. This class is instantiated for two - * container types: map and hashmap. Other types are possible, - * but currently not supported. Other implementations may be achieved - * by specializing the SETUP class. - * - * As an example below the specialization for a vector like - * implementation is shown. - * - * @author M.Frank CERN/LHCb - * @version 1.0 - * - */ - template <class SETUP> - class GAUDI_API KeyedObjectManager { - private: - typedef std::vector<void*> seq_type; - /// Container holding array like container - seq_type* m_seq; - /// Dirty flag - mutable long m_direct; - mutable long m_keyCtxt; - union { - /// Buffer space to hold keyed container - char buffer[128]; - SETUP* s; - } m_setup; - - /// Callback when the container becomes dirty - void onDirty() const; - - public: - /// Standard Constructor - KeyedObjectManager(); - /// Standard Destructor - virtual ~KeyedObjectManager(); - /// Clear all direct access fields - void clearDirect(); - /// Insert element into direct access map - long insertDirect(ObjectContainerBase* b,ContainedObject* c,void* o, long k); - /// Check if the container is dirty - long isDirect() const { return m_direct; } - /// Retrieve object identified by a key from the container - void* object(long key) const; - /// Insert new object into container - long insert(ObjectContainerBase* b,ContainedObject* c,void* o, long* k); - /// Insert new object into container - long insert(ObjectContainerBase* b,ContainedObject* c,void* o,long k); - /// Remove object from container (very inefficient if key is invalid) - void* erase(long key, const void* obj); - /// Remove object by sequential iterators - long erase(seq_type::iterator beg, seq_type::iterator end); - /// Reserve buffer space - void reserve(long size); - /// Clear content of the vector - void clear(); - /// Setup of the Map and the parent object - void setup(void* seq, void** rndm); - /// Access CLID for this type of container. - static CLID classID(); - }; - - /// Forward declaration of specialized std::map-like object manager - typedef KeyedObjectManager< map > Map; - /// Forward declaration of specialized std::hashmap-like object manager - typedef KeyedObjectManager< hashmap > HashMap; - /// Forward declaration of specialized std::vector-like object manager - typedef KeyedObjectManager< vector > Vector; - /// Forward declaration of specialized redirection array object manager - typedef KeyedObjectManager< array > Array; -} -#endif // GAUDIKERNEL_KEYEDOBJECTMANAGER_H diff --git a/GaudiKernel/GaudiKernel/KeyedTraits.h b/GaudiKernel/GaudiKernel/KeyedTraits.h index fd358433f3..15fb5f33d8 100644 --- a/GaudiKernel/GaudiKernel/KeyedTraits.h +++ b/GaudiKernel/GaudiKernel/KeyedTraits.h @@ -27,11 +27,9 @@ namespace Containers { // Forward declarations /// Container traits class - template <class CONTAINER, class DATATYPE> struct traits; + template <class DATATYPE> struct traits; /// Key traits class - template <class KEY> struct key_traits; - /// Object manager class - template <class SETUP> class KeyedObjectManager; + template <class KEY> struct key_traits; /** Function to be called to indicate that an object cannot be inserted to the container. Internally an exception is thrown. */ @@ -102,7 +100,7 @@ namespace Containers { @author M.Frank CERN/LHCb @version 1.0 */ - template < class CONTAINER, class DATATYPE > + template < class DATATYPE > struct traits : public key_traits < typename DATATYPE::key_type > { /// Allow to check the access to container elements for consistency diff --git a/GaudiKernel/src/Lib/KeyedObjectManager.cpp b/GaudiKernel/src/Lib/KeyedObjectManager.cpp deleted file mode 100644 index 240d443a4f..0000000000 --- a/GaudiKernel/src/Lib/KeyedObjectManager.cpp +++ /dev/null @@ -1,664 +0,0 @@ -// Include files -#include "GaudiKernel/Kernel.h" -#include "GaudiKernel/GaudiException.h" -#include "GaudiKernel/ContainedObject.h" -#include "GaudiKernel/KeyedObjectManager.h" -#include <algorithm> -#include <map> -#include "GaudiKernel/HashMap.h" - -namespace Containers { - struct hashmap { - typedef GaudiUtils::HashMap<long, void*> map_type; - map_type m; - std::vector<void*> v; - bool insert(void* obj, long key) { - auto p = m.insert(map_type::value_type(key,obj)); - return p.second; - } - }; - struct map { - typedef std::map<long, void*> map_type; - map_type m; - std::vector<void*> v; - bool insert(void* obj, long key) { - auto p = m.insert(map_type::value_type(key,obj)); - return p.second; - } - }; - struct array { - typedef std::vector<long> map_type; - /// Indirection array - std::vector<long> m_idx; - /// Direct access array - std::vector<void*> v; - struct decrement { - long m_min; - decrement(long m) : m_min(m) {} - bool operator()(long& j) const { - if ( j > m_min ) --j; - return true; - } - }; - }; - struct vector { - typedef std::vector<void*> map_type; - /// Direct access array - std::vector<void*> v; - }; - - template <class CONT> - class find { - const void* m_obj; - typedef typename CONT::value_type v_type; - public: - find(const void* o) : m_obj(o) {} - bool operator()(const void* cmp) const { - return cmp == m_obj; - } - bool operator()(const v_type& cmp) const { - return (*this)(cmp.second); - } - }; -} -void Containers::cannotAssignObjectKey() { - throw GaudiException("Cannot assign key to keyed object! Object already has a key.", - "KeyedObject", - 0); -} -void Containers::cannotInsertToContainer() { - throw GaudiException("Cannot insert element to Keyed Container!", - "KeyedContainer", - 0); -} - -void Containers::containerIsInconsistent() { - throw GaudiException("Keyed Container structures are inconsistent - severe problem!", - "KeyedContainer", - 0); -} - -void Containers::invalidContainerOperation() { - throw GaudiException("Keyed Container cannot satisfy request - severe problem!", - "KeyedContainer", - 0); -} - -template <class T> -Containers::KeyedObjectManager<T>::KeyedObjectManager() -: m_seq(nullptr), m_direct(0) -{ - if ( sizeof(typename T::map_type) > sizeof(m_setup.buffer) ) { - throw GaudiException("Basic STL contaier sizes are incompatible", - "KeyedContainer", - 0); - } - m_setup.s = ::new(m_setup.buffer+sizeof(m_setup.s)) T(); - m_keyCtxt = -1; -} - -template <class T> -Containers::KeyedObjectManager<T>::~KeyedObjectManager() -{ - m_setup.s->~T(); -} - -/// Setup of the Map and the parent object -template <class T> void -Containers::KeyedObjectManager<T>::setup(void* seq, void** rndm) -{ - m_seq = (seq_type*)seq; - *rndm = &m_setup.s->v; -} - -template <class T> -void Containers::KeyedObjectManager<T>::onDirty() const { - m_direct = 1; - for(int i = 0, stop = m_setup.s->v.size(); i < stop; i++ ) { - m_setup.s->insert(*(m_setup.s->v.begin()+i), i); - } - m_setup.s->v.clear(); -} - -template <class T> -long Containers::KeyedObjectManager<T>::insert( - ObjectContainerBase* pBase, - ContainedObject* pObject, - void* obj, - long* key) -{ - *key = ++m_keyCtxt; - return insert(pBase, pObject, obj, *key); -} - -template <class T> -long Containers::KeyedObjectManager<T>::insert( - ObjectContainerBase* pBase, - ContainedObject* pObject, - void* obj, - long key) -{ - /// Keep major key value - if ( key > m_keyCtxt ) { - m_keyCtxt = key; - } - if ( 1==m_direct ) { - if ( m_setup.s->insert(obj, key) ) { - if ( !pObject->parent() ) { - pObject->setParent(pBase); - } - m_seq->push_back(obj); - return OBJ_INSERTED; - } - } - else if ( key == long(m_setup.s->v.size()) ) { - m_setup.s->v.push_back(obj); - if ( !pObject->parent() ) { - pObject->setParent(pBase); - } - m_seq->push_back(obj); - return OBJ_INSERTED; - } - else { - // Document is dirty now... - // need to copy all pointers from the vector to the map - onDirty(); - return insert(pBase, pObject, obj, key); - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -template <class T> -long Containers::KeyedObjectManager<T>::insertDirect( - ObjectContainerBase* pBase, - ContainedObject* pObject, - void* obj, - long key) -{ - /// Keep major key value - if ( key > m_keyCtxt ) { - m_keyCtxt = key; - } - if ( 1==m_direct ) { - if ( m_setup.s->insert(obj, key) ) { - if ( !pObject->parent() ) { - pObject->setParent(pBase); - } - return OBJ_INSERTED; - } - } - else if ( key == long(m_setup.s->v.size()) ) { - m_setup.s->v.push_back(obj); - if ( !pObject->parent() ) { - pObject->setParent(pBase); - } - return OBJ_INSERTED; - } - else { - // Document is dirty now... - // need to copy all pointers from the vector to the map - onDirty(); - return insertDirect(pBase, pObject, obj, key); - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -// Remove object from container -template <class T> -void* Containers::KeyedObjectManager<T>::erase(long key, - const void* obj) { - typedef typename T::map_type MTYP; - typedef find<MTYP> FND; - if ( 1 == m_direct ) { - auto& m = m_setup.s->m; - auto i = (obj ? std::find_if(m.begin(),m.end(),FND(obj)) - : m_setup.s->m.find(key) ); - if ( i != m_setup.s->m.end() ) { - void* o = i->second; - auto j = std::find(m_seq->begin(),m_seq->end(),o); - if ( j != m_seq->end() ) { - m_seq->erase(j); - m_setup.s->m.erase(i); - return o; - } - } - containerIsInconsistent(); - } - onDirty(); - return erase(key, obj); -} - -template <class T> -void* Containers::KeyedObjectManager<T>::object(long key) const -{ - if ( 0 == m_direct ) onDirty(); - auto i = m_setup.s->m.find(key); - if ( i != m_setup.s->m.end() ) return (*i).second; - return nullptr; -} - -template <class T> -void Containers::KeyedObjectManager<T>::reserve(long len) -{ - switch( m_direct ) { - case 1: - break; - case 0: - m_setup.s->v.reserve(len); - break; - default: - break; - } - m_seq->reserve(len); -} - -template <class T> -void Containers::KeyedObjectManager<T>::clear() -{ - clearDirect(); - m_seq->clear(); -} - -template <class T> -void Containers::KeyedObjectManager<T>::clearDirect() -{ - switch( m_direct ) { - case 1: - m_setup.s->m.clear(); - break; - case 0: - m_setup.s->v.clear(); - break; - default: - break; - } - m_direct = 0; - m_keyCtxt = -1; -} - -// Remove object by sequential iterators -template <class T> -long Containers::KeyedObjectManager<T>::erase(seq_type::iterator beg, - seq_type::iterator end) -{ - typedef typename T::map_type MTYP; - typedef find<MTYP> FND; - if ( 0 == m_direct ) { - onDirty(); - return erase(beg, end); - } - if ( beg == m_seq->begin() && end == m_seq->end() ) { - clear(); - } - else { - for ( auto j=beg; j != end; ++j) { - auto& m = m_setup.s->m; - auto i = std::find_if(m.begin(),m.end(),FND(*j)); - if ( i != m_setup.s->m.end() ) { - m_setup.s->m.erase(i); - continue; - } - containerIsInconsistent(); - } - m_seq->erase(beg, end); - } - return OBJ_ERASED; -} - -namespace Containers { - - /* First specialize static methods and then instantiate templated class to appear as symbols in the library - This order in needed for gcc 4.0 (MacOSX) */ - - template<> - CLID KeyedObjectManager< Containers::map >::classID() { - return CLID_ObjectVector+0x00030000; - } - template<> - CLID KeyedObjectManager< Containers::hashmap >::classID() { - return CLID_ObjectVector+0x00040000; - } - - template class KeyedObjectManager<Containers::hashmap>; - template class KeyedObjectManager<Containers::map>; -} - -/* - * - * - * Inline code for indirection array implementation - * - */ -typedef Containers::array __A; - -namespace Containers { - -//__forceinline -template<> void* -KeyedObjectManager< __A >::object(long value) const -{ -#ifdef CHECK_KEYED_CONTAINER - unsigned long siz = m_setup.s->m_idx.size(); - if ( value >= 0 && size_t(value) < siz ) { - long ent = *(m_setup.s->m_idx.begin()+value); - if ( ent >= 0 ) { - return *(m_setup.s->v.begin() + ent); - } - } - return nullptr; -#else - return *(m_setup.s->v.begin() + (*(m_setup.s->m_idx.begin()+value))); -#endif -} - -template<> -void KeyedObjectManager< __A >::onDirty() const { - m_direct = 1; - m_setup.s->m_idx.reserve(m_setup.s->v.size()+1); - for(int i = 0, stop = m_setup.s->v.size(); i < stop; ++i) { - if ( !m_setup.s->v[i] ) { - containerIsInconsistent(); - } - m_setup.s->m_idx.push_back(i); - } -} - -// Insert new object into container -template<> -long KeyedObjectManager< __A >::insert(ObjectContainerBase* b, - ContainedObject* c, - void* o, - long* k) -{ - // auto key creation only possible for direct access! - if ( 0 == m_direct ) { - m_seq->push_back(o); - m_setup.s->v.push_back(o); - if ( !c->parent() ) c->setParent(b); - *k = ++m_keyCtxt; - return OBJ_INSERTED; - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -// Insert new object into container -template<> -long KeyedObjectManager< __A >::insert(ObjectContainerBase* b, - ContainedObject* c, - void* o, - long k) -{ - if ( 0 == m_direct ) { - if ( k == m_keyCtxt+1 ) { - return insert(b, c, o, &k); - } - onDirty(); - return insert(b, c, o, k); - } - /// Keep major key value - if ( k > m_keyCtxt ) m_keyCtxt = k; - /// Extend redirection array and insert - if ( k+1 > long(m_setup.s->m_idx.size()) ) { - m_setup.s->m_idx.resize(k+1, -1); - } - auto idx = m_setup.s->m_idx.begin()+k; - if ( *idx == -1 ) { - *idx = m_setup.s->v.size(); - m_setup.s->v.push_back(o); - m_seq->push_back(o); - if ( !c->parent() ) c->setParent(b); - return OBJ_INSERTED; - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -// Insert new object into container -template<> long -KeyedObjectManager< __A >::insertDirect(ObjectContainerBase* b, - ContainedObject* c, - void* o, - long k) -{ - if ( 0 == m_direct ) { - if ( k == m_keyCtxt+1 ) { - m_setup.s->v.push_back(o); - if ( !c->parent() ) c->setParent(b); - ++m_keyCtxt; - return OBJ_INSERTED; - } - onDirty(); - return insertDirect(b, c, o, k); - } - /// Keep major key value - if ( k > m_keyCtxt ) m_keyCtxt = k; - /// Extend redirection array and insert - if ( k+1 > long(m_setup.s->m_idx.size()) ) { - m_setup.s->m_idx.resize(k+1, -1); - } - auto idx = m_setup.s->m_idx.begin()+k; - if ( *idx == -1 ) { - *idx = m_setup.s->v.size(); - m_setup.s->v.push_back(o); - if ( !c->parent() ) c->setParent(b); - return OBJ_INSERTED; - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -// Clear content of the vector -template<> -void KeyedObjectManager< __A >::clearDirect() { - m_setup.s->v.clear(); - m_setup.s->m_idx.clear(); - m_direct = 0; - m_keyCtxt = -1; -} - -// Remove object from container (very inefficient if key is invalid) -template<> -void* KeyedObjectManager< __A >::erase(long key, - const void* obj) -{ - typedef std::vector<long> id_type; - typedef id_type::iterator id_iter; - if ( 0 == m_direct ) { - onDirty(); - return erase(key, obj); - } - if ( obj ) { - id_type& idx = m_setup.s->m_idx; - for (auto & elem : idx) { - auto j = m_setup.s->v.begin()+(elem); - auto k = std::find(m_seq->begin(),m_seq->end(),*j); - if ( *j == obj ) { - void* o = *j; - m_seq->erase(k); - m_setup.s->v.erase(j); - std::for_each(m_setup.s->m_idx.begin(), - m_setup.s->m_idx.end(), - array::decrement(elem)); - elem = -1; - return o; - } - } - } - else if ( key >= 0 && key < long(m_setup.s->m_idx.size()) ) { - auto idx = m_setup.s->m_idx.begin()+key; - if ( *idx != -1 ) { - auto i = m_setup.s->v.begin()+(*idx); - if ( i == m_setup.s->v.end() ) { - containerIsInconsistent(); - } - void* o = *i; - auto j=std::find(m_seq->begin(),m_seq->end(),o); - if ( j == m_seq->end() ) { - containerIsInconsistent(); - } - m_seq->erase(j); - m_setup.s->v.erase(i); - std::for_each(m_setup.s->m_idx.begin(), - m_setup.s->m_idx.end(), - array::decrement(*idx)); - *idx = -1; - return o; - } - } - containerIsInconsistent(); - return nullptr; -} - -// Remove object by sequential iterators -template<> -long KeyedObjectManager< __A >::erase(seq_type::iterator beg, - seq_type::iterator end) -{ - typedef std::vector<long> id_type; - typedef id_type::iterator id_iter; - if ( beg == m_seq->begin() && end == m_seq->end() ) { - clear(); - return OBJ_ERASED; - } - else if ( 0 == m_direct ) { - onDirty(); - return erase(beg, end); - } - else { - long cnt = 0, nobj = end-beg; - id_type& idx = m_setup.s->m_idx; - for (auto & elem : idx) { - auto j = m_setup.s->v.begin()+(elem); - auto k = std::find(beg,end,*j); - if ( k != end ) { - m_setup.s->v.erase(j); - std::for_each(m_setup.s->m_idx.begin(), - m_setup.s->m_idx.end(), - array::decrement(elem)); - elem = -1; - cnt++; - if ( cnt == nobj ) break; - } - } - m_seq->erase(beg, end); - if ( cnt != nobj ) { - containerIsInconsistent(); - } - return OBJ_ERASED; - } - // cannot reach this point -} - -template<> -CLID KeyedObjectManager< __A >::classID() { - return CLID_ObjectVector+0x00050000; -} -} -template class Containers::KeyedObjectManager<__A>; -/* - * - * - * Implementation for objects with vector like access - * - * - **/ -typedef Containers::vector __V; - -namespace Containers { -// Access single entry by long(integer) key -template<> -void* KeyedObjectManager< __V >::object(long /* value */) const -{ - invalidContainerOperation(); - return nullptr; -} - -template<> -void KeyedObjectManager<__V>::onDirty() const { - invalidContainerOperation(); -} - -// Insert new object into container -template<> -long KeyedObjectManager< __V >::insert(ObjectContainerBase* b, - ContainedObject* c, - void* o, - long* k) -{ - m_seq->push_back(o); - m_setup.s->v.push_back(o); - if ( !c->parent() ) c->setParent(b); - *k = (m_setup.s->v.size()-1); - return OBJ_INSERTED; -} - -// Insert new object into container -template<> -long KeyedObjectManager< __V >::insert(ObjectContainerBase* b, - ContainedObject* c, - void* o, - long k) -{ - if ( k == long(m_setup.s->v.size()) ) { - return insert(b, c, o, &k); - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -// Insert new object into container -template<> long -KeyedObjectManager< __V >::insertDirect(ObjectContainerBase* b, - ContainedObject* c, - void* o, - long k) -{ - if ( k == long(m_setup.s->v.size()) ) { - m_setup.s->v.push_back(o); - if ( !c->parent() ) c->setParent(b); - return OBJ_INSERTED; - } - cannotInsertToContainer(); - return OBJ_CANNOT_INSERT; -} - -// Clear content of the vector -template<> -void KeyedObjectManager< __V >::clearDirect() { - m_setup.s->v.clear(); - m_direct = 0; - m_keyCtxt = -1; -} - -// Remove object from container (very inefficient if key is invalid) -template<> void* -KeyedObjectManager< __V >::erase(long /* key */, - const void* /* obj */) -{ - invalidContainerOperation(); - return nullptr; -} - -// Remove object by sequential iterators -template<> -long KeyedObjectManager< __V >::erase(seq_type::iterator beg, - seq_type::iterator end) -{ - if ( beg == m_seq->begin() && end == m_seq->end() ) { - clear(); - return OBJ_ERASED; - } - invalidContainerOperation(); - return OBJ_ERASED; -} - -template<> -CLID KeyedObjectManager< __V >::classID() { - return CLID_ObjectVector+0x00060000; -} - -} -template class Containers::KeyedObjectManager<__V>; diff --git a/GaudiKernel/src/Lib/KeyedTraits.cpp b/GaudiKernel/src/Lib/KeyedTraits.cpp new file mode 100644 index 0000000000..91d9553cfe --- /dev/null +++ b/GaudiKernel/src/Lib/KeyedTraits.cpp @@ -0,0 +1,26 @@ +// Include files +#include "GaudiKernel/GaudiException.h" +#include "GaudiKernel/KeyedTraits.h" + +void Containers::cannotAssignObjectKey() { + throw GaudiException("Cannot assign key to keyed object! Object already has a key.", + "KeyedObject", + 0); +} +void Containers::cannotInsertToContainer() { + throw GaudiException("Cannot insert element to Keyed Container!", + "KeyedContainer", + 0); +} + +void Containers::containerIsInconsistent() { + throw GaudiException("Keyed Container structures are inconsistent - severe problem!", + "KeyedContainer", + 0); +} + +void Containers::invalidContainerOperation() { + throw GaudiException("Keyed Container cannot satisfy request - severe problem!", + "KeyedContainer", + 0); +} -- GitLab From a501ed844358c02af6cce8684c7cdcc2347977bc Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 13:19:09 +0100 Subject: [PATCH 02/10] restored Containers::HashMap as template argument of KeyedContainer --- .../src/DataSvc/StoreExplorerAlg.cpp | 7 +++--- GaudiKernel/GaudiKernel/KeyedContainer.h | 19 +++------------- GaudiKernel/GaudiKernel/KeyedTraits.h | 22 +++++++++++++------ 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp b/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp index 26e190f759..ebb521611b 100644 --- a/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp +++ b/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp @@ -120,7 +120,6 @@ public: const CLID id = p->clID(); log << " [" << numObj << "]"; if ( m_testAccess ) { - using ko_t = KeyedObject<int>; CLID idd = id>>16; switch(idd) { case CLID_ObjectList>>16: /* ObjectList */ @@ -130,13 +129,13 @@ public: access((ObjectVector<ContainedObject>*)base); break; case (CLID_ObjectVector+0x00030000)>>16: /* Keyed Map */ - access((KeyedContainer<ko_t,std::map<ko_t::key_type, ko_t*>>*)base); + access((KeyedContainer<KeyedObject<int>,Containers::Map>*)base); break; case (CLID_ObjectVector+0x00040000)>>16: /* Keyed Hashmap */ - access((KeyedContainer<ko_t,std::unordered_map<ko_t::key_type, ko_t*>>*)base); + access((KeyedContainer<KeyedObject<int>,Containers::HashMap>*)base); break; //case (CLID_ObjectVector+0x00050000)>>16: /* Keyed array */ - // access((KeyedContainer<ko_t,Containers::Array>*)base); + // access((KeyedContainer<KeyedObject<int>,Containers::Array>*)base); // break; } } diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index 5d3f831855..1e9d0575e6 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -22,19 +22,6 @@ #define FORCE_INLINE inline #endif -template<typename T> -struct CLID_KC_Vector_Offset {}; - -template <class K, class V> -struct CLID_KC_Vector_Offset<std::map<K,V>> { - constexpr static const CLID value = 0x00030000 + CLID_ObjectVector; -}; - -template <class K, class V> -struct CLID_KC_Vector_Offset<std::unordered_map<K,V>> { - constexpr static const CLID value = 0x00040000 + CLID_ObjectVector; -}; - /** template class KeyedContainer, KeyedContainer.h * * This class represents a container, where the contained objects @@ -71,14 +58,14 @@ struct CLID_KC_Vector_Offset<std::unordered_map<K,V>> { * @version 1.0 * */ -template <class DATATYPE, class MAPPING=std::unordered_map<typename DATATYPE::key_type, DATATYPE*>> +template <class DATATYPE, class MAPPING=Containers::HashMap> class GAUDI_API KeyedContainer: public ObjectContainerBase { public: /// Definition of the contained object type typedef DATATYPE contained_type; /// Definition of the implementing container type - typedef MAPPING map_type; + typedef typename MAPPING:: template map_type<DATATYPE> map_type; /** General container specific type definitions. The following type definitions are generic to most STL containers @@ -173,7 +160,7 @@ public: virtual const CLID& clID() const { return this->classID(); } /// Retrieve class ID static const CLID& classID() { - static CLID cid= DATATYPE::classID() + CLID_KC_Vector_Offset<MAPPING>::value; + static CLID cid= DATATYPE::classID() + MAPPING::clid_offset; return cid; } //@} diff --git a/GaudiKernel/GaudiKernel/KeyedTraits.h b/GaudiKernel/GaudiKernel/KeyedTraits.h index 15fb5f33d8..b8c125e62a 100644 --- a/GaudiKernel/GaudiKernel/KeyedTraits.h +++ b/GaudiKernel/GaudiKernel/KeyedTraits.h @@ -5,6 +5,9 @@ // Include files #include <vector> +#include <map> +#include <unordered_map> +#include "GaudiKernel/ClassID.h" // Forward declarations template <class K> class KeyedObject; @@ -24,13 +27,6 @@ namespace Containers { OBJ_CANNOT_INSERT /**< Cannot insert object into container. */ }; - // Forward declarations - - /// Container traits class - template <class DATATYPE> struct traits; - /// Key traits class - template <class KEY> struct key_traits; - /** Function to be called to indicate that an object cannot be inserted to the container. Internally an exception is thrown. */ GAUDI_API void cannotInsertToContainer(); @@ -113,6 +109,18 @@ namespace Containers { #endif } }; + + struct Map { + template <class DATATYPE> + using map_type = std::map<typename DATATYPE::key_type, DATATYPE*>; + constexpr static const CLID clid_offset = 0x00030000 + CLID_ObjectVector; + }; + struct HashMap{ + template <class DATATYPE> + using map_type = std::unordered_map<typename DATATYPE::key_type, DATATYPE*>; + constexpr static const CLID clid_offset = 0x00040000 + CLID_ObjectVector; + }; + } #endif // GAUDIKERNEL_KEYEDTRAITS_H -- GitLab From 5ca63b51a41867614643abb10e3e5d9c494d94d4 Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 13:46:22 +0100 Subject: [PATCH 03/10] removed some useless code --- GaudiKernel/GaudiKernel/KeyedContainer.h | 10 ++++----- GaudiKernel/GaudiKernel/KeyedTraits.h | 28 +----------------------- 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index 1e9d0575e6..4f8af93033 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -113,13 +113,13 @@ private: /// Internal function to access objects within the container value_type i_object(const key_type& k) const { - auto it = m_random.find(traits::hash(k)); + auto it = m_random.find(k); return it == m_random.end() ? nullptr : it->second; } /// Internal function to erase an object from the container long i_erase(const key_type& k, const_reference v=nullptr) { - auto kv = m_random.find(traits::hash(k)); + auto kv = m_random.find(k); if (kv != m_random.end() && (v && kv->second == v)) { auto it = std::find(m_sequential.begin(), m_sequential.end(), kv->second); m_sequential.erase(it); @@ -463,7 +463,7 @@ StatusCode KeyedContainer<DATATYPE, MAPPING>::update() m_keySeq = -1; for(auto obj: m_sequential) { const auto k = obj->key(); - m_random.insert({traits::hash(k), obj}); + m_random.insert({k, obj}); if (m_keySeq < k) m_keySeq = k; } return StatusCode::SUCCESS; @@ -488,11 +488,11 @@ KeyedContainer<DATATYPE, MAPPING>::insert(const value_type val, if (val && ((!val->hasKey()) || (val->key() == k))) { // to attempt an insertion, we need an object either // without key or with the same key we pass - auto it = m_random.find(traits::hash(k)); + auto it = m_random.find(k); if (it == m_random.end()) { traits::setKey(val, k); m_keySeq = std::max(k, m_keySeq); - m_random.insert({traits::hash(k), val}); + m_random.insert({k, val}); m_sequential.push_back(val); val->setParent(this); traits::addRef(val); diff --git a/GaudiKernel/GaudiKernel/KeyedTraits.h b/GaudiKernel/GaudiKernel/KeyedTraits.h index b8c125e62a..a01b09c86f 100644 --- a/GaudiKernel/GaudiKernel/KeyedTraits.h +++ b/GaudiKernel/GaudiKernel/KeyedTraits.h @@ -1,8 +1,6 @@ #ifndef GAUDIKERNEL_KEYEDTRAITS_H #define GAUDIKERNEL_KEYEDTRAITS_H -#define CHECK_KEYED_CONTAINER - // Include files #include <vector> #include <map> @@ -67,21 +65,8 @@ namespace Containers { static key_type makeKey(int k) {return key_type(k); } /// Full unhashed key identifier static long identifier(const key_type& k) {return k; } - /// Hash function for this key - static long hash(const key_type& key_value) {return key_value; } /// Set object key when inserted into the container static void setKey(obj_type* v, const key_type& k) {if(v)v->setKey(k); } - /** Check the validity of the object's key. - Select if key-checks should be performed by - switching on/off the macro CHECK_KEYED_CONTAINER. - */ - static bool checkKey(obj_type* v,const key_type& k) { -#ifdef CHECK_KEYED_CONTAINER - return (v) ? (hash(v->key())==hash(k)) : false; -#else - return true; -#endif - } /// Add reference counter to object when inserted into the container static long addRef(obj_type* v) { return (v) ? v->addRef() : 0; } /// Release reference to object @@ -97,18 +82,7 @@ namespace Containers { @version 1.0 */ template < class DATATYPE > - struct traits : public key_traits < typename DATATYPE::key_type > - { - /// Allow to check the access to container elements for consistency - static bool checkBounds(const std::vector<DATATYPE*>* cnt, - const typename DATATYPE::key_type& k) { -#ifdef CHECK_KEYED_CONTAINER - return size_t(cnt->size()) > size_t(traits::hash(k)); -#else - return true; -#endif - } - }; + using traits = key_traits<typename DATATYPE::key_type>; struct Map { template <class DATATYPE> -- GitLab From b2437eb54ed4b5b6c026310d859fef1e6bfafe75 Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 19:17:53 +0100 Subject: [PATCH 04/10] restored KeyedObjectManager<hashmap> for compatibility with old files --- GaudiKernel/GaudiKernel/KeyedTraits.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/GaudiKernel/GaudiKernel/KeyedTraits.h b/GaudiKernel/GaudiKernel/KeyedTraits.h index a01b09c86f..be76934fa7 100644 --- a/GaudiKernel/GaudiKernel/KeyedTraits.h +++ b/GaudiKernel/GaudiKernel/KeyedTraits.h @@ -74,27 +74,30 @@ namespace Containers { }; /** Definition of the container traits class. - - Select if container-checks should be performed by - switching on/off the macro CHECK_KEYED_CONTAINER. - - @author M.Frank CERN/LHCb - @version 1.0 */ template < class DATATYPE > using traits = key_traits<typename DATATYPE::key_type>; - struct Map { + // There is no technical reason to use the dummy KeyedObjectManager<T> typedefs, + // instead the underlying map and hashmap classes, but we keep it for backward + // compatibility with old data (on file). + struct map { template <class DATATYPE> using map_type = std::map<typename DATATYPE::key_type, DATATYPE*>; constexpr static const CLID clid_offset = 0x00030000 + CLID_ObjectVector; }; - struct HashMap{ + struct hashmap{ template <class DATATYPE> using map_type = std::unordered_map<typename DATATYPE::key_type, DATATYPE*>; constexpr static const CLID clid_offset = 0x00040000 + CLID_ObjectVector; }; + template <typename T> + struct KeyedObjectManager: public T {}; + + typedef KeyedObjectManager<map> Map; + typedef KeyedObjectManager<hashmap> HashMap; + } #endif // GAUDIKERNEL_KEYEDTRAITS_H -- GitLab From 047b4cab2e70f53353e84692661a28a9b200fadf Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 19:19:05 +0100 Subject: [PATCH 05/10] fixed some clang warnings and clean up --- GaudiKernel/GaudiKernel/KeyedContainer.h | 34 ++++++------------------ 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index 4f8af93033..1eb3df14d4 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -13,15 +13,6 @@ #include "GaudiKernel/KeyedObject.h" #include "GaudiKernel/GaudiException.h" -// Forward declarations -// template <class T, class M> class KeyedContainer; - -#ifdef WIN32 -#define FORCE_INLINE __forceinline -#else -#define FORCE_INLINE inline -#endif - /** template class KeyedContainer, KeyedContainer.h * * This class represents a container, where the contained objects @@ -148,7 +139,7 @@ public: } KeyedContainer(const KeyedContainer&) = delete; /// Destructor - virtual ~KeyedContainer(); + ~KeyedContainer() noexcept override { clear(); } //@} /**@name DataObject virtual function overloads. @@ -157,7 +148,7 @@ public: */ //@{ /// Retrieve class ID - virtual const CLID& clID() const { return this->classID(); } + const CLID& clID() const override { return this->classID(); } /// Retrieve class ID static const CLID& classID() { static CLID cid= DATATYPE::classID() + MAPPING::clid_offset; @@ -182,7 +173,7 @@ public: */ //@{ /// ObjectContainerBase overload: Number of objects in the container - virtual size_type numberOfObjects() const { return m_sequential.size(); } + size_type numberOfObjects() const override { return m_sequential.size(); } /** ObjectContainerBase overload: Add an object to the container. * Plese see the documentation of the member function * @@ -194,7 +185,7 @@ public: * container. * @return long integer representation of the key value. */ - virtual long add(ContainedObject* pObject); + long add(ContainedObject* pObject) override; /** ObjectContainerBase overload: Remove an object from the container. * Because this function is also called from the destructor of @@ -208,18 +199,18 @@ public: * @param pObject Pointer to the object to be removed from the * container. */ - virtual long remove(ContainedObject* pObject); + long remove(ContainedObject* pObject) override; /** ObjectContainerBase overload: Retrieve the object by reference * given the long integer representation of the object's key. */ - virtual ContainedObject* containedObject(long key_value) const { + ContainedObject* containedObject(long key_value) const override { return i_object( traits::makeKey( key_value ) ); } /** ObjectContainerBase overload: Retrieve the full long integer * representation of the object's key from the object base class pointer. */ - virtual long index(const ContainedObject* p) const; + long index(const ContainedObject* p) const override; /** Retrieve the full content of the object container. * @param v Vector of contained objects, which will host * all objects contained in this container. @@ -251,7 +242,7 @@ public: * This function reuses the "update" callback of the generic DataObject * base class. */ - virtual StatusCode update(); + StatusCode update() override; //@} /**@name Sequential array access to objects using iterators. @@ -449,13 +440,6 @@ public: * */ -// Destructor -template <class DATATYPE, class MAPPING> inline -KeyedContainer<DATATYPE, MAPPING>::~KeyedContainer() -{ - clear(); -} - // Configure direct access template <class DATATYPE, class MAPPING> inline StatusCode KeyedContainer<DATATYPE, MAPPING>::update() @@ -566,6 +550,4 @@ KeyedContainer<DATATYPE, MAPPING>::erase(iterator start_pos, m_sequential.erase(start_pos, stop_pos); } - -#undef FORCE_INLINE #endif // GAUDIKERNEL_KEYEDCONTAINER_H -- GitLab From e7cbb5d9e64b5438e2e1b1e03902b466adc8604d Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 19:20:09 +0100 Subject: [PATCH 06/10] fixed automatic key value in KeyedContainer for LHCb classes --- GaudiKernel/GaudiKernel/KeyedContainer.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index 1eb3df14d4..37a508dcf3 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -100,7 +100,7 @@ private: map_type m_random; /// Keep track of the highest inserted key (for sparse containers) - key_type m_keySeq{-1}; + std::size_t m_keySeq{std::numeric_limits<std::size_t>::max()}; /// Internal function to access objects within the container value_type i_object(const key_type& k) const { @@ -444,11 +444,12 @@ public: template <class DATATYPE, class MAPPING> inline StatusCode KeyedContainer<DATATYPE, MAPPING>::update() { - m_keySeq = -1; + m_keySeq = std::numeric_limits<std::size_t>::max(); for(auto obj: m_sequential) { const auto k = obj->key(); m_random.insert({k, obj}); - if (m_keySeq < k) m_keySeq = k; + const auto k1 = std::hash<key_type>()(k); + if (m_keySeq < k1) m_keySeq = k1; } return StatusCode::SUCCESS; } @@ -475,11 +476,12 @@ KeyedContainer<DATATYPE, MAPPING>::insert(const value_type val, auto it = m_random.find(k); if (it == m_random.end()) { traits::setKey(val, k); - m_keySeq = std::max(k, m_keySeq); m_random.insert({k, val}); m_sequential.push_back(val); val->setParent(this); traits::addRef(val); + const auto k1 = std::hash<key_type>()(k); + m_keySeq = std::max(k1, m_keySeq); return k; } } @@ -495,7 +497,7 @@ KeyedContainer<DATATYPE, MAPPING>::insert(const value_type val) { if (val) { return val->hasKey() ? insert(val, val->key()) - : insert(val, ++m_keySeq); + : insert(val, key_type(++m_keySeq)); } // Cannot insert object...indicate bad object insertion... Containers::cannotInsertToContainer(); -- GitLab From 594cc96cb98d0e9025a6884ae582634a27828010 Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Thu, 19 Nov 2015 23:53:14 +0100 Subject: [PATCH 07/10] removed last reference to Containers::Array/Vector (never used in LHCb) --- GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp | 3 --- GaudiKernel/dict/dictionary.xml | 2 -- 2 files changed, 5 deletions(-) diff --git a/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp b/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp index ebb521611b..f0f199ea4c 100644 --- a/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp +++ b/GaudiCommonSvc/src/DataSvc/StoreExplorerAlg.cpp @@ -134,9 +134,6 @@ public: case (CLID_ObjectVector+0x00040000)>>16: /* Keyed Hashmap */ access((KeyedContainer<KeyedObject<int>,Containers::HashMap>*)base); break; - //case (CLID_ObjectVector+0x00050000)>>16: /* Keyed array */ - // access((KeyedContainer<KeyedObject<int>,Containers::Array>*)base); - // break; } } } diff --git a/GaudiKernel/dict/dictionary.xml b/GaudiKernel/dict/dictionary.xml index c004c6b87a..3ba3a7abee 100644 --- a/GaudiKernel/dict/dictionary.xml +++ b/GaudiKernel/dict/dictionary.xml @@ -217,8 +217,6 @@ <class name="Containers::KeyedObjectManager<Containers::hashmap>"/> <class name="Containers::KeyedObjectManager<Containers::map>"/> - <class name="Containers::KeyedObjectManager<Containers::array>"/> - <class name="Containers::KeyedObjectManager<Containers::vector>"/> <!--class name="std::vector<std::basic_string<char> >"/--> -- GitLab From e31de0ee6d1373fb59b29d496cdade7ac58efbc8 Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Fri, 20 Nov 2015 00:54:03 +0100 Subject: [PATCH 08/10] attempt to avoid the need of hashable keys in KeyedContainer --- GaudiKernel/GaudiKernel/KeyedContainer.h | 25 ++++++++++++------------ GaudiKernel/GaudiKernel/KeyedTraits.h | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index 37a508dcf3..b3d86fe896 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -100,17 +100,20 @@ private: map_type m_random; /// Keep track of the highest inserted key (for sparse containers) - std::size_t m_keySeq{std::numeric_limits<std::size_t>::max()}; + typedef typename map_type::key_type map_key_type; + map_key_type m_keySeq{-1}; + + inline static map_key_type to_map_key(const key_type& k) { return k; } /// Internal function to access objects within the container value_type i_object(const key_type& k) const { - auto it = m_random.find(k); + auto it = m_random.find(to_map_key(k)); return it == m_random.end() ? nullptr : it->second; } /// Internal function to erase an object from the container long i_erase(const key_type& k, const_reference v=nullptr) { - auto kv = m_random.find(k); + auto kv = m_random.find(to_map_key(k)); if (kv != m_random.end() && (v && kv->second == v)) { auto it = std::find(m_sequential.begin(), m_sequential.end(), kv->second); m_sequential.erase(it); @@ -121,7 +124,6 @@ private: } return static_cast<long>(Containers::OBJ_NOT_FOUND); } - //@} public: @@ -444,12 +446,11 @@ public: template <class DATATYPE, class MAPPING> inline StatusCode KeyedContainer<DATATYPE, MAPPING>::update() { - m_keySeq = std::numeric_limits<std::size_t>::max(); + m_keySeq = -1; for(auto obj: m_sequential) { - const auto k = obj->key(); + const auto k = to_map_key(obj->key()); m_random.insert({k, obj}); - const auto k1 = std::hash<key_type>()(k); - if (m_keySeq < k1) m_keySeq = k1; + if (m_keySeq < k) m_keySeq = k; } return StatusCode::SUCCESS; } @@ -473,14 +474,14 @@ KeyedContainer<DATATYPE, MAPPING>::insert(const value_type val, if (val && ((!val->hasKey()) || (val->key() == k))) { // to attempt an insertion, we need an object either // without key or with the same key we pass - auto it = m_random.find(k); + const auto k1 = to_map_key(k); + auto it = m_random.find(k1); if (it == m_random.end()) { traits::setKey(val, k); - m_random.insert({k, val}); + m_random.insert({k1, val}); m_sequential.push_back(val); val->setParent(this); traits::addRef(val); - const auto k1 = std::hash<key_type>()(k); m_keySeq = std::max(k1, m_keySeq); return k; } @@ -545,7 +546,7 @@ KeyedContainer<DATATYPE, MAPPING>::erase(iterator start_pos, { std::for_each(start_pos, stop_pos, [this](value_type &v) { - m_random.erase(v->key()); + m_random.erase(to_map_key(v->key())); if (v->parent() == this) v->setParent(nullptr); traits::release(v); }); diff --git a/GaudiKernel/GaudiKernel/KeyedTraits.h b/GaudiKernel/GaudiKernel/KeyedTraits.h index be76934fa7..c41e44ff8b 100644 --- a/GaudiKernel/GaudiKernel/KeyedTraits.h +++ b/GaudiKernel/GaudiKernel/KeyedTraits.h @@ -83,12 +83,12 @@ namespace Containers { // compatibility with old data (on file). struct map { template <class DATATYPE> - using map_type = std::map<typename DATATYPE::key_type, DATATYPE*>; + using map_type = std::map<long, DATATYPE*>; constexpr static const CLID clid_offset = 0x00030000 + CLID_ObjectVector; }; struct hashmap{ template <class DATATYPE> - using map_type = std::unordered_map<typename DATATYPE::key_type, DATATYPE*>; + using map_type = std::unordered_map<long, DATATYPE*>; constexpr static const CLID clid_offset = 0x00040000 + CLID_ObjectVector; }; -- GitLab From b2bf64c234294d1bc74da8b9c036546c33a3110e Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Fri, 20 Nov 2015 01:09:49 +0100 Subject: [PATCH 09/10] allow key conversion to long via hash function or implicit conversion --- GaudiKernel/GaudiKernel/KeyedContainer.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index b3d86fe896..b59229573a 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -103,7 +103,11 @@ private: typedef typename map_type::key_type map_key_type; map_key_type m_keySeq{-1}; - inline static map_key_type to_map_key(const key_type& k) { return k; } + // if the key provides a hash method we use it, otherwise we fall back + // on implicit conversion to map_key_type. + template <typename K, typename=decltype(K().hash())> + inline static map_key_type to_map_key(const K& k) { return k.hash(); } + inline static map_key_type to_map_key(map_key_type k) { return k; } /// Internal function to access objects within the container value_type i_object(const key_type& k) const { -- GitLab From df14e2389f9dbc7ae12868587eab72d0c3e2465e Mon Sep 17 00:00:00 2001 From: Marco Clemencic <marco.clemencic@cern.ch> Date: Fri, 20 Nov 2015 07:50:18 +0100 Subject: [PATCH 10/10] minor optimization in KeyedContainer::clear --- GaudiKernel/GaudiKernel/KeyedContainer.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/GaudiKernel/GaudiKernel/KeyedContainer.h b/GaudiKernel/GaudiKernel/KeyedContainer.h index b59229573a..96665b3d61 100644 --- a/GaudiKernel/GaudiKernel/KeyedContainer.h +++ b/GaudiKernel/GaudiKernel/KeyedContainer.h @@ -237,7 +237,7 @@ public: /// Reserve place for "value" objects in the container. void reserve(size_type value) { m_sequential.reserve(value); } /// Clear the entire content and erase the objects from the container - void clear() { erase(begin(), end()); } + void clear(); /** Retrieve the full content of the object container by reference. * Returned is the random access container if in sequntial direct * access mode. Otherwise the sequential access container is returned @@ -543,6 +543,18 @@ long KeyedContainer<DATATYPE, MAPPING>::remove(ContainedObject* p) return p1 ? this->erase(p1) : (long) Containers::OBJ_NOT_FOUND; } +template <class DATATYPE, class MAPPING> inline +void +KeyedContainer<DATATYPE, MAPPING>::clear() +{ + for(auto v: m_sequential) { + if (v->parent() == this) v->setParent(nullptr); + traits::release(v); + } + m_sequential.clear(); + m_random.clear(); +} + template <class DATATYPE, class MAPPING> inline void KeyedContainer<DATATYPE, MAPPING>::erase(iterator start_pos, -- GitLab