Comparison of the PODIO Collection
s with a C++ named requirement Container.
The PODIO Collection
s interface was designed to mimic the standard Container interface, in particular std::vector
. Perfect compliance with the Container is not achieved as the Collection
s are concerned with additional semantics such as mutable/immutable element access, associations and relations, and IO which that are not part of Container.
On the implementation level most of the differences with respect to the Container comes from the fact that in order to satisfy the additional semantics a Collection
doesn't directly store user layer objects. Instead, data layer objects are stored and user layer objects are constructed and returned when needed. Similarly, the Collection
iterators operate on the user layer objects but don't expose Collection
's storage directly to the users. Instead, they construct and return user layer objects when needed.
In other words, a Collection
utilizes the user layer type as a reference type instead of using plain references (&
or &&
) to stored data layer types.
As a consequence some of the standard algorithms may not work with PODIO Collection
iterators. See standard algorithm documentation below.
The following tables list the compliance of a PODIO generated collection with the Container named requirement, stating which member types, interfaces, or concepts are fulfilled and which are not. Additionally, there are some comments explaining missing parts or pointing out differences in behaviour.
Name | Type | Requirements | Fulfilled by Collection? | Comment |
---|---|---|---|---|
value_type |
T |
Erasable | ✔️ yes | Defined as immutable component type |
reference |
T& |
❌ no | Not defined | |
const_reference |
const T& |
❌ no | Not defined | |
iterator |
Iterator whose value_type is T |
LegacyForwardIterator convertible to const_iterator |
❌ no | Defined as podio MutableCollectionIterator . iterator::value_type not defined, not LegacyForwardIterator (see below), not convertible to const_iterator |
const_iterator |
Constant iterator whose value_type is T |
LegacyForwardIterator | ❌ no | Defined as podio CollectionIterator . const_iterator::value_type not defined, not LegacyForwardIterator (see below) |
difference_type |
Signed integer | Must be the same as std::iterator_traits::difference_type for iterator and const_iterator |
❌ no | std::iterator_traits::difference_type not defined |
size_type |
Unsigned integer | Large enough to represent all positive values of difference_type |
✔️ yes |
Expression | Return type | Semantics | Fulfilled by Collection? | Comment |
---|---|---|---|---|
C() |
C |
Creates an empty container | ✔️ yes | |
C(a) |
C |
Creates a copy of a |
❌ no | Not defined, non-copyable by design |
C(rv) |
C |
Moves rv |
✔️ yes | |
a = b |
C& |
Destroys or copy-assigns all elements of a from elements of b |
❌ no | Not defined, non-copyable by design |
a = rv |
C& |
Destroys or move-assigns all elements of a from elements of rv |
✔️ yes | |
a.~C() |
void |
Destroys all elements of a and frees all memory |
✔️ yes | Invalidates all handles retrieved from this collection |
a.begin() |
(const_)iterator |
Iterator to the first element of a |
✔️ yes | |
a.end() |
(const_)iterator |
Iterator to one past the last element of a |
✔️ yes | |
a.cbegin() |
const_iterator |
Same as const_cast<const C&>(a).begin() |
✔️ yes | |
a.cend() |
const_iterator |
Same as const_cast<const C&>(a).end() |
✔️ yes | |
a == b |
Convertible to bool |
Same as std::equal(a.begin(), a.end(), b.begin(), b.end()) |
❌ no | Not defined |
a != b |
Convertible to bool |
Same as !(a == b) |
❌ no | Not defined |
a.swap(b) |
void |
Exchanges the values of a and b |
❌ no | Not defined |
swap(a,b) |
void |
Same as a.swap(b) |
❌ no | a.swap(b) not defined |
a.size() |
size_type |
Same as std::distance(a.begin(), a.end()) |
✔️ yes | |
a.max_size() |
size_type |
b.size() where b is the largest possible container |
✔️ yes | |
a.empty() |
Convertible to bool |
Same as a.begin() == a.end() |
✔️ yes |
The C++ standard specifies AllocatorAwareContainer for containers that can use other allocators beside the default allocator.
PODIO collections don't provide a customization point for allocators and use only the default allocator. Therefore they are not AllocatorAwareContainers.
Name | Requirements | Fulfilled by Collection? | Comment |
---|---|---|---|
allocator_type |
allocator_type::value_type same as value_type |
❌ no | allocator_type not defined |
The PODIO Collections currently are not checked against expression and statements requirements for AllocatorAwareContainer.
The C++ specifies a set of named requirements for iterators. Starting with C++20 the standard specifies also iterator concepts. The requirements imposed by the concepts and named requirements are similar but not identical.
In the following tables a convention from Collection
is used: iterator
stands for PODIO MutableCollectionIterator
and const_iterator
stands for PODIO CollectionIterator
.
Named requirement | iterator |
const_iterator |
---|---|---|
LegacyIterator | ❌ no (see below) | ❌ no (see below) |
LegacyInputIterator | ❌ no (see below) | ❌ no (see below) |
LegacyForwardIterator | ❌ no (see below) | ❌ no (see below) |
LegacyOutputIterator | ❌ no (see below) | ❌ no (see below) |
LegacyBidirectionalIterator | ❌ no | ❌ no |
LegacyRandomAccessIterator | ❌ no | ❌ no |
LegacyContiguousIterator | ❌ no | ❌ no |
Concept | iterator |
const_iterator |
---|---|---|
std::indirectly_readable |
❌ no | ❌ no |
std::indirectly_writable |
❌ no | ❌ no |
std::weakly_incrementable |
❌ no | ❌ no |
std::incrementable |
❌ no | ❌ no |
std::input_or_output_iterator |
❌ no | ❌ no |
std::input_iterator |
❌ no | ❌ no |
std::output_iterator |
❌ no | ❌ no |
std::forward_iterator |
❌ no | ❌ no |
std::bidirectional_iterator |
❌ no | ❌ no |
std::random_access_iterator |
❌ no | ❌ no |
std::contiguous_iterator |
❌ no | ❌ no |
Requirement | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|
CopyConstructible | ❌ no / ❌ no | Move constructor and copy constructor not defined |
CopyAssignable | ❌ no / ❌ no | Move assignment and copy assignment not defined |
Destructible | ✔️ yes / ✔️ yes | |
Swappable | ❌ no / ❌ no | |
std::iterator_traits::value_type (Until C++20 ) |
❌ no / ❌ no | Not defined |
std::iterator_traits::difference_type |
❌ no / ❌ no | Not defined |
std::iterator_traits::reference |
❌ no / ❌ no | Not defined |
std::iterator_traits::pointer |
❌ no / ❌ no | Not defined |
std::iterator_traits::iterator_category |
❌ no / ❌ no | Not defined |
Expression | Return type | Semantics | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|---|---|
*r |
Unspecified | ✔️ yes / ✔️ yes | ||
++r |
It& |
✔️ yes / ✔️ yes |
Requirement | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|
LegacyIterator | ❌ no / ❌ no | See above |
EqualityComparable | ✔️ yes / ✔️ yes |
Expression | Return type | Semantics | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|---|---|
i != j |
Contextually convertible to bool |
Same as !(i==j) |
✔️ yes / ✔️ yes | |
*i |
reference , convertible to value_type |
❌ no / ❌ no | reference and value_type not defined |
|
i->m |
Same as (*i).m |
✔️ yes / ✔️ yes | ||
++r |
It& |
✔️ yes / ✔️ yes | ||
(void)r++ |
Same as (void)++r |
❌ no / ❌ no | Post-increment not defined | |
*r++ |
Convertible to value_type |
Same as value_type x = *r; ++r; return x; |
❌ no / ❌ no | Post-increment and value_type not defined |
In addition to the LegacyForwardIterator the C++ standard specifies also the mutable LegacyForwardIterator, which is both LegacyForwardIterator and LegacyOutputIterator. The term mutable used in this context doesn't imply mutability in the sense used in the PODIO.
Requirement | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|
LegacyInputIterator | ❌ no / ❌ no | See above |
DefaultConstructible | ❌ no / ❌ no | Value initialization not defined |
If mutable iterator then reference same as value_type& or value_type&& , otherwise same as const value_type& or const value_type&& |
❌ no / ❌ no | reference and value_type not defined |
Multipass guarantee | ❌ no / ❌ no | Copy constructor not defined |
Singular iterators | ❌ no / ❌ no | Value initialization not defined |
Expression | Return type | Semantics | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|---|---|
i++ |
It |
Same as It ip = i; ++i; return ip; |
❌ no / ❌ no | Post-increment not defined |
*i++ |
reference |
❌ no / ❌ no | Post-increment and reference not defined |
Requirement | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|
LegacyIterator | ❌ no / ❌ no | See above |
Is pointer type or class type | ✔️ yes / ✔️ yes |
Expression | Return type | Semantics | Fulfilled by iterator /const_iterator ? |
Comment |
---|---|---|---|---|
*r = o |
❗ attention / ❗ attention | Defined but an assignment doesn't modify objects inside collection | ||
++r |
It& |
✔️ yes / ✔️ yes | ||
r++ |
Convertible to const It& |
Same as It temp = r; ++r; return temp; |
❌ no / ❌ no | Post-increment not defined |
*r++ = o |
Same as *r = o; ++r; |
❌ no / ❌ no | Post-increment not defined |
Adaptor | Compatible with Collection? | Comment |
---|---|---|
std::reverse_iterator |
❌ no | iterator and const_iterator not LegacyBidirectionalIterator or std::bidirectional_iterator |
std::back_insert_iterator |
❗ attention | Compatible only with SubsetCollections, otherwise throws std::invalid_argument |
std::front_insert_iterator |
❌ no | push_front not defined |
std::insert_iterator |
❌ no | insert not defined |
std::const_iterator |
❌ no | iterator and const_iterator not LegacyInputIterator or std::input_iterator |
std::move_iterator |
❌ no | iterator and const_iterator not LegacyInputIterator or std::input_iterator |
std::counted_iterator |
❌ no | iterator and const_iterator not std::input_or_output_iterator |
Most of the standard algorithms require the iterators to be at least InputIterator. The iterators of PODIO collection don't fulfil this requirement, therefore they are not compatible with standard algorithms according to the specification.
In practice, some algorithms may still compile with the collections depending on the implementation of a given algorithm. In general, the standard algorithms mutating a collection will give wrong results, while the standard algorithms not mutating a collection in principle should give correct results if they compile.
The standard range algorithm use constrains to operate at least on std::input_iterator
s and std::ranges::input_range
s. The iterators of PODIO collection don't model these concepts, therefore can't be used with standard range algorithms. The range algorithms won't compile with PODIO Collection
iterators.