-
Notifications
You must be signed in to change notification settings - Fork 62
Document 'Collection' comparison with 'Container' named requirement #598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
d340640
Add document comparing collection with standard 'container' named req…
m-fila e1161e1
Add to collection: `cbegin`, `cend`, `max_size`, `size_type`, `differ…
m-fila d1539d4
Add basic tests for collection compliance with container named requi…
m-fila 8e34c3d
add missing `max_size` implementation, add collection methods and ali…
m-fila 3c74e1f
update documentation with container like methods and aliases
m-fila d7b1acc
Add placeholders for iterator requirements and interaction with std a…
m-fila e117c94
fix fail message
m-fila b1d59a8
check Erasable, fix consistency, add links to reference
m-fila 8740945
fix consistency, add macro to indicate checks that may need updating …
m-fila 0a98b44
add short note on AllocatorAwareContainer, simplify comments
m-fila a8af6ea
add singularity iterators check
m-fila 18f9e71
rename pre-increment and post-increment
m-fila 43a6b38
add comment on expression and statements in AllocatorAwareContainer
m-fila 0f4975d
fix contextually convertible, add multipass guarantee
m-fila 9ebbeea
add placeholders for LegacyOutputIterator
m-fila cd4ea94
add adaptors table, algorithms table
m-fila 01b5427
add comment on algorithms and ranges
m-fila b5065fb
add iterator concepts table, move iterator concepts to separate test
m-fila d8dabe5
add tests for dereference assignment (and increment)
m-fila b3760e0
updated adaptors
m-fila 1a63c21
Return type aliases in UserDataContainer begin and end methods
m-fila 55e77e5
Don't use decltype in UserDataCollection type aliases
m-fila b6ab5d3
reorder sections, fix consistency and typos
m-fila 04ea18a
rename check macro, check dereference assignment, duplicate tests for…
m-fila f79ac29
fix commented test, add some comments, use static_require_false inst…
m-fila 4c1afbb
don't create separate target for tests
m-fila b844c09
add comments, reorganize test sections
m-fila e3356b7
fix pre-commit
m-fila 04db87f
fix iterators are not swappable
m-fila 4975d44
fix not needed requirement, fix typo
m-fila 0f733e2
fix typo
m-fila 3fdf08b
fix cv and ref qualifiers, add traits for * and ->
m-fila 75c1414
fix trait consistency
m-fila 107dacb
add mention the rest of legacy iterators
m-fila 72109a1
add check iterator_category
m-fila e25de51
add clarification *mutable* in std iterators vs *mutable* in podio
m-fila a7248b0
fix typos
m-fila eb4a493
add checks for adaptors
m-fila b3d953d
add checks for move iterator adaptor
m-fila f86ac42
fix typos
m-fila 5d7dd38
add collection vs container docs to index
m-fila 7477890
add paragraph on internals
m-fila a55733c
clarify container value_type
m-fila File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| # PODIO Collection as a *Container* | ||
|
|
||
| Comparison of the PODIO `Collection`s with a C++ named requirement [*Container*](https://en.cppreference.com/w/cpp/named_req/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](design.md#the-user-layer). Instead, [data layer objects](design.md#the-internal-data-layer) 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](#collection-and-standard-algorithms) 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. | ||
|
|
||
| ### Container Types | ||
|
|
||
| | Name | Type | Requirements | Fulfilled by Collection? | Comment | | ||
| |------|------|--------------|--------------------------|---------| | ||
| | `value_type` | `T` | *[Erasable](https://en.cppreference.com/w/cpp/named_req/Erasable)* | ✔️ yes | Defined as an immutable user layer object type | | ||
| | `reference` | `T&` | | ❌ no | Not defined | | ||
| | `const_reference` | `const T&` | | ❌ no | Not defined | | ||
| | `iterator` | Iterator whose `value_type` is `T` | [*LegacyForwardIterator*](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) convertible to `const_iterator` | ❌ no | Defined as podio `MutableCollectionIterator`. `iterator::value_type` not defined, not [*LegacyForwardIterator*](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) ([see below](#legacyforwarditerator)), not convertible to `const_iterator`| | ||
| | `const_iterator` | Constant iterator whose `value_type` is `T` | [*LegacyForwardIterator*](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) | ❌ no | Defined as podio `CollectionIterator`. `const_iterator::value_type` not defined, not [*LegacyForwardIterator*](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) ([see below](#legacyforwarditerator)) | ||
| | `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 | | | ||
|
|
||
| ### Container member functions and operators | ||
|
|
||
| | 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 | | | ||
|
|
||
| ## Collection as an *AllocatorAwareContainer* | ||
|
|
||
| The C++ standard specifies [AllocatorAwareContainer](https://en.cppreference.com/w/cpp/named_req/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*. | ||
|
|
||
| ### AllocatorAwareContainer types | ||
|
|
||
| | Name | Requirements | Fulfilled by Collection? | Comment | | ||
| |------|--------------|--------------------------|---------| | ||
| | `allocator_type` | `allocator_type::value_type` same as `value_type` | ❌ no | `allocator_type` not defined | | ||
|
|
||
| ### *AllocatorAwareContainer* expression and statements | ||
|
|
||
| The PODIO Collections currently are not checked against expression and statements requirements for *AllocatorAwareContainer*. | ||
|
|
||
| ## Collection iterators as an *Iterator* | ||
|
|
||
| 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`. | ||
| ### Iterator summary | ||
|
|
||
| | Named requirement | `iterator` | `const_iterator` | | ||
| |-------------------|-----------------------|-----------------------------| | ||
| | [LegacyIterator](https://en.cppreference.com/w/cpp/named_req/Iterator) | ❌ no ([see below](#legacyiterator)) | ❌ no ([see below](#legacyiterator)) | | ||
| | [LegacyInputIterator](https://en.cppreference.com/w/cpp/named_req/InputIterator) | ❌ no ([see below](#legacyinputiterator)) | ❌ no ([see below](#legacyinputiterator)) | | ||
| | [LegacyForwardIterator](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) | ❌ no ([see below](#legacyforwarditerator)) | ❌ no ([see below](#legacyforwarditerator)) | | ||
| | [LegacyOutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator) | ❌ no ([see below](#legacyoutputiterator)) | ❌ no ([see below](#legacyoutputiterator)) | | ||
| | [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator) | ❌ no | ❌ no | | ||
| | [LegacyRandomAccessIterator](https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator) | ❌ no | ❌ no | | ||
| | [LegacyContiguousIterator](https://en.cppreference.com/w/cpp/named_req/ContiguousIterator) | ❌ 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 | | ||
|
|
||
| ### LegacyIterator | ||
|
|
||
| | Requirement | Fulfilled by `iterator`/`const_iterator`? | Comment | | ||
| |-------------|-------------------------------------------|---------| | ||
| | [*CopyConstructible*](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) | ❌ no / ❌ no | Move constructor and copy constructor not defined | | ||
| | [*CopyAssignable*](https://en.cppreference.com/w/cpp/named_req/CopyAssignable) | ❌ no / ❌ no | Move assignment and copy assignment not defined | | ||
| | [*Destructible*](https://en.cppreference.com/w/cpp/named_req/Destructible) | ✔️ yes / ✔️ yes | | | ||
| | [*Swappable*](https://en.cppreference.com/w/cpp/named_req/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 | | | ||
|
|
||
| ### LegacyInputIterator | ||
|
|
||
| | Requirement | Fulfilled by `iterator`/`const_iterator`? | Comment | | ||
| |-------------|-------------------------------------------|---------| | ||
| | [*LegacyIterator*](https://en.cppreference.com/w/cpp/named_req/Iterator) | ❌ no / ❌ no | [See above](#legacyiterator) | | ||
| | [*EqualityComparable*](https://en.cppreference.com/w/cpp/named_req/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 | | ||
|
|
||
| ### LegacyForwardIterator | ||
|
|
||
| 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*](https://en.cppreference.com/w/cpp/named_req/InputIterator) | ❌ no / ❌ no | [See above](#legacyinputiterator)| | ||
| | [*DefaultConstructible*](https://en.cppreference.com/w/cpp/named_req/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](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) | ❌ no / ❌ no | Copy constructor not defined | | ||
| | [Singular iterators](https://en.cppreference.com/w/cpp/named_req/ForwardIterator) | ❌ 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 | | ||
|
|
||
| ### LegacyOutputIterator | ||
|
|
||
| | Requirement | Fulfilled by `iterator`/`const_iterator`? | Comment | | ||
| |-------------|-------------------------------------------|---------| | ||
| | [*LegacyIterator*](https://en.cppreference.com/w/cpp/named_req/Iterator) | ❌ no / ❌ no | [See above](#legacyiterator) | | ||
| | 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 | | ||
|
|
||
| ## Collection iterators and standard iterator adaptors | ||
|
|
||
| | 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` | | ||
|
|
||
|
|
||
| ## Collection and standard algorithms | ||
|
|
||
| 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. | ||
|
|
||
| ## Standard range algorithms | ||
|
|
||
| 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. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.