An STL list of pointers that by default owns its pointed-to elements. More...
#include <list>
#include <typeinfo>
#include <functional>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include "SGTools/BaseInfo.h"
#include "SGTools/DataBucketTraitFwd.h"
#include "SGTools/ClassName.h"
#include "AthContainers/OwnershipPolicy.h"
#include "AthContainers/exceptions.h"
#include "AthContainers/tools/DVLNoBase.h"
#include "AthContainers/tools/DVLInfo.h"
#include "AthContainers/tools/DVLDataBucket.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 "AthContainers/DataList.icc"
Go to the source code of this file.
Classes | |
struct | DataListBase< T > |
Derivation information for DataList . More... | |
class | DataList< T, BASE > |
Derived DataList<T> . More... | |
class | DataList< T, DataModel_detail::NoBase > |
Base specialization for DataList<T> . More... | |
class | ClassName< DataList< T > > |
Specialization of ClassName for DataList . More... | |
class | DataList< T, BASE > |
Derived DataList<T> . More... | |
struct | SG::DataBucketTrait< DataList< 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 | DATALIST_BASE(T, BASE) |
Declare base class info to DataList . Single, non-virtual derivation. | |
#define | DATALIST_VIRTBASES1(T, B1) |
Declare base class info to DataList . Single, virtual derivation. | |
#define | DATALIST_VIRTBASES2(T, B1, B2) |
Declare base class info to DataList . Multiple derivation. | |
#define | DATALIST_VIRTBASES3(T, B1, B2, B3) |
Declare base class info to DataList . Multiple derivation. | |
Functions | |
template<class DL > | |
void | test2_assignelement1 () |
template<class T > | |
bool | operator== (const DataList< T > &a, const DataList< T > &b) |
List equality comparison. | |
template<class T > | |
bool | operator!= (const DataList< T > &a, const DataList< T > &b) |
Based on operator==. | |
template<class T > | |
bool | operator< (const DataList< T > &a, const DataList< T > &b) |
List ordering relation. | |
template<class T > | |
bool | operator> (const DataList< T > &a, const DataList< T > &b) |
Based on operator<. | |
template<class T > | |
bool | operator<= (const DataList< T > &a, const DataList< T > &b) |
Based on operator<. | |
template<class T > | |
bool | operator>= (const DataList< T > &a, const DataList< T > &b) |
Based on operator<. | |
template<class T > | |
void | swap (DataList< T > &a, DataList< T > &b) |
See DataList<T, BASE>::swap() . |
An STL list of pointers that by default owns its pointed-to elements.
A DataList<T>
acts like a std::list<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 DataList
owns its contained elements or not.
If a DataList
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 (*l.front()) = 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 ( (*list1.front()) = (*list2.front());
).
Beware of ownership issues when modify a DataList
. Obviously you should not delete explicitly a DataList
element (because this is already taken care of by this object). A DataList
should never have two elements pointing to the same object. This may seem obvious but certain STL algorithms (eg: remove_if
) may leave a DataList
with two copies of the same element in the "left-over" range. To avoid a crash when clearing the list (eg: in the destructor we have introduced a helper function that searches and removes duplicates in the DataList
. 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 DataList
.
All these cautions do not apply when a DataList
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 DataList
elements allocated by DataPool
. Otherwise consider the cleaner alternative of using a list<T*>
.
The interface for DataList
should be mostly compatible with that of std::list
. 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 DataList
are available for some algorithms. These include:
std::remove
std::remove_if
std::unique
std::reverse
std::rotate
std::partition
std::stable_partition
There are a few other additions to the standard std::list
interface.
stdcont
may be used to get access to the underlying std::list
representation.PtrList
is the type of the underlying std::List
. BaseContainer
is a synonym for this.ownPolicy
returns the ownership policy of the container.clear()
is provided that takes as an argument a new ownership policy for the container. This is the only way to change the ownership policy.Note that since DataList<T>
has an element type of T*
, it is not possible to directly insert a const T*
. If you want to do that, see ConstDataList
. (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::list<const T*>
.) Don't just use a const_cast!
Finally, DataList's
may inherit from one another. If you have class D
which derives from class B
, you can set things up so that DataList<D>
derives from DataList<B>
. This allows you do to the same sort of conversions on the DataList's
as on the element pointers themselves. The key to doing this is to add the declaration
DATALIST_BASE (D, B);
before using DataList<D>
. A few caveats about doing this. The pointers are actually stored in the base DataList
instance, and the type that stdcont
returns will reflect this. For example, in the example given above, DataList<D>::stdcont()
will return a reference to std::list<B*>. Second, in order to preserve the invariant that a DataList<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 DataList
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:
DataList<D> ld; ld.push_back (new D); // This is ok. ld.push_back (new B); // This will give a compilation error (it would break the invariant). DataList<B>& lb = ld; lb.push_back (new B); // This will give a run-time error (it breaks the invariant). lb.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:
Then a D_List
will be convertible to a DataList<B>, but _not_ to a B_List
.
Multiple and virtual inheritance are also supported. In this case, use DATALIST_VIRTBASES
n (where n is 1, 2, or 3) instead of DATALIST_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
DATALIST_VIRTBASES1(N, M); DATALIST_VIRTBASES1(O, M); DATALIST_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 { ... }; DATALIST_VIRTBASES2(N, M, L); DATALIST_VIRTBASES1(O, M); DATALIST_VIRTBASES2(P, N, O);
Note, however, that you don't have to tell DataList
about the complete hierarchy; leaving the L
out of DATALIST_VIRTBASES
would work (you just wouldn't be able to convert to DataList<L>
).
If you use DATALIST_VIRTBASES
, there is an additional time penalty to retrieve elements from the collection. This does not apply for DATALIST_BASES
.
All applicable DATALIST_*
macros must be visible at the point at which a DataList
is instantiated. A confusing compilation error is likely to result otherwise. Note that this means that if you have the DATALIST_*
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:
BList.h:
#include "B.h" #include "DataList.h" typedef DataList<B> BVec;
DList.h:
#include "D.h" #include "DataList.h" DATALIST_BASE(D,B); typedef DataList<D> DVec;
D2List.h:
#include "D2.h" #include "DataList.h" #include "DList.h" // This is required DATALIST_BASE(D2,D); typedef DataList<D2> DVec;
Using DATALIST_BASE
will also set up the corresponding SG::BaseInfo
definitions, both for the vectors themselves and for the contained objects.
#define DATALIST_BASE | ( | T, | |||
BASE | ) |
template <> struct DataListBase<T> \ { typedef DataList<BASE> Base; }; \ SG_BASE(DataList<T>, DataList<BASE>); \ template struct DataList_detail::DVLEltBaseInit<T>
Declare base class info to DataList
. Single, non-virtual derivation.
DATALIST_BASE(D, B)
says that D
derives non-virtually from B
.
This macro creates an appropriate specialization of DataListBase
.
#define DATALIST_VIRTBASES1 | ( | T, | |||
B1 | ) |
template <> struct DataListBase<T> \ { typedef DataList_detail::VirtBases<B1> Base; }; \ SG_BASES1(DataList<T>, SG_VIRTUAL(DataList<B1>)); \ template struct DataList_detail::DVLEltBaseInit<T>
Declare base class info to DataList
. Single, virtual derivation.
DATALIST_VIRTBASES(D, B1)
says that D
derives virtually from B1
.
This macro creates an appropriate specialization of DataListBase
.
#define DATALIST_VIRTBASES2 | ( | T, | |||
B1, | |||||
B2 | ) |
template <> struct DataListBase<T> \ { typedef DataList_detail::VirtBases<B1, B2> Base; }; \ SG_BASES2(DataList<T>, SG_VIRTUAL(DataList<B1>), \ SG_VIRTUAL(DataList<B2>)); \ template struct DataList_detail::DVLEltBaseInit<T>
Declare base class info to DataList
. Multiple derivation.
DATALIST_VIRTBASES(D, B1)
says that D
derives from both B1
and B2
.
This macro creates an appropriate specialization of DataListBase
.
#define DATALIST_VIRTBASES3 | ( | T, | |||
B1, | |||||
B2, | |||||
B3 | ) |
template <> struct DataListBase<T> \ { typedef DataList_detail::VirtBases<B1, B2, B3> Base; }; \ SG_BASES3(DataList<T>, SG_VIRTUAL(DataList<B1>), \ SG_VIRTUAL(DataList<B2>), \ SG_VIRTUAL(DataList<B3>)); \ template struct DataList_detail::DVLEltBaseInit<T>
Declare base class info to DataList
. Multiple derivation.
DATALIST_VIRTBASES(D, B1)
says that D
derives from all of B1
, B2
, and B3
.
This macro creates an appropriate specialization of DataListBase
.
List ordering relation.
This is a total ordering relation. It is linear in the size of the lists. Comparisons are done on the pointer values of the elements.
See std::lexicographical_compare()
for how the determination is made.
This is a total ordering relation. It is linear in the size of the lists. Comparisons are done on the pointer values of the elements.
See std::lexicographical_compare()
for how the determination is made.
List equality comparison.
This is an equivalence relation. It is linear in the size of the lists. Lists are considered equivalent if their sizes are equal, and if corresponding elements compare equal.
This is an equivalence relation. It is linear in the size of the lists. Lists are considered equivalent if their sizes are equal, and if corresponding elements compare equal.