diff --git a/doc/collections_as_container.md b/doc/collections_as_container.md index b3ef3432b..8f80a8c7e 100644 --- a/doc/collections_as_container.md +++ b/doc/collections_as_container.md @@ -2,7 +2,7 @@ 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 are move-only classes with emphasis on the distinction between mutable and immutable access to the elements. +The PODIO `Collection`s interface was designed to remind the standard *Container* interface, in particular `std::vector`. The 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 are not part of *Container*. ### Container Types @@ -140,7 +140,7 @@ The C++ specifies a set of named requirements for iterators. Starting with C++20 | Expression | Return type | Semantics | Fulfilled by `iterator`/`const_iterator`? | Comment | |------------|-------------|-----------|-------------------------------------------|---------| -| `*r = o` | | | ❌ no / ❌ no | Assignment doesn't modify objects inside collection | +| `*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 | diff --git a/tests/unittests/std_interoperability.cpp b/tests/unittests/std_interoperability.cpp index f060e84f4..46f46aa67 100644 --- a/tests/unittests/std_interoperability.cpp +++ b/tests/unittests/std_interoperability.cpp @@ -395,10 +395,14 @@ TEST_CASE("Collection iterators", "[collection][container][iterator][std]") { using iterator = CollectionType::iterator; using const_iterator = CollectionType::const_iterator; // the checks are duplicated for iterator and const_iterator as expectations on them are slightly different + + // nested sections as the requirements make a hierarchy SECTION("LegacyForwardIterator") { + // LegacyForwardIterator requires LegacyInputIterator SECTION("LegacyInputIterator") { + // LegacyInputIterator requires LegacyIterator SECTION("LegacyIterator") { // CopyConstructible @@ -474,7 +478,8 @@ TEST_CASE("Collection iterators", "[collection][container][iterator][std]") { STATIC_REQUIRE(traits::has_preincrement_v); STATIC_REQUIRE( std::is_same_v()), std::add_lvalue_reference_t>); - } + + } // end of LegacyIterator // EqualityComparable // iterator @@ -552,7 +557,8 @@ TEST_CASE("Collection iterators", "[collection][container][iterator][std]") { DOCUMENTED_STATIC_FAILURE(traits::has_value_type_v>); // STATIC_REQUIRE(std::is_convertible_v < decltype(*std::declval()++), // std::iterator_traits::value_type >>); - } + + } // end of LegacyInputIterator // Mutable iterator: reference same as value_type& or value_type&& DOCUMENTED_STATIC_FAILURE(traits::has_reference_v); @@ -576,75 +582,76 @@ TEST_CASE("Collection iterators", "[collection][container][iterator][std]") { DOCUMENTED_STATIC_FAILURE(std::is_default_constructible_v); // const_iterator DOCUMENTED_STATIC_FAILURE(std::is_default_constructible_v); - } - // Multipass guarantee - // iterator - { - CollectionType coll; - for (int i = 0; i < 3; ++i) { - coll.create(); - } + // Multipass guarantee // iterator - auto a = coll.begin(); - auto b = coll.begin(); - REQUIRE(a == b); - REQUIRE(*a == *b); - REQUIRE(++a == ++b); - REQUIRE(*a == *b); - DOCUMENTED_STATIC_FAILURE(std::is_copy_constructible_v); - // auto a_copy = a; - // ++a_copy; - // REQUIRE(a == b); - // REQUIRE(*a == *b); + { + CollectionType coll; + for (int i = 0; i < 3; ++i) { + coll.create(); + } + // iterator + auto a = coll.begin(); + auto b = coll.begin(); + REQUIRE(a == b); + REQUIRE(*a == *b); + REQUIRE(++a == ++b); + REQUIRE(*a == *b); + DOCUMENTED_STATIC_FAILURE(std::is_copy_constructible_v); + // auto a_copy = a; + // ++a_copy; + // REQUIRE(a == b); + // REQUIRE(*a == *b); + + // const_iterator + auto ca = coll.cbegin(); + auto cb = coll.cbegin(); + REQUIRE(ca == cb); + REQUIRE(*ca == *cb); + REQUIRE(++ca == ++cb); + REQUIRE(*ca == *cb); + DOCUMENTED_STATIC_FAILURE(std::is_copy_constructible_v); + // auto ca_copy = ca; + // ++ca_copy; + // REQUIRE(ca == cb); + // REQUIRE(*ca == *cb); + } + // Singular iterators + // iterator + STATIC_REQUIRE(traits::has_equality_comparator_v); + DOCUMENTED_STATIC_FAILURE(std::is_default_constructible_v); + //{ + // REQUIRE(iterator{} == iterator{}); + //} // const_iterator - auto ca = coll.cbegin(); - auto cb = coll.cbegin(); - REQUIRE(ca == cb); - REQUIRE(*ca == *cb); - REQUIRE(++ca == ++cb); - REQUIRE(*ca == *cb); - DOCUMENTED_STATIC_FAILURE(std::is_copy_constructible_v); - // auto ca_copy = ca; - // ++ca_copy; - // REQUIRE(ca == cb); - // REQUIRE(*ca == *cb); - } + STATIC_REQUIRE(traits::has_equality_comparator_v); + DOCUMENTED_STATIC_FAILURE(std::is_default_constructible_v); + //{ + // REQUIRE(const_iterator{} == const_iterator{}); + //} - // Singular iterators - // iterator - STATIC_REQUIRE(traits::has_equality_comparator_v); - DOCUMENTED_STATIC_FAILURE(std::is_default_constructible_v); - //{ - // REQUIRE(iterator{} == iterator{}); - //} - // const_iterator - STATIC_REQUIRE(traits::has_equality_comparator_v); - DOCUMENTED_STATIC_FAILURE(std::is_default_constructible_v); - //{ - // REQUIRE(const_iterator{} == const_iterator{}); - //} + // i++ + // iterator + DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); + // STATIC_REQUIRE(std::is_same_v()++), iterator>); + // const_iterator + DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); + // STATIC_REQUIRE(std::is_same_v()++), const_iterator>); - // i++ - // iterator - DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); - // STATIC_REQUIRE(std::is_same_v()++), iterator>); - // const_iterator - DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); - // STATIC_REQUIRE(std::is_same_v()++), const_iterator>); + // *i++ + // iterator + DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); + DOCUMENTED_STATIC_FAILURE(traits::has_reference_v>); + // STATIC_REQUIRE(std::is_same_v < decltype(*std::declval()++), + // std::iterator_traits::reference >>); + // const_iterator + DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); + DOCUMENTED_STATIC_FAILURE(traits::has_reference_v>); + // STATIC_REQUIRE(std::is_same_v < decltype(*std::declval()++), + // std::iterator_traits::reference >>); - // *i++ - // iterator - DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); - DOCUMENTED_STATIC_FAILURE(traits::has_reference_v>); - // STATIC_REQUIRE(std::is_same_v < decltype(*std::declval()++), - // std::iterator_traits::reference >>); - // const_iterator - DOCUMENTED_STATIC_FAILURE(traits::has_postincrement_v); - DOCUMENTED_STATIC_FAILURE(traits::has_reference_v>); - // STATIC_REQUIRE(std::is_same_v < decltype(*std::declval()++), - // std::iterator_traits::reference >>); + } // end of LegacyForwardIterator SECTION("LegacyOutputIterator") { @@ -712,7 +719,9 @@ TEST_CASE("Collection iterators", "[collection][container][iterator][std]") { DOCUMENTED_STATIC_FAILURE( traits::has_dereference_assignment_increment_v); // TODO add runtime check for assignment validity like in '*r = o' case - } + + } // end of LegacyOutputIterator + } TEST_CASE("Collection and std iterator adaptors", "[collection][container][adapter][std]") {