#ifndef _evt_ComponentGroup_h_ #define _evt_ComponentGroup_h_ #include #include #include #include #include #include namespace evt { /** * \brief Auxiliary function to check whether the iterator * points to a valid Component. */ template void Check(Iterator& i, Iterator& e, int id) { if (i == e) { std::ostringstream error; // XXX See Make. error << "Id " << id << " not present."; ERROR(error); throw utl::NonExistentComponentException(error.str()); } } /** * \class ComponentGroup ComponentGroup.h "evt/ComponentGroup.h" * \brief Common class for groups of components of the Event hierarchy * * Groups elements of the event hierarchy and responds to the has/make/get * interface. * * \param Component The actual type of the component. Its instances are * constructed here with the following expression * \code * Component* c = new Component(id); * \endcode * where id is of const int type. * * Since the objects will be owned, they must be feasible to be * destructed. In particular, given the innards of this class * the destruction is perfomed, at last, by * * template * void boost::checked_delete(T*); * * so the destructor must be accesible at least by that function. * * \todo The friend declation that may be needed to be granted to * checked_delete reveals the implementation of this class. It's * somewhat the same that happens in this Event hierarchy with * utl::LameShadowPtr in the sense that the class that will be * buried inside the ShadowPtr gives friendship to ShadowPtr * because it happens that ShadowPtr it's used to contain that * class' instances in the parent object within the hierarchy. * Another possibility is to leave the destructors public (but, * of course, keeping restricted the means of construction), it * doesn't seem likely that, by chance, the destructor is called * from client code. Another last possibility (in the case * of having to grant friendship to a type) would have been * to allow typedef-names in friend declaration, so that an * appropiate alias is declared and then friendship is declared * using that alias: so that the real underlying type is hidden. * Unfortunately up to now it isn't allowed, see * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf * * \author Rodolfo Federico Gamarra * \date 03 Mar 2009 * \ingroup evt */ template class ComponentGroup { private: /** * \brief Little helper to retrieve the second from the * pair. * * XXX Some Boost "clever" binder / lambda / whatever * could be used here. */ /* template< class R > struct SecondResolver { typedef R result_type; template< class Pair > R operator()( const Pair& p ) const { return *p.second; } }; */ template struct SecondResolver { typedef RetType result_type; typedef ArgType argument_type; result_type operator()(argument_type p) const { return * p.second; } }; /** * Given the usage context where id-lookup is performed * then seems better to introduce a map instead of a vector * and using linear-search. On the other hand the iteration * over the map should be still equally performing than the * one over the vector. * Then the map holds the relation id->Component. * * Since the objects will be heap-allocated (and owned) favor * Boost's ptr container instead a home-cooked raw * container. */ typedef boost::ptr_map InternalComponentCollection; // Some More aliases (in const and non-const flavor for some cases) typedef typename InternalComponentCollection::key_type KeyType; typedef typename InternalComponentCollection::mapped_type MappedType; typedef const Component* /* No nested typedef for this...*/ ConstMappedType; typedef typename InternalComponentCollection::mapped_reference MappedReference; typedef typename InternalComponentCollection::const_mapped_reference ConstMappedReference; typedef typename InternalComponentCollection::const_reference ConstReference; typedef typename InternalComponentCollection::reference Reference; typedef typename InternalComponentCollection::const_iterator PairConstIterator; typedef typename InternalComponentCollection::iterator PairIterator; // Alternative typedef SecondResolver ConstComponentResolver; // Alternative typedef SecondResolver ComponentResolver; typedef SecondResolver ConstComponentResolver; typedef SecondResolver ComponentResolver; /** * \brief Instance of the (stateless) helper class (stored * on a class for the containing class) for const component * resolving. */ static const ConstComponentResolver kConstResolver; /** * \brief Non-const resolving. * \sa fConstResolver */ static const ComponentResolver kResolver; public: /** * \brief Alias for constant iterator over contained components. * \sa ComponentIterator */ typedef boost::transform_iterator ComponentConstIterator; /** * \brief Alias for non-constant iterator over contained components. * \sa ComponentConstIterator */ typedef boost::transform_iterator ComponentIterator; /** * \brief Retrieve by id. */ const Component& Get(const int id) const { PairConstIterator i = fComponents.find(id); PairConstIterator e = fComponents.end(); Check(i, e, id); return * i->second; } /** * \brief Retrieve by id. */ Component& Get(const int id) { PairIterator i = fComponents.find(id); PairIterator e = fComponents.end(); Check(i, e, id); return * i->second; } /** * \brief Construct by id. */ void Make(const int id) { // id-constructor Component* c = new Component(id); /* * The id needs to be non-const due to the needs * of the object being called. * http://www.boost.org/doc/libs/1_38_0/libs/ptr_container/doc/tutorial.html * "Note that must create the key as an lvalue (due to exception-safety issues)..." */ int i = id; bool already = !fComponents.insert(i, c).second; if (already) { /* * boost::ptr_map_adapter::insert_impl * takes care of destroying if insertion * wasn't performed at last. * delete c; */ std::ostringstream error; // XXX Put some component label: add a typedef to the Component type? error << id << " already present."; WARNING(error); } } /** * \brief Query existence. */ bool Has(const int id) const { return fComponents.find(id) != fComponents.end(); } /** * \brief Query quantity. */ int GetNumberOf() const { // XXX Why this isn't unsigned (taken from sdet::SEvent::GetNumberOfStations and others)? return fComponents.size(); } /** * \brief Non-const begin-iterator. */ ComponentIterator Begin() { return boost::make_transform_iterator(fComponents.begin(), kResolver); } /** * \brief Non-const end-iterator. */ ComponentIterator End() { return boost::make_transform_iterator(fComponents.end(), kResolver); } /** * \brief Const begin-iterator. */ ComponentConstIterator Begin() const { return boost::make_transform_iterator(fComponents.begin(), kConstResolver); } /** * \brief Const end-iterator. */ ComponentConstIterator End() const { return boost::make_transform_iterator(fComponents.end(), kConstResolver); } private: InternalComponentCollection fComponents; }; } #endif //_evt_ComponentGroup_h_