Detector/ComponentGroup.h
Go to the documentation of this file.
1 #ifndef _det_ComponentGroup_h
2 #define _det_ComponentGroup_h
3 
4 #include <det/VManager.h>
5 #include <det/DetectorComponent.h>
6 #include <utl/ErrorLogger.h>
7 //
8 #include <list>
9 #include <set>
10 #include <algorithm>
11 //
13 // This include generates a warning:
14 // boost/ptr_container/detail/map_iterator.hpp:52: warning: type qualifiers ignored on function return type
15 // https://svn.boost.org/trac/boost/ticket/4276
16 #include <boost/ptr_container/ptr_map.hpp>
17 #include <boost/iterator/transform_iterator.hpp>
18 
19 
20 namespace det {
21 
46  struct IdOnlyCreator {
47  template<class Parent, class Child>
48  static Child* CreateObject(int id, const Parent& /*parent*/)
49  { return new Child(id); }
50  };
51 
52 
63  struct ParentCreator {
64  template<class Parent, class Child>
65  static Child* CreateObject(int id, const Parent& parent)
66  { /* Retrieve the parent's ids. */ return new Child(id, parent.GetIdsMap(), parent); }
67  };
68 
69 
72  private:
88  template<class A1, class A2, class A3, class A4> friend class ComponentGroup;
89 
91  template<class Component>
92  static void UpdateComponent(Component& c, bool invData, bool invComp)
93  { c.Update(invData, invComp); }
94  };
95 
96 
126  template<class P, class C, class Creator, class ManagerProvider>
128  private:
129  typedef boost::ptr_map<int, C> ComponentMap;
130 
131  /*
132  * It seems that's more proper to have a set here; but VManager
133  * doesn't set methods. Anyway this class doesn't rely on a no-repetitions
134  * invariant; having them will only degrade the performance and it's
135  * meaningless (this class only care about membership).
136  * See next.
137  */
138  typedef std::list<int> IdList;
139 
140  /*
141  * Now we may want to query, repeteadly the existance of a given component,
142  * without actually loading the component. For this case, we fill a set
143  * so as to have an efficient query mechanism (instead of a linear search
144  * along the list). Note that, obviously, any repetition in the list is lost,
145  * which is 0k.
146  */
147  typedef std::set<int> IdSet;
148  typedef typename IdList::const_iterator IdIterator;
149  typedef typename ComponentMap::iterator ComponentMapIterator;
150  typedef typename ComponentMap::const_iterator ComponentMapConstIterator;
151 
159  : fContainer(p) { }
160  const C& operator()(const IdList::value_type& id) const
161  { return fContainer.Get(id); }
162  private:
164  };
165 
173  : fContainer(p) { }
174 
180  C& operator()(const IdList::value_type& id) const
181  { return fContainer.Get(id); }
182 
183  private:
185  };
186 
187  public:
189  typedef boost::transform_iterator<
191  IdIterator,
192  const C&
194 
196  typedef boost::transform_iterator<
198  IdIterator,
199  C&
201 
203  typedef C ComponentType;
204 
206  ComponentGroup(const P& p) : fParent(p) { }
207 
212  const C& Get(int i) const;
213 
218  C& Get(int i);
219 
221  bool Exists(int i) const;
222 
225  Begin()
226  const
227  {
228  // Here the call is 'begin' in lower case as of standard-C++ usage.
229  return ConstIterator(fComponentsIds.begin(), InternalConstFunctor(*this));
230  }
231 
234  End()
235  const
236  {
237  // see Begin().
238  return ConstIterator(fComponentsIds.end(), InternalConstFunctor(*this));
239  }
240 
242  Iterator
244  {
245  // See const Begin.
246  return Iterator(fComponentsIds.begin(), InternalFunctor(*this));
247  }
248 
250  Iterator
251  End()
252  {
253  // see Begin().
254  return Iterator(fComponentsIds.end(), InternalFunctor(*this));
255  }
256 
272  void Update(const VManager::IndexMap& m, const bool invalidateData = true, const bool invalidateComponents = true);
273 
275  typedef IdList::size_type SizeType;
276 
279 
280  private:
282  const P& fParent;
283 
286 
289 
296 
299  };
300 
301 
302  template<class P, class C, class Creator, class ManagerProvider>
303  void
304  ComponentGroup<P, C, Creator, ManagerProvider>::Update(const VManager::IndexMap& m, const bool invalidateData, const bool invalidateComponents)
305  {
306  //DEBUGLOG("Updating");
307  // Check for empty as an indicator that this is the first call to update.
308  if (fComponentsIds.empty() || invalidateComponents) {
309  // Clear all as part of component invalidation...
310  fComponentsIds.clear();
311  fComponentsById.clear();
312  fComponentsIdsSet.clear();
313  fNumberOfIds = 0;
314  // This update method seems to be an implicit interface for Detectors.
315  // Keep its name within this template class, but with an aditional
316  // parameter: the map.
317  // --
318  // Retrieve the manager via the template argument.
319  const VManager& mgr = ManagerProvider::GetInstance();
320  // Rely on the field with the name.
321  const VManager::Status s = mgr.GetData(fComponentsIds, C::kComponentName, "", m);
322  if (s == VManager::eNotFound) {
323  std::ostringstream e;
324  e << "Couldn't find the list of " << C::kComponentName << ':';
325  for (VManager::IndexMap::const_iterator i = m.begin(); i != m.end(); ++i) {
326  e << ' ' << i->first << '=' << i->second;
327  }
328  //DEBUGLOG(e);
329  } else {
330  // std::list::size has linear behaviour.
331  fNumberOfIds = fComponentsIds.size();
332  }
333  }
334  /*
335  * Now update (only) the components already loaded (this may be
336  * a second call to the Update method).
337  */
338  for (ComponentMapIterator i = fComponentsById.begin(), e = fComponentsById.end(); i != e; ++i)
339  ComponentUpdater::UpdateComponent(*(i->second), invalidateData, invalidateComponents);
340  //DEBUGLOG("Updating end");
341  }
342 
343 
344  template<class P, class C, class Creator, class ManagerProvider>
345  const C&
347  const
348  {
349  // Look for already created objects.
350  const ComponentMapConstIterator ic = fComponentsById.find(id);
351  if (ic != fComponentsById.end())
352  return *ic->second;
353  // Need to load him, if it exists: modify internal mutable data fields.
354  const IdIterator ii = std::find(fComponentsIds.begin(), fComponentsIds.end(), id);
355  if (ii != fComponentsIds.end()) {
356  // Being a template functions eases the use & specalization, but puts the burden
357  // in this call.
358  C* c = Creator::template CreateObject<P, C>(id, fParent);
359  fComponentsById.insert(id, c);
360  return *c;
361  } else {
362  std::ostringstream e;
363  e << "No " << C::kComponentName << " with Id= " << id << " was found.";
364  ERROR(e);
365  throw utl::NonExistentComponentException(e.str());
366  }
367  }
368 
369 
370  template<class P, class C, class Creator, class ManagerProvider>
371  C&
373  {
374  /*
375  * Use const_cast s to avoid repetition as recommended in
376  * "Avoid Duplication in const and Non-const Member Function," on p. 23, in Item 3
377  * "Use const whenever possible," in Effective C++, 3d ed
378  * by Scott Meyers, ISBN-13: 9780321334879.
379  * In Offline's recommendations (https://www.auger.unam.mx/AugerWiki/CppConventions) it's said:
380  * "In this respect the use of const_cast<...> is strongly discouraged since it
381  * can unravel weird compiler bugs.
382  * Use of the mutable keyword is discouraged."
383  * The referred may have something to do with
384  * (http://gcc.gnu.org/ml/gcc-bugs/2007-12/msg01824.html)
385  * "for-loop iterate condition optimized away" posted by Darko Veberic
386  * "it seems that with -O2 and when foo is const class, the (it != foo.End())
387  * is optimized away as also const (equal true) and the loop does not end, runs
388  * over and (usually) produces segfault..."
389  *
390  * Quoting Meyers:
391  * "As a general rule, casting is such a bad idea, I've devoted an entire Item to telling you not
392  * to do it (Item 27), but code duplication is no picnic, either. In this case, the const version
393  * of operator[] does exactly what the non-const version does, it just has a const-qualified return type.
394  * Casting away the const on the return value is safe, in this case, because whoever called the non-const
395  * operator[] must have had a non-const object in the first place. Otherwise they couldn't have called
396  * a non-const function. So having the non-const operator[] call the const version is a safe way to
397  * avoid code duplication, even though it requires a cast."
398  *
399  * This usage is also favored in
400  * "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" By Herb Sutter, Andrei Alexandrescu.
401  * See item exceptions for "94. Avoid casting away const". There they avoid the static_cast thanks to
402  * a const reference variable, which may ease over-suspicious coders; anyway stick to Meyer's choice.
403  *
404  * The static_cast changes this type in order to resolve the desired overloaded method, which returns
405  * const, so the const_cast is used to cast away the constness of the returned reference.
406  */
407  return const_cast<C&>(static_cast<const ComponentGroup&>(*this).Get(id));
408  }
409 
410 
411  template<class P, class C, class Creator, class ManagerProvider>
412  bool
414  const
415  {
416  // Lazy init...
417  if (fComponentsIdsSet.empty()) {
418  // ...insert everything in the sequence to the set.
419  fComponentsIdsSet.insert(fComponentsIds.begin(), fComponentsIds.end());
420  }
421  return fComponentsIdsSet.find(i) != fComponentsIdsSet.end();
422  }
423 
424 }
425 
426 
427 #endif
C & operator()(const IdList::value_type &id) const
Converts the integral id to the object. Resolve the id through the container: Id it&#39;s an integer at t...
const C & operator()(const IdList::value_type &id) const
ComponentGroup(const P &p)
Construct with parent.
ComponentMap::const_iterator ComponentMapConstIterator
IdList::size_type SizeType
Type for number of components.
const ComponentGroup< P, C, Creator, ManagerProvider > & fContainer
The child doesn&#39;t actually receive the information from its parent upon construction.
Functor to convert id to Counter.
C ComponentType
The type of the contained component.
SizeType fNumberOfIds
The number of Ids. We keep the number of IDs separately because in a std::list the query for number i...
IdList::const_iterator IdIterator
Base class for exceptions trying to access non-existing components.
boost::transform_iterator< InternalConstFunctor, IdIterator, const C & > ConstIterator
Convenience alias for constant iterators over components.
Interface for detector managers.
Definition: VManager.h:115
InternalConstFunctor(const ComponentGroup< P, C, Creator, ManagerProvider > &p)
Const functor to convert id to Counter.
IdList fComponentsIds
List of contained ids.
Iterator End()
End iterator over components.
SizeType GetNumberOfComponents() const
Returns the number of components.
IdSet fComponentsIdsSet
Set of contained ids.
const C & Get(int i) const
Retrieve component by id.
ComponentMap fComponentsById
Id to object conversion map.
virtual Status GetData(double &returnData, const std::string &componentProperty, const std::string &componentName, const IndexMap &componentIndex) const =0
Iterator Begin()
Begin iterator over components.
constexpr double s
Definition: AugerUnits.h:163
void Update(const VManager::IndexMap &m, const bool invalidateData=true, const bool invalidateComponents=true)
Updates the components.
boost::ptr_map< int, C > ComponentMap
const P & fParent
The parent of the components.
bool Exists(int i) const
Check for existence by id.
ComponentMap::iterator ComponentMapIterator
ComponentGroup< P, C, Creator, ManagerProvider > & fContainer
Base class for group of detector components.
boost::transform_iterator< InternalFunctor, IdIterator, C & > Iterator
Convenience alias for iterators over components.
static void UpdateComponent(Component &c, bool invData, bool invComp)
Perform the update call.
std::map< std::string, std::string > IndexMap
Definition: VManager.h:133
static Child * CreateObject(int id, const Parent &)
InternalFunctor(ComponentGroup< P, C, Creator, ManagerProvider > &p)
Initialize with a reference to the containing object so as to have a reference to which invoke the Ge...
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
static Child * CreateObject(int id, const Parent &parent)
Simple struct to defer update call.
Status
Specifies success or (eventually) various possible failure modes.
Definition: VManager.h:127
The child the information from the parent upon construction.

, generated on Tue Sep 26 2023.