/cvmfs/atlas.cern.ch/repo/sw/ASG/AnalysisBase/2.4.28/AthContainers/AthContainers/DataVector.h File Reference

An STL vector of pointers that by default owns its pointed-to elements. More...

#include "AthContainers/exceptions.h"
#include "AthContainers/OwnershipPolicy.h"
#include "AthContainers/IndexTrackingPolicy.h"
#include "AthContainers/AuxVectorBase.h"
#include "AthContainers/tools/DVLNoBase.h"
#include "AthContainers/tools/DVLInfo.h"
#include "AthContainers/tools/DVLCast.h"
#include "AthContainers/tools/DVLIterator.h"
#include "AthContainers/tools/DVL_iter_swap.h"
#include "AthContainers/tools/DVL_algorithms.h"
#include "AthContainers/tools/ElementProxy.h"
#include "AthContainers/tools/IsMostDerivedFlag.h"
#include "AthLinks/tools/selection_ns.h"
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>
#include <typeinfo>
#include <functional>
#include <iostream>
#include <algorithm>
#include <stdexcept>
#include <iterator>
#include "SGTools/BaseInfo.h"
#include "AthContainers/ClassName.h"
#include "AthContainers/tools/DVLDataBucket.h"
#include "SGTools/DataBucketTraitFwd.h"
#include "AthContainers/DataVector.icc"

Go to the source code of this file.

Classes

struct  DataVectorBase< T >
 Derivation information for DataVector. More...
class  DataVector< T, BASE >
 Derived DataVector<T>. More...
class  DataVector< T, DataModel_detail::NoBase >
 Base specialization for DataVector<T>. More...
class  DataVector< T, BASE >
 Derived DataVector<T>. More...
class  ClassName< DataVector< T > >
 Specialization of ClassName for DataVector. More...
struct  SG::DataBucketTrait< DataVector< T >, U >
 Metafunction to find the proper DataBucket class for T. More...

Namespaces

namespace  SG
 

Constructor from a payload object.


Defines

#define HAVE_CONSTDATAVECTOR
#define DATAVECTOR_BASE(T, BASE)
 Declare base class info to DataVector. Single, non-virtual derivation.
#define DATAVECTOR_BASE_FWD(T, BASE)
 Version of DATAVECTOR_BASE that can be used in forward declarations.
#define DATAVECTOR_VIRTBASES1(T, B1)
 Declare base class info to DataVector. Single, virtual derivation.
#define DATAVECTOR_VIRTBASES1_FWD(T, B1)
 Version of DATAVECTOR_VIRTBASES1 that can be used in forward declarations.
#define DATAVECTOR_VIRTBASES2(T, B1, B2)
 Declare base class info to DataVector. Multiple derivation.
#define DATAVECTOR_VIRTBASES2_FWD(T, B1, B2)
 Version of DATAVECTOR_VIRTBASES2 that can be used in forward declarations.
#define DATAVECTOR_VIRTBASES3(T, B1, B2, B3)
 Declare base class info to DataVector. Multiple derivation.
#define DATAVECTOR_VIRTBASES3_FWD(T, B1, B2, B3)
 Version of DATAVECTOR_VIRTBASES3 that can be used in forward declarations.

Functions

template<class DV >
void test2_assignelement1 ()
template<class DV >
void test2_assignelement2 ()
template<class T >
bool operator== (const DataVector< T > &a, const DataVector< T > &b)
 Vector equality comparison.
template<class T >
bool operator!= (const DataVector< T > &a, const DataVector< T > &b)
 Based on operator==.
template<class T >
bool operator< (const DataVector< T > &a, const DataVector< T > &b)
 Vector ordering relation.
template<class T >
bool operator> (const DataVector< T > &a, const DataVector< T > &b)
 Based on operator<.
template<class T >
bool operator<= (const DataVector< T > &a, const DataVector< T > &b)
 Based on operator<.
template<class T >
bool operator>= (const DataVector< T > &a, const DataVector< T > &b)
 Based on operator<.
template<class T >
void swap (DataVector< T > &a, DataVector< T > &b)
 See DataVector<T, BASE>::swap().

Detailed Description

An STL vector of pointers that by default owns its pointed-to elements.

Author:
scott snyder, Paolo Calafiura, etc
Date:
May 2005; rewritten from earlier version. For further information, see <https://twiki.cern.ch/twiki/bin/viewauth/AtlasComputing/DataVector>

Introduction ============

A DataVector<T> acts like a std::vector<T*>, except that it can optionally manage the memory that it contains. The constructors take an (optional) extra argument, which can be either SG::OWN_ELEMENTS or SG::VIEW_ELEMENTS (defaulting to SG::OWN_ELEMENTS, except for a copy constructor). This tells whether the DataVector owns its contained elements or not.

Ownership issues ================

If a DataVector owns its elements, then they are deleted when the container itself is. Further, they are deleted by actions which erase elements from the container (i.e, erase(), pop_back()). A replacement (such as v[0] = new T ) will result in the old element being deleted and the container taking ownership of the new element. It is an error to assign directly between two owning containers (v1[0] = v2[0]). To remove an element from a container and acquire ownership, use swapElement.

Beware of ownership issues when you modify a DataVector. Obviously you should not delete explicitly a DataVector element. A DataVector should never have two elements pointing to the same object. This may seem obvious but certain std algorithms (e.g. remove_if) may leave a DataVector with two copies of the same element in the "left-over" range. To avoid a crash when clearing the vector (e.g. in the destructor we have introduced a $n\log n$ helper function that searches and removes duplicates in the DataVector. This is used by the destructor by clear() and by erase(first, last). As this may change in the future to improve performance, do not rely on this functionality and do avoid introducing duplicated elements in a DataVector.

All these cautions do not apply when a DataVector it is created with the flag SG::VIEW_ELEMENTS (see enum OwnershipPolicy) and hence does not own its elements. This is typically used to have DataVector elements allocated by DataPool. Otherwise consider the cleaner alternative of using a vector<T*>.

The interface for DataVector should be mostly compatible with that of std::vector. There are a few differences which should not make much difference in practice. For example, methods which would return a reference return a proxy object instead. Also value_type is used instead of const_reference; this is justified by the fact that the elements are always pointers.

Note that algorithms which modify their range may not work correctly if the container owns its contents. Specializations that work properly for DataVector are available for some algorithms. These include:

Alternately, for sort(), the sort() methods defined in DataVector may be used. Or do the sorting in a view DataVector or a plain std::vector.

There are a few other additions to the standard std::vector interface.

Note that since DataVector<T> has an element type of T*, it is not possible to directly insert a const T*. If you want to do that, see ConstDataVector. (In some cases, such as if the destination container is not being recorded in StoreGate, it may be more appropriate to simply use a std::vector<const T*>.) Don't just use a const_cast!

Inheritance ===========

DataVector's may inherit from one another. If you have class D which derives from class B, you can set things up so that DataVector<D> derives from DataVector<B>. This allows you do to the same sort of conversions on the DataVector's as on the element pointers themselves. The key to doing this is to add the declaration

   DATAVECTOR_BASE (D, B);

before using DataVector<D>. A few caveats about doing this. The pointers are actually stored in the base DataVector instance, and the type that stdcont returns will reflect this. For example, in the example given above, DataVector<D>::stdcont() will return a reference to std::vector<B*>. Second, in order to preserve the invariant that a DataVector<D> contains only elements that actually derive from D, while at the same time not requiring that the contained objects be polymorphic, there is a restriction that you cannot insert into a DataVector if you're not referring to it as the most derived type (even if such an insertion would not actually break the invariant). This is implemented as a runtime check.

Example:

   DataVector<D> vd;
   vd.push_back (new D);  // This is ok.
   vd.push_back (new B);  // This will give a compilation error
                             (it would break the invariant).
   DataVector<B>& vb = vd;
   vb.push_back (new B);  // This will give a run-time error
                             (it breaks the invariant).
   vb.push_back (new D);  // This will also give a run-time error.
                             (It's actually ok, but there's no good way
                             to distinguish it from the previous case.)

Note also this (related to a common atlas idiom). If we have the above, and also:

   class B_Vector : public DataVector<B> { ... };
   class D_Vector : public DataVector<D> { ... };

Then a D_Vector will be convertible to a DataVector<B>, but _not_ to a B_Vector.

Multiple and virtual inheritance are also supported. In this case, use DATAVECTOR_VIRTBASESn (where n is 1, 2, or 3) instead of DATAVECTOR_BASE. Example: Given:

   class M { ... };
   class N : virtual public M { ... };
   class O : virtual public M { ... };
   class P : virtual public N, virtual public O { ... };

declare this with

   DATAVECTOR_VIRTBASES1(N, M);
   DATAVECTOR_VIRTBASES1(O, M);
   DATAVECTOR_VIRTBASES2(P, N, O);

There is a restriction that there must be a unique base class that does not derive from anything else. For example, the diamond configuration above is ok, but this would not be:

   class L { ... };
   class M { ... };
   class N : virtual public M, virtual public L { ... };
   class O : virtual public M { ... };
   class P : virtual public N, virtual public O { ... };

   DATAVECTOR_VIRTBASES2(N, M, L);
   DATAVECTOR_VIRTBASES1(O, M);
   DATAVECTOR_VIRTBASES2(P, N, O);

Note, however, that you don't have to tell DataVector about the complete hierarchy; leaving the L out of DATAVECTOR_VIRTBASES would work (you just wouldn't be able to convert to DataVector<L>).

If you use DATAVECTOR_VIRTBASES, there is an additional time penalty to retrieve elements from the collection. This does not apply for DATAVECTOR_BASES.

All applicable DATAVECTOR_* macros must be visible at the point at which a DataVector is instantiated. A confusing compilation error is likely to result otherwise. Note that this means that if you have the DATAVECTOR_* macros within a container header file, then the header for the derived container must include the header for the base container. Be alert to this when converting existing code to use the inheritance scheme. For example, if class D2 derives from D which derives from B:

BVec.h:

  #include "B.h"
  #include "DataVector.h"
  typedef DataVector<B> BVec;

DVec.h:

  #include "D.h"
  #include "DataVector.h"
  DATAVECTOR_BASE(D,B);
  typedef DataVector<D> DVec;

D2Vec.h:

  #include "D2.h"
  #include "DataVector.h"
  #include "DVec.h" // This is required
  DATAVECTOR_BASE(D2,D);
  typedef DataVector<D2> DVec;

Using DATAVECTOR_BASE will also set up the corresponding SG::BaseInfo definitions, both for the vectors themselves and for the contained objects.

Auxiliary data ==============

A DataVector may also have `auxiliary data' associated with it. This is a set of name/value pairs that can be attached to each element of the vector. These data are stored in vectors that exist parallel to the DataVector; the exact way in which this managed is hidden behind an abstract interface.

We'll start with an example, and then go into more detail.

 class MyClass
   : public SG::AuxElement  // Derive from AuxElement to allow for aux data
 {
 public:
   // A getter for an aux data item.
   float foo() const
   { static ConstAccessor<float> acc ("foo");  return acc(*this); }

   // A setter for an aux data item.
   void foo(float x)
   { static Accessor<float> acc ("foo");  acc(*this) = x; }
 };

 ...

 // Create the vector and associate a store.
 DataVector<MyClass>* v = new DataVector<MyClass>;
 SG::AuxStoreInternal* store = new SG::AuxStoreInternal;
 v->setStore (store);

 // Add an item to the vector and set aux data on it.
 v->push_back (new MyClass);
 v[0]->foo() = 3;

 // Add a user-defined aux data item.
 MyClass::Accessor<int> x ("x");
 x(*v[0]) = 10;

 // Add a standalone store to an object.
 MyClass* c = new MyClass;
 c->makePrivateStore();
 c->foo() = 4;
 c->push_back (c); // Aux data will be transferred to the container.

In order to be able store auxiliary data in a container three things must hold. First, the container's payload type must derive from SG::AuxElement. Second, the container must have index tracking enabled. Third, the container must have an associated auxiliary data store. More about these below.

SG::AuxElement --------------

A type which may have associated auxiliary data must derive from the base class SG::AuxElement. This does a several things.

First, in order to be able to find auxiliary data from a pointer to a container element, the element must be able to know both the container that it's a member of and its index within that container. SG::AuxElement makes this information available with the container() and index() methods. This information is maintained as long as the container has index tracking enabled (see below).

Second, it provides an interface for getting/setting auxiliary data. The recommended way of doing this is through the nested Accessor and ConstAccessor classes; these allows caching the translation from attribute names to the internal representation. The difference between these two is that ConstAccessor allows only const access to the element, while Accessor, which derives from it, allows non-const access as well. Create an Accessor or ConstAccessor object with the data type (which can be anything that can be used within a std::vector) and a name. For Accessor, the resulting object can then be used both as an rvalue and a lvalue; for ConstAccessor, it can be used only as an rvalue.

  MyClass* c = ...;
  MyClass::Accessor<double> y ("y");
  y(*c) = 4;  // assign attribute.
  return y(*c);  // read attribute.

A given name must always be used with the same type, otherwise an exception will be thrown. In the case that you want to use the same name for different types in different classes, the name may be qualified with an optional class name:

  MyClass::ConstAccessor<double> y ("y", "MyClass");

If you have some auxiliary data items that are to be regarded as members of a class, it is recommended to define a setter and getter as in the example above.

If you need to operate on a particular auxiliary data item for all elements in a container, it will be more efficient to access the auxiliary data directly by index, rather than through the elements. This can be done like:

  DataVector<MyClass>* v = ...;
  MyClass::ConstAccesor<float> x ("x");
  size_t sz = v->size();
  for (size_t i = 0; i < sz; i++)
    do_something (x(*v, i));

Accessor and ConstAccessor also have getDataArray methods to directly return a pointer to the start of the auxiliary data array.

It is also possible to use the auxdata method to access auxiliary data directly. However, it is not recommended to do this inside a loop or anywhere where performance is important.

  c->auxdata<int> ("aux") = 5;  // set
  return c->auxdata<int> ("aux");  // retrieve

Decorations -----------

In addition, sometimes one wants to add additional auxiliary data to an existing, const container; this is called `decorating' it. For example, you might want to retrieve a const container from StoreGate, run some algorithm on it, and attach additional data to the object that can be accessed by downstream algorithms or written to a file. To support this, there is a Decorator object analogous to Accessor and ConstAccessor. The difference is that Decorator can operate on a const object and return a non-const reference.

To prevent modifying existing data, the contents of a container may be locked with the lock() call; this happens automatically when the container is made const with StoreGateSvc::setConst. Once a container is locked, Decorator will only succeed if either the variable does not yet exist (in which case it is created and marked as a decoration) or it is marked as a decoration.

Calling clearDecorations will erase all variables marked as decorations, restoring the state back to where it was when lock was called.

An auxdecor method is also available, analogous to auxdata.

Index tracking --------------

Recall that a DataVector either owns its elements or not. By default, a DataVector that owns its elements will update the container and index fields of the elements that it contains, while a view DataVector will not.

This rule does not always suffice, though. In particular, a DataVector that gets filled with elements from a DataPool does not own its elements but should track indices. For this reason, one can specify an index tracking policy separate from the ownership policy. Where DataVector takes an ownership policy, it can also take as the next argument an index tracking policy. This policy defaults to SG::DEFAULT_TRACK_INDICES, which means to set the indexing policy based on the ownership policy. But it can also be set to SG::ALWAYS_TRACK_INDICES or SG::NEVER_TRACK_INDICES to override this.

The current state of index tracking for a DataVector is returned by the trackIndices method. Like the ownership policy, it may be changed with the clear method.

Auxiliary store ---------------

DataVector does not itself manage the storage for auxiliary data. Instead, this is done by a separate _auxiliary store_ object. This store object implements either the interface SG::IConstAuxStore or SG::IAuxStore (which derives from it). The first of these provides operations needed to read data from the store, while the second adds operations needed to add to and modify the data in the store.

When you are create a DataVector object that is to have auxiliary data, you will also need to create the store object. A generic store object, which manages dynamic auxiliary data, is available, SG::AuxStoreInternal. There may also be specialized store implementations for particular data classes. Store implementations also exist that are specialized for use in root; in that case, the data are managed as part of a root tree, and the store object manages access to it.

  DataVector<MyClass>* v = new DataVector<MyClass>;
  CHECK( evtStore->record (v, "mykey") );
  SG::AuxStoreInternal* store = new SG::AuxStoreInternal;
  CHECK( evtStore->record (store, "mykeyAux.") );
  v->setStore (store);

You can only set a store if the container has index tracking enabled; otherwise, an exception will be thrown.

You should not have to explicitly deal with the auxiliary store for objects that are read from a file. The I/O system is responsible for getting the store association correct in that case.

Standalone objects ------------------

Normally, an element can only have associated auxiliary data if it is a member of a container; otherwise, there is no store in which to store the auxiliary data. However, it is possible to request that a store be created for an individual element not part of a container by calling the method makePrivateStore. You can then add auxiliary data to the object:

  MyClass* c = new MyClass;
  c->makePrivateStore();
  MyClass::Accessor<int> x ("x");
  x(*c) = 5;

If the element is then added to a container, the auxiliary data will be copied to the container's store, and the private store the was associated with the element will be released. The fact that there was a private store is remembered, however; if the element is later removed from the container (in a way that doesn't delete the element), the private store will be remade and the auxiliary data copied back from the container to the private store.

makePrivateStore can also take an argument. If provided, auxiliary data will be copied from it. This can be used to properly implement copy constructors:

  class MyStandaloneClass
    : public SG::AuxElement
  {
  public:
    MyStandaloneClass() { this->makePrivateStore(); }

    MyStandaloneClass (const MyStandaloneClass& other)
      SG::AuxElement (other)
    {
      this->makePrivateStore (other);
    }

As a shorthand, one can use the wrapper class SG::AuxElementComplete. This will add constructors that automatically make a private store:

  typedef SG::AuxElementComplete<MyClass> MyStandaloneClass;

A standalone object also has setStore methods that can be used to associate an external store with a since object, in the same manner as for containers.


Define Documentation

#define DATAVECTOR_BASE ( T,
BASE   ) 
Value:
DATAVECTOR_BASE_FWD(T, BASE);             \
template struct DataVector_detail::DVLEltBaseInit<T>

Declare base class info to DataVector. Single, non-virtual derivation.

DATAVECTOR_BASE(D, B) says that D derives non-virtually from B.

This macro creates an appropriate specialization of DataVectorBase.

#define DATAVECTOR_BASE_FWD ( T,
BASE   ) 
Value:
template <> struct DataVectorBase<T>      \
{ typedef DataVector<BASE> Base; };       \
SG_BASE(DataVector<T>, DataVector<BASE>)

Version of DATAVECTOR_BASE that can be used in forward declarations.

#define DATAVECTOR_VIRTBASES1 ( T,
B1   ) 
Value:
DATAVECTOR_VIRTBASES1_FWD(T, B1);                     \
template struct DataVector_detail::DVLEltBaseInit<T>

Declare base class info to DataVector. Single, virtual derivation.

DATAVECTOR_VIRTBASES1(D, B1) says that D derives virtually from B1.

This macro creates an appropriate specialization of DataVectorBase.

#define DATAVECTOR_VIRTBASES1_FWD ( T,
B1   ) 
Value:
template <> struct DataVectorBase<T>                  \
{ typedef DataVector_detail::VirtBases<B1> Base; };   \
SG_BASES1(DataVector<T>, SG_VIRTUAL(DataVector<B1>))

Version of DATAVECTOR_VIRTBASES1 that can be used in forward declarations.

#define DATAVECTOR_VIRTBASES2 ( T,
B1,
B2   ) 
Value:
DATAVECTOR_VIRTBASES2_FWD(T, B1, B2);                   \
template struct DataVector_detail::DVLEltBaseInit<T>

Declare base class info to DataVector. Multiple derivation.

DATAVECTOR_VIRTBASES2(D, B1, B2) says that D derives from both B1 and B2.

This macro creates an appropriate specialization of DataVectorBase.

#define DATAVECTOR_VIRTBASES2_FWD ( T,
B1,
B2   ) 
Value:
template <> struct DataVectorBase<T>                    \
{ typedef DataVector_detail::VirtBases<B1, B2> Base; }; \
SG_BASES2(DataVector<T>, SG_VIRTUAL(DataVector<B1>),    \
                         SG_VIRTUAL(DataVector<B2>))

Version of DATAVECTOR_VIRTBASES2 that can be used in forward declarations.

#define DATAVECTOR_VIRTBASES3 ( T,
B1,
B2,
B3   ) 
Value:
DATAVECTOR_VIRTBASES3_FWD(T, B1, B2, B3);               \
template struct DataVector_detail::DVLEltBaseInit<T>

Declare base class info to DataVector. Multiple derivation.

DATAVECTOR_VIRTBASES3(D, B1, B2, B3) says that D derives from all of B1, B2, and B3.

This macro creates an appropriate specialization of DataVectorBase.

#define DATAVECTOR_VIRTBASES3_FWD ( T,
B1,
B2,
B3   ) 
Value:
template <> struct DataVectorBase<T>                        \
{ typedef DataVector_detail::VirtBases<B1, B2, B3> Base; }; \
SG_BASES3(DataVector<T>, SG_VIRTUAL(DataVector<B1>),        \
                         SG_VIRTUAL(DataVector<B2>),        \
                         SG_VIRTUAL(DataVector<B3>))

Version of DATAVECTOR_VIRTBASES3 that can be used in forward declarations.


Function Documentation

template<class T >
bool operator< ( const DataVector< T > &  a,
const DataVector< T > &  b 
) [inline]

Vector ordering relation.

Parameters:
a A DataVector.
b A DataVector of the same type as x.
Returns:
True iff x is lexicographically less than y.

This is a total ordering relation. It is linear in the size of the vectors. Comparisons are done on the pointer values of the elements.

See std::lexicographical_compare() for how the determination is made.

template<class T >
bool operator== ( const DataVector< T > &  a,
const DataVector< T > &  b 
) [inline]

Vector equality comparison.

Parameters:
a A DataVector.
b A DataVector of the same type as x.
Returns:
True iff the size and elements of the vectors are equal.

This is an equivalence relation. It is linear in the size of the vectors. Vectors are considered equivalent if their sizes are equal, and if corresponding elements compare equal.

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 15 Apr 2017 for RootCore Packages by  doxygen 1.6.1