Belle II Software  release-08-01-10
RelationArray.h
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #pragma once
10 
11 #include <framework/datastore/DataStore.h>
12 #include <framework/datastore/StoreAccessorBase.h>
13 #include <framework/utilities/ArrayIterator.h>
14 #include <framework/dataobjects/RelationElement.h>
15 #include <framework/dataobjects/RelationContainer.h>
16 #include <framework/logging/Logger.h>
17 
18 namespace Belle2 {
23  template <class T> class StoreArray;
24 
63  public:
66 
69 
72 
82  };
83 
88  typedef std::pair<index_type, bool> consolidation_type;
89 
94  struct Identity {
96  consolidation_type operator()(index_type old) const { return std::make_pair(old, false); }
97  };
98 
104  template < class MapType = std::map<index_type, consolidation_type> > class ReplaceMap {
105  public:
106 
108  explicit ReplaceMap(MapType& replace): m_replace(replace) {}
109 
112  {
113  typename MapType::const_iterator iter = m_replace.find(old);
114  if (iter != m_replace.end()) {
115  return iter->second;
116  }
117  return std::make_pair(old, false);
118  }
119 
120  private:
121 
123  MapType& m_replace;
124  };
125 
126 
132  template < class VecType = std::vector<consolidation_type> > class ReplaceVec {
133  public:
134 
136  explicit ReplaceVec(VecType& replace): m_replace(replace) {}
137 
139  consolidation_type operator()(index_type old) const { return m_replace[old]; }
140 
141  private:
142 
144  VecType& m_replace;
145  };
146 
147 
153  bool create(bool replace = false)
154  {
155  bool result = DataStore::Instance().createObject(0, replace, *this);
156  m_relations = reinterpret_cast<RelationContainer**>(DataStore::Instance().getObject(*this));
157  if (result) {
158  (*m_relations)->setFromName(m_accessorFrom.first);
159  (*m_relations)->setFromDurability(m_accessorFrom.second);
160  (*m_relations)->setToName(m_accessorTo.first);
161  (*m_relations)->setToDurability(m_accessorTo.second);
162  }
163  return result;
164  }
165 
178  template <class FROM, class TO> RelationArray(const StoreArray<FROM>& from, const StoreArray<TO>& to, const std::string& name = "",
180  StoreAccessorBase(name.empty() ? DataStore::relationName(from.getName(), to.getName()) : name, durability,
181  RelationContainer::Class(), false),
184  m_relations(0)
185  {
186  if (m_accessorFrom.second > m_durability || m_accessorTo.second > m_durability) {
187  B2FATAL("Tried to create RelationArray '" << m_name << "' with a durability larger than the StoreArrays it relates");
188  }
189  }
190 
198  RelationArray(const AccessorParams& fromAccessor, const AccessorParams& toAccessor,
200  StoreAccessorBase(DataStore::relationName(fromAccessor.first, toAccessor.first), durability, RelationContainer::Class(), false),
201  m_accessorFrom(fromAccessor),
202  m_accessorTo(toAccessor),
203  m_relations(nullptr)
204  {
205  if (m_accessorFrom.second > m_durability || m_accessorTo.second > m_durability) {
206  B2FATAL("Tried to create RelationArray '" << m_name << "' with a durability larger than the StoreArrays it relates");
207  }
208  }
209 
218  explicit RelationArray(const std::string& name, DataStore::EDurability durability = DataStore::c_Event):
219  StoreAccessorBase(name, durability, RelationContainer::Class(), false),
220  m_relations(0)
221  {
222  if (name.empty()) {
223  B2FATAL("Cannot guess relation name, please supply correct name");
224  }
225  }
226 
229 
234  inline bool isValid() const { ensureAttached(); return m_relations && *m_relations;}
236  inline operator bool() const { return isValid(); }
237 
239  const RelationElement& operator[](int i) const { assertValid(); return (*m_relations)->getElement(i);}
240 
242  int getEntries() const { return isValid() ? ((*m_relations)->getEntries()) : 0; }
243 
246  {
247  ensureAttached();
248  if (m_accessorFrom.first.empty())
249  B2FATAL("trying to get accessor params from non-existing relation (this is likely a framework bug)");
250  return m_accessorFrom;
251  }
252 
255  {
256  ensureAttached();
257  if (m_accessorTo.first.empty())
258  B2FATAL("trying to get accessor params from non-existing relation (this is likely a framework bug)");
259  return m_accessorTo;
260  }
261 
263  bool getModified() const { assertValid(); return (*m_relations)->getModified(); }
264 
266  void setModified(bool modified) { assertCreated(); (*m_relations)->setModified(modified); }
267 
269  void clear() override
270  {
271  setModified(true);
272  (*m_relations)->elements().Delete();
273  }
274 
281  void add(index_type from, index_type to, weight_type weight = 1.0)
282  {
283  setModified(true);
284  new (next()) RelationElement(from, to, weight);
285  }
286 
293  void add(index_type from, const std::vector<index_type>& to, weight_type weight = 1.0)
294  {
295  setModified(true);
296  std::vector<weight_type> weights(to.size(), weight);
297  new (next()) RelationElement(from, to, weights);
298  }
299 
306  void add(index_type from, const std::vector<index_type>& to, const std::vector<weight_type>& weights)
307  {
308  setModified(true);
309  new (next()) RelationElement(from, to, weights);
310  }
311 
320  template <class InputIterator> void add(index_type from, const InputIterator& begin, const InputIterator& end)
321  {
322  setModified(true);
323  new (next()) RelationElement(from, begin, end);
324  }
325 
331  void consolidate() { consolidate<Identity, Identity>(); }
332 
363  template<class FunctionFrom, class FunctionTo> void consolidate(const
364  FunctionFrom& replaceFrom = FunctionFrom(), const FunctionTo &
365  replaceTo = FunctionTo(), EConsolidationAction action =
366  c_doNothing);
367 
369  const_iterator begin() const { assertValid(); return const_iterator((*m_relations)->elements(), 0); }
371  const_iterator end() const { assertValid(); return const_iterator((*m_relations)->elements(), getEntries()); }
372 
373  private:
381  explicit RelationArray(const AccessorParams& params):
382  StoreAccessorBase(params.first, params.second, RelationContainer::Class(), false),
383  m_relations(0)
384  {
385  if (params.first.empty()) {
386  B2FATAL("Cannot guess relation name, please supply correct name");
387  }
388  }
389 
390 
393  {
394  int index = (*m_relations)->elements().GetLast() + 1;
395  return static_cast<RelationElement*>((*m_relations)->elements().AddrAt(index));
396  }
397 
399  void checkRelation(const std::string& direction, const AccessorParams& array, const AccessorParams& rel) const
400  {
401  if (array.second == 0 && array.first.empty())
402  return; //no information to check against...
403 
404  if (array != rel) {
405  B2FATAL("Relation '" << m_name << "' exists but points " << direction << " wrong array:"
406  << " requested " << array.first << "(" << array.second << ")"
407  << ", got " << rel.first << "(" << rel.second << ")"
408  );
409  }
410  }
411 
413  void ensureAttached() const
414  {
415  if (m_relations)
416  return;
417 
418  const_cast<RelationArray*>(this)->m_relations = reinterpret_cast<RelationContainer**>(DataStore::Instance().getObject(*this));
419  if (m_relations && *m_relations && !(*m_relations)->isDefaultConstructed()) {
420  AccessorParams fromAccessorRel((*m_relations)->getFromName(), (DataStore::EDurability)(*m_relations)->getFromDurability());
421  AccessorParams toAccessorRel((*m_relations)->getToName(), (DataStore::EDurability)(*m_relations)->getToDurability());
422  //set if unset
423  if (m_accessorFrom.first.empty())
424  const_cast<RelationArray*>(this)->m_accessorFrom = fromAccessorRel;
425  if (m_accessorTo.first.empty())
426  const_cast<RelationArray*>(this)->m_accessorTo = toAccessorRel;
427  checkRelation("from", m_accessorFrom, fromAccessorRel);
428  checkRelation("to", m_accessorTo, toAccessorRel);
429  } else {
430  //no relation found, mark as invalid
431  const_cast<RelationArray*>(this)->m_relations = nullptr;
432  }
433  }
434 
436  void assertValid() const { if (!isValid()) B2FATAL("RelationArray does not point to valid StoreObject"); }
437 
443  {
444  if (!isValid()) {
445  if (!create()) {
446  B2FATAL("Couldn't create relation " << m_name << "!");
447  }
448  }
449  }
450 
453 
456 
459 
460  template<class FROM, class TO> friend class RelationIndex;
461  template<class FROM, class TO> friend class RelationIndexContainer;
462 
463  };
464 
465  template<class FunctionFrom, class FunctionTo>
466  void RelationArray::consolidate(const FunctionFrom& replaceFrom, const FunctionTo& replaceTo, EConsolidationAction action)
467  {
468  if (!isValid()) {
469  B2ERROR("Cannot consolidate an invalid relation (" << m_name << ")");
470  return;
471  }
472  typedef std::map<index_type, weight_type> element_t;
473  typedef std::map<index_type, element_t > buffer_t;
474  buffer_t buffer;
475 
476  //Fill all existing elements in a nested map, adding the weights of
477  //duplicate elements
478  index_type lastFromIndex(0);
479  buffer_t::iterator lastFromIter = buffer.end();
480  unsigned int nElements = (*m_relations)->getEntries();
481  TClonesArray& elements = (*m_relations)->elements();
482  for (unsigned int i = 0; i < nElements; ++i) {
483  RelationElement& element = *static_cast<RelationElement*>(elements[i]);
484  //Replace from index
485  consolidation_type from = replaceFrom(element.getFromIndex());
486 
487  //Ignore whole element if original element got deleted
488  if (action == c_deleteElement && from.second) continue;
489 
490  //Check if the fromIndex is the same as the last one and reuse
491  //iterator if possible
492  if (from.first != lastFromIndex || lastFromIter == buffer.end()) {
493  lastFromIter = buffer.insert(make_pair(from.first, element_t())).first;
494  lastFromIndex = from.first;
495  }
496  //Loop over all elements of this relationelement and add them to the map
497  size_t size = element.getSize();
498  for (size_t j = 0; j < size; ++j) {
499  //Replace to Index
500  consolidation_type to = replaceTo(element.getToIndex(j));
501  //Ignore whole element if original element got deleted
502  if (action == c_deleteElement && to.second) continue;
503  double weight = element.getWeight(j);
504  //Original from or to element got deleted. Do whatever is specified by action
505  //Warning: if there is more than one element pointing to the same
506  //from->to element after transformation the negative weight option is
507  //not safe as we sum a positive and a negative weight when
508  //consolidating.
509  if (from.second || to.second) {
510  if (action == c_zeroWeight) {
511  weight = 0;
512  } else if (action == c_negativeWeight && weight > 0) {
513  weight = -weight;
514  }
515  }
516  //add the weight to the new from->to index pair
517  lastFromIter->second[to.first] += weight;
518  }
519  }
520  //Clear the existing relation
521  elements.Delete();
522  //Fill the map into the relation
523  for (buffer_t::iterator iter = buffer.begin(); iter != buffer.end(); ++iter) {
524  add(iter->first, iter->second.begin(), iter->second.end());
525  }
526  }
527 
529 } // end namespace Belle2
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:51
EDurability
Durability types.
Definition: DataStore.h:58
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
bool createObject(TObject *object, bool replace, const StoreAccessorBase &accessor)
Create a new object/array in the DataStore or add an existing one.
Definition: DataStore.cc:316
TObject ** getObject(const StoreAccessorBase &accessor)
Get a pointer to a pointer of an object in the DataStore.
Definition: DataStore.cc:306
Optimizes class to iterate over TObjArray and classes inheriting from it.
Definition: ArrayIterator.h:23
Struct to replace indices based on a map-like container.
ReplaceMap(MapType &replace)
Set reference to used replacement map.
consolidation_type operator()(index_type old) const
Take old index and return the new index.
MapType & m_replace
Reference of the used replacement map.
Struct to replace indices based on a sequential container.
VecType & m_replace
Reference of the used replacement vector.
consolidation_type operator()(index_type old) const
Take old index and return the new index.
ReplaceVec(VecType &replace)
Set reference to used replacement vector.
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:62
bool getModified() const
Get modified flag of underlying container.
ObjArrayIterator< const TClonesArray, const RelationElement > const_iterator
STL-like const_iterator over the T objects (not T* ).
Definition: RelationArray.h:65
const_iterator begin() const
Return const_iterator to first entry.
AccessorParams m_accessorTo
Accessor params for to array.
RelationArray(const StoreArray< FROM > &from, const StoreArray< TO > &to, const std::string &name="", DataStore::EDurability durability=DataStore::c_Event)
Constructor which takes both store arrays and performs some sanity checks on the relation.
const AccessorParams & getFromAccessorParams() const
Return the AccessorParams the attached relation points from.
void checkRelation(const std::string &direction, const AccessorParams &array, const AccessorParams &rel) const
Check that the AccessorParams stored in the relation and the one given to the constructor are the sam...
RelationContainer ** m_relations
Pointer that actually holds the relations.
void ensureAttached() const
Attach to relation, if necessary.
const RelationElement & operator[](int i) const
Imitate array functionality.
void add(index_type from, const std::vector< index_type > &to, weight_type weight=1.0)
Add a new element to the relation.
bool isValid() const
Check whether the object was created.
std::pair< index_type, bool > consolidation_type
Typedef declaring the return value of any consolidation mapping.
Definition: RelationArray.h:88
const AccessorParams & getToAccessorParams() const
Return the AccessorParams the attached relation points to.
void consolidate()
Consolidate Relation Elements.
RelationElement::index_type index_type
Typedef to simplify use of correct index_type.
Definition: RelationArray.h:68
EConsolidationAction
Modification actions for the consolidate member.
Definition: RelationArray.h:77
@ c_negativeWeight
Flip the sign of the weight to become negative if the original element got re-attributed.
Definition: RelationArray.h:79
@ c_zeroWeight
Set the weight of the relation to 0 if the original element got re-attributed.
Definition: RelationArray.h:80
@ c_deleteElement
Delete the whole relation element if the original element got re-attributed.
Definition: RelationArray.h:81
@ c_doNothing
Do nothing, just treat it as reordering.
Definition: RelationArray.h:78
~RelationArray()
Empty destructor.
void setModified(bool modified)
Set modified flag of underlying container.
void add(index_type from, const InputIterator &begin, const InputIterator &end)
Add a new element to the relation.
void add(index_type from, const std::vector< index_type > &to, const std::vector< weight_type > &weights)
Add a new element to the relation.
int getEntries() const
Get the number of elements.
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
RelationElement::weight_type weight_type
Typedef to simplify use of correct weight_type.
Definition: RelationArray.h:71
RelationArray(const AccessorParams &fromAccessor, const AccessorParams &toAccessor, DataStore::EDurability durability=DataStore::c_Event)
Constructor with AccessorParams for from- and to-side.
RelationArray(const AccessorParams &params)
Constructor which accepts the AccessorParams of the relation.
RelationArray(const std::string &name, DataStore::EDurability durability=DataStore::c_Event)
Constructor which only accepts name and durability of the relation.
const_iterator end() const
Return const_iterator to last entry +1.
void assertCreated()
Create relation, if necessary.
bool create(bool replace=false)
Create an empty relation array in the data store.
AccessorParams m_accessorFrom
Accessor params for from array.
void clear() override
Clear all elements from the relation.
RelationElement * next()
Return address where the next RelationElement should be created.
void assertValid() const
check that pointer exits, otherwise bail out.
Class to store relations between StoreArrays in the DataStore.
bool isDefaultConstructed() const
Returns true if no information was set yet or Clear() was called.
void setFromName(const std::string &name)
Set name of the StoreArray we relate from.
Class to store a single element of a relation.
unsigned int index_type
type used for indices.
float weight_type
type used for weights.
Class to store a bidirectional index between two StoreArrays.
Provides access to fast ( O(log n) ) bi-directional lookups on a specified relation.
Definition: RelationIndex.h:76
Base class for StoreObjPtr and StoreArray for easier common treatment.
DataStore::EDurability m_durability
Store durability under which the object/array is saved.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
AccessorParams getAccessorParams() const
Return pair of name and durability under which stored object is saved.
std::string m_name
Store name under which this object/array is saved.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
std::pair< std::string, DataStore::EDurability > AccessorParams
Pair of parameters needed to find an object in the DataStore.
Abstract base class for different kinds of events.
Struct for identity transformation on indices.
Definition: RelationArray.h:94
consolidation_type operator()(index_type old) const
Take old index and return the new index.
Definition: RelationArray.h:96