diff options
| -rw-r--r-- | source/tests/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | source/tests/src/iterable.cpp | 1063 | ||||
| -rw-r--r-- | source/tests/src/iterable_suite.cpp | 719 |
3 files changed, 1064 insertions, 720 deletions
diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt index 7d08e12..77a0a66 100644 --- a/source/tests/CMakeLists.txt +++ b/source/tests/CMakeLists.txt @@ -14,7 +14,7 @@ add_executable("${PROJECT_NAME}_tests" "src/equality_comparison.cpp" "src/hash.cpp" "src/io_operators.cpp" - # "src/iterable_suite.cpp" + "src/iterable.cpp" # "src/relational_operators_suite.cpp" ) diff --git a/source/tests/src/iterable.cpp b/source/tests/src/iterable.cpp new file mode 100644 index 0000000..265dc8c --- /dev/null +++ b/source/tests/src/iterable.cpp @@ -0,0 +1,1063 @@ +#include "newtype/derivable.hpp" +#include "newtype/deriving.hpp" +#include "newtype/impl/type_traits_extensions.hpp" +#include "newtype/newtype.hpp" + +#include <catch2/catch_test_macros.hpp> + +#include <algorithm> +#include <array> +#include <iterator> +#include <numeric> + +namespace iterable_types +{ + + struct with_member + { + using iterator = char *; + using const_iterator = char const *; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + auto constexpr begin() -> iterator; + auto constexpr begin() const -> const_iterator; + auto constexpr cbegin() const -> const_iterator; + auto constexpr rbegin() -> reverse_iterator; + auto constexpr rbegin() const -> const_reverse_iterator; + auto constexpr crbegin() const -> const_reverse_iterator; + + auto constexpr end() -> iterator; + auto constexpr end() const -> const_iterator; + auto constexpr cend() const -> const_iterator; + auto constexpr rend() -> reverse_iterator; + auto constexpr rend() const -> const_reverse_iterator; + auto constexpr crend() const -> const_reverse_iterator; + }; + + struct with_free + { + using iterator = char *; + using const_iterator = char const *; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + }; + + auto constexpr begin(with_free &) -> with_free::iterator; + auto constexpr begin(with_free const &) -> with_free::const_iterator; + auto constexpr cbegin(with_free const &) -> with_free::const_iterator; + auto constexpr rbegin(with_free &) -> with_free::reverse_iterator; + auto constexpr rbegin(with_free const &) -> with_free::const_reverse_iterator; + auto constexpr crbegin(with_free const &) -> with_free::const_reverse_iterator; + auto constexpr end(with_free &) -> with_free::iterator; + auto constexpr end(with_free const &) -> with_free::const_iterator; + auto constexpr cend(with_free const &) -> with_free::const_iterator; + auto constexpr rend(with_free &) -> with_free::reverse_iterator; + auto constexpr rend(with_free const &) -> with_free::const_reverse_iterator; + auto constexpr crend(with_free const &) -> with_free::const_reverse_iterator; + +} // namespace iterable_types + +SCENARIO("Iterators", "[iterators]") +{ + GIVEN("A new_type over a non-iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type<int, struct tag>; + static_assert(!nt::impl::has_begin_v<type_alias::base_type>); + static_assert(!nt::impl::has_begin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_cbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_rbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_rbegin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_crbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_end_v<type_alias::base_type>); + static_assert(!nt::impl::has_end_v<type_alias::base_type const>); + static_assert(!nt::impl::has_cend_v<type_alias::base_type>); + static_assert(!nt::impl::has_rend_v<type_alias::base_type>); + static_assert(!nt::impl::has_rend_v<type_alias::base_type const>); + static_assert(!nt::impl::has_crend_v<type_alias::base_type>); + + THEN("it has no begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_begin_v<type_alias>); + } + + THEN("it has no constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_begin_v<type_alias const>); + } + + THEN("it has no cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_cbegin_v<type_alias>); + } + + THEN("it has no rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rbegin_v<type_alias>); + } + + THEN("it has no constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rbegin_v<type_alias const>); + } + + THEN("it has no crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_crbegin_v<type_alias>); + } + + THEN("it has no end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_end_v<type_alias>); + } + + THEN("it has no constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_end_v<type_alias const>); + } + + THEN("it has no cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_cend_v<type_alias>); + } + + THEN("it has no rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rend_v<type_alias>); + } + + THEN("it has no constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rend_v<type_alias const>); + } + + THEN("it has no crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_crend_v<type_alias>); + } + } + + GIVEN("A new_type over a non-iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>; + static_assert(!nt::impl::has_begin_v<type_alias::base_type>); + static_assert(!nt::impl::has_begin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_cbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_rbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_rbegin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_crbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_end_v<type_alias::base_type>); + static_assert(!nt::impl::has_end_v<type_alias::base_type const>); + static_assert(!nt::impl::has_cend_v<type_alias::base_type>); + static_assert(!nt::impl::has_rend_v<type_alias::base_type>); + static_assert(!nt::impl::has_rend_v<type_alias::base_type const>); + static_assert(!nt::impl::has_crend_v<type_alias::base_type>); + + THEN("it has no begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_begin_v<type_alias>); + } + + THEN("it has no constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_begin_v<type_alias const>); + } + + THEN("it has no cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_cbegin_v<type_alias>); + } + + THEN("it has no rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rbegin_v<type_alias>); + } + + THEN("it has no constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rbegin_v<type_alias const>); + } + + THEN("it has no crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_crbegin_v<type_alias>); + } + + THEN("it has no end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_end_v<type_alias>); + } + + THEN("it has no constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_end_v<type_alias const>); + } + + THEN("it has no cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_cend_v<type_alias>); + } + + THEN("it has no rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rend_v<type_alias>); + } + + THEN("it has no constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rend_v<type_alias const>); + } + + THEN("it has no crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_crend_v<type_alias>); + } + } + + GIVEN("A new_type over an iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type<std::array<int, 1>, struct tag>; + static_assert(nt::impl::has_begin_v<type_alias::base_type>); + static_assert(nt::impl::has_begin_v<type_alias::base_type const>); + static_assert(nt::impl::has_cbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_rbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_rbegin_v<type_alias::base_type const>); + static_assert(nt::impl::has_crbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_end_v<type_alias::base_type>); + static_assert(nt::impl::has_end_v<type_alias::base_type const>); + static_assert(nt::impl::has_cend_v<type_alias::base_type>); + static_assert(nt::impl::has_rend_v<type_alias::base_type>); + static_assert(nt::impl::has_rend_v<type_alias::base_type const>); + static_assert(nt::impl::has_crend_v<type_alias::base_type>); + + THEN("it has no begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_begin_v<type_alias>); + } + + THEN("it has no constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_begin_v<type_alias const>); + } + + THEN("it has no cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_cbegin_v<type_alias>); + } + + THEN("it has no rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rbegin_v<type_alias>); + } + + THEN("it has no constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rbegin_v<type_alias const>); + } + + THEN("it has no crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_crbegin_v<type_alias>); + } + + THEN("it has no end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_end_v<type_alias>); + } + + THEN("it has no constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_end_v<type_alias const>); + } + + THEN("it has no cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_cend_v<type_alias>); + } + + THEN("it has no rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rend_v<type_alias>); + } + + THEN("it has no constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_rend_v<type_alias const>); + } + + THEN("it has no crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_crend_v<type_alias>); + } + } + + GIVEN("A new_type over an iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type<std::array<int, 1>, struct tag, deriving(nt::Iterable)>; + static_assert(nt::impl::has_begin_v<type_alias::base_type>); + static_assert(nt::impl::has_begin_v<type_alias::base_type const>); + static_assert(nt::impl::has_cbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_rbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_rbegin_v<type_alias::base_type const>); + static_assert(nt::impl::has_crbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_end_v<type_alias::base_type>); + static_assert(nt::impl::has_end_v<type_alias::base_type const>); + static_assert(nt::impl::has_cend_v<type_alias::base_type>); + static_assert(nt::impl::has_rend_v<type_alias::base_type>); + static_assert(nt::impl::has_rend_v<type_alias::base_type const>); + static_assert(nt::impl::has_crend_v<type_alias::base_type>); + + THEN("it has begin") + { + STATIC_REQUIRE(nt::impl::has_begin_v<type_alias>); + } + + THEN("it has constant begin") + { + STATIC_REQUIRE(nt::impl::has_begin_v<type_alias const>); + } + + THEN("it has cbegin") + { + STATIC_REQUIRE(nt::impl::has_cbegin_v<type_alias>); + } + + THEN("it has rbegin") + { + STATIC_REQUIRE(nt::impl::has_rbegin_v<type_alias>); + } + + THEN("it has constant rbegin") + { + STATIC_REQUIRE(nt::impl::has_rbegin_v<type_alias const>); + } + + THEN("it has crbegin") + { + STATIC_REQUIRE(nt::impl::has_crbegin_v<type_alias>); + } + + THEN("it has end") + { + STATIC_REQUIRE(nt::impl::has_end_v<type_alias>); + } + + THEN("it has constant end") + { + STATIC_REQUIRE(nt::impl::has_end_v<type_alias const>); + } + + THEN("it has cend") + { + STATIC_REQUIRE(nt::impl::has_cend_v<type_alias>); + } + + THEN("it has rend") + { + STATIC_REQUIRE(nt::impl::has_rend_v<type_alias>); + } + + THEN("it has constant rend") + { + STATIC_REQUIRE(nt::impl::has_rend_v<type_alias const>); + } + + THEN("it has crend") + { + STATIC_REQUIRE(nt::impl::has_crend_v<type_alias>); + } + } +} + +SCENARIO("Iterators (member)", "[iterators]") +{ + GIVEN("A new_type over a non-iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type<int, struct tag>; + static_assert(!nt::impl::has_member_begin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_begin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_cbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rbegin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_crbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_end_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_end_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_cend_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rend_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rend_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_crend_v<type_alias::base_type>); + + THEN("it has no member begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_begin_v<type_alias>); + } + + THEN("it has no member constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_begin_v<type_alias const>); + } + + THEN("it has no member cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_cbegin_v<type_alias>); + } + + THEN("it has no member rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rbegin_v<type_alias>); + } + + THEN("it has no member constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rbegin_v<type_alias const>); + } + + THEN("it has no member crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_crbegin_v<type_alias>); + } + + THEN("it has no member end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_end_v<type_alias>); + } + + THEN("it has no member constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_end_v<type_alias const>); + } + + THEN("it has no member cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_cend_v<type_alias>); + } + + THEN("it has no member rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rend_v<type_alias>); + } + + THEN("it has no member constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rend_v<type_alias const>); + } + + THEN("it has no member crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_crend_v<type_alias>); + } + } + + GIVEN("A new_type over a non-iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>; + static_assert(!nt::impl::has_member_begin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_begin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_cbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rbegin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_crbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_end_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_end_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_cend_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rend_v<type_alias::base_type>); + static_assert(!nt::impl::has_member_rend_v<type_alias::base_type const>); + static_assert(!nt::impl::has_member_crend_v<type_alias::base_type>); + + THEN("it has no member begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_begin_v<type_alias>); + } + + THEN("it has no member constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_begin_v<type_alias const>); + } + + THEN("it has no member cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_cbegin_v<type_alias>); + } + + THEN("it has no member rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rbegin_v<type_alias>); + } + + THEN("it has no member constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rbegin_v<type_alias const>); + } + + THEN("it has no member crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_crbegin_v<type_alias>); + } + + THEN("it has no member end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_end_v<type_alias>); + } + + THEN("it has no member constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_end_v<type_alias const>); + } + + THEN("it has no member cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_cend_v<type_alias>); + } + + THEN("it has no member rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rend_v<type_alias>); + } + + THEN("it has no member constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rend_v<type_alias const>); + } + + THEN("it has no member crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_crend_v<type_alias>); + } + } + + GIVEN("A new_type over an iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type<std::array<int, 1>, struct tag>; + static_assert(nt::impl::has_member_begin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_begin_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_cbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rbegin_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_crbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_end_v<type_alias::base_type>); + static_assert(nt::impl::has_member_end_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_cend_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rend_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rend_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_crend_v<type_alias::base_type>); + + THEN("it has no member begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_begin_v<type_alias>); + } + + THEN("it has no member constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_begin_v<type_alias const>); + } + + THEN("it has no member cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_cbegin_v<type_alias>); + } + + THEN("it has no member rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rbegin_v<type_alias>); + } + + THEN("it has no member constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rbegin_v<type_alias const>); + } + + THEN("it has no member crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_crbegin_v<type_alias>); + } + + THEN("it has no member end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_end_v<type_alias>); + } + + THEN("it has no member constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_end_v<type_alias const>); + } + + THEN("it has no member cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_cend_v<type_alias>); + } + + THEN("it has no member rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rend_v<type_alias>); + } + + THEN("it has no member constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_rend_v<type_alias const>); + } + + THEN("it has no member crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_member_crend_v<type_alias>); + } + } + + GIVEN("A new_type over an iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type<std::array<int, 1>, struct tag, deriving(nt::Iterable)>; + static_assert(nt::impl::has_member_begin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_begin_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_cbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rbegin_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_crbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_member_end_v<type_alias::base_type>); + static_assert(nt::impl::has_member_end_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_cend_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rend_v<type_alias::base_type>); + static_assert(nt::impl::has_member_rend_v<type_alias::base_type const>); + static_assert(nt::impl::has_member_crend_v<type_alias::base_type>); + + THEN("it has member begin") + { + STATIC_REQUIRE(nt::impl::has_member_begin_v<type_alias>); + } + + THEN("it has member constant begin") + { + STATIC_REQUIRE(nt::impl::has_member_begin_v<type_alias const>); + } + + THEN("it has member cbegin") + { + STATIC_REQUIRE(nt::impl::has_member_cbegin_v<type_alias>); + } + + THEN("it has member rbegin") + { + STATIC_REQUIRE(nt::impl::has_member_rbegin_v<type_alias>); + } + + THEN("it has member constant rbegin") + { + STATIC_REQUIRE(nt::impl::has_member_rbegin_v<type_alias const>); + } + + THEN("it has member crbegin") + { + STATIC_REQUIRE(nt::impl::has_member_crbegin_v<type_alias>); + } + + THEN("it has member end") + { + STATIC_REQUIRE(nt::impl::has_member_end_v<type_alias>); + } + + THEN("it has member constant end") + { + STATIC_REQUIRE(nt::impl::has_member_end_v<type_alias const>); + } + + THEN("it has member cend") + { + STATIC_REQUIRE(nt::impl::has_member_cend_v<type_alias>); + } + + THEN("it has member rend") + { + STATIC_REQUIRE(nt::impl::has_member_rend_v<type_alias>); + } + + THEN("it has member constant rend") + { + STATIC_REQUIRE(nt::impl::has_member_rend_v<type_alias const>); + } + + THEN("it has member crend") + { + STATIC_REQUIRE(nt::impl::has_member_crend_v<type_alias>); + } + } +} + +SCENARIO("Iterators (free)", "[iterators]") +{ + GIVEN("A new_type over a non-iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type<int, struct tag>; + static_assert(!nt::impl::has_free_begin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_begin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_cbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rbegin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_crbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_end_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_end_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_cend_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rend_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rend_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_crend_v<type_alias::base_type>); + + THEN("it has no free begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_begin_v<type_alias>); + } + + THEN("it has no free constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_begin_v<type_alias const>); + } + + THEN("it has no free cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_cbegin_v<type_alias>); + } + + THEN("it has no free rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rbegin_v<type_alias>); + } + + THEN("it has no free constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rbegin_v<type_alias const>); + } + + THEN("it has no free crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_crbegin_v<type_alias>); + } + + THEN("it has no free end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_end_v<type_alias>); + } + + THEN("it has no free constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_end_v<type_alias const>); + } + + THEN("it has no free cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_cend_v<type_alias>); + } + + THEN("it has no free rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rend_v<type_alias>); + } + + THEN("it has no free constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rend_v<type_alias const>); + } + + THEN("it has no free crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_crend_v<type_alias>); + } + } + + GIVEN("A new_type over a non-iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>; + static_assert(!nt::impl::has_free_begin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_begin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_cbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rbegin_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_crbegin_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_end_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_end_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_cend_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rend_v<type_alias::base_type>); + static_assert(!nt::impl::has_free_rend_v<type_alias::base_type const>); + static_assert(!nt::impl::has_free_crend_v<type_alias::base_type>); + + THEN("it has no free begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_begin_v<type_alias>); + } + + THEN("it has no free constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_begin_v<type_alias const>); + } + + THEN("it has no free cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_cbegin_v<type_alias>); + } + + THEN("it has no free rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rbegin_v<type_alias>); + } + + THEN("it has no free constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rbegin_v<type_alias const>); + } + + THEN("it has no free crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_crbegin_v<type_alias>); + } + + THEN("it has no free end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_end_v<type_alias>); + } + + THEN("it has no free constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_end_v<type_alias const>); + } + + THEN("it has no free cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_cend_v<type_alias>); + } + + THEN("it has no free rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rend_v<type_alias>); + } + + THEN("it has no free constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rend_v<type_alias const>); + } + + THEN("it has no free crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_crend_v<type_alias>); + } + } + + GIVEN("A new_type over an iterable base type not deriving nt::Iterable") + { + using type_alias = nt::new_type<std::array<int, 1>, struct tag>; + static_assert(nt::impl::has_free_begin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_begin_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_cbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rbegin_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_crbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_end_v<type_alias::base_type>); + static_assert(nt::impl::has_free_end_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_cend_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rend_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rend_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_crend_v<type_alias::base_type>); + + THEN("it has no free begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_begin_v<type_alias>); + } + + THEN("it has no free constant begin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_begin_v<type_alias const>); + } + + THEN("it has no free cbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_cbegin_v<type_alias>); + } + + THEN("it has no free rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rbegin_v<type_alias>); + } + + THEN("it has no free constant rbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rbegin_v<type_alias const>); + } + + THEN("it has no free crbegin") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_crbegin_v<type_alias>); + } + + THEN("it has no free end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_end_v<type_alias>); + } + + THEN("it has no free constant end") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_end_v<type_alias const>); + } + + THEN("it has no free cend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_cend_v<type_alias>); + } + + THEN("it has no free rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rend_v<type_alias>); + } + + THEN("it has no free constant rend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_rend_v<type_alias const>); + } + + THEN("it has no free crend") + { + STATIC_REQUIRE_FALSE(nt::impl::has_free_crend_v<type_alias>); + } + } + + GIVEN("A new_type over an iterable base type deriving nt::Iterable") + { + using type_alias = nt::new_type<std::array<int, 1>, struct tag, deriving(nt::Iterable)>; + static_assert(nt::impl::has_free_begin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_begin_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_cbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rbegin_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_crbegin_v<type_alias::base_type>); + static_assert(nt::impl::has_free_end_v<type_alias::base_type>); + static_assert(nt::impl::has_free_end_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_cend_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rend_v<type_alias::base_type>); + static_assert(nt::impl::has_free_rend_v<type_alias::base_type const>); + static_assert(nt::impl::has_free_crend_v<type_alias::base_type>); + + THEN("it has free begin") + { + STATIC_REQUIRE(nt::impl::has_free_begin_v<type_alias>); + } + + THEN("it has free constant begin") + { + STATIC_REQUIRE(nt::impl::has_free_begin_v<type_alias const>); + } + + THEN("it has free cbegin") + { + STATIC_REQUIRE(nt::impl::has_free_cbegin_v<type_alias>); + } + + THEN("it has free rbegin") + { + STATIC_REQUIRE(nt::impl::has_free_rbegin_v<type_alias>); + } + + THEN("it has free constant rbegin") + { + STATIC_REQUIRE(nt::impl::has_free_rbegin_v<type_alias const>); + } + + THEN("it has free crbegin") + { + STATIC_REQUIRE(nt::impl::has_free_crbegin_v<type_alias>); + } + + THEN("it has free end") + { + STATIC_REQUIRE(nt::impl::has_free_end_v<type_alias>); + } + + THEN("it has free constant end") + { + STATIC_REQUIRE(nt::impl::has_free_end_v<type_alias const>); + } + + THEN("it has free cend") + { + STATIC_REQUIRE(nt::impl::has_free_cend_v<type_alias>); + } + + THEN("it has free rend") + { + STATIC_REQUIRE(nt::impl::has_free_rend_v<type_alias>); + } + + THEN("it has free constant rend") + { + STATIC_REQUIRE(nt::impl::has_free_rend_v<type_alias const>); + } + + THEN("it has free crend") + { + STATIC_REQUIRE(nt::impl::has_free_crend_v<type_alias>); + } + } +} + +SCENARIO("Iterator Semantics", "[iterators]") +{ + GIVEN("An iterable new_type") + { + using type_alias = nt::new_type<std::array<int, 3>, struct tag, deriving(nt::Iterable)>; + + THEN("a non-const object can be used in value range-based for") + { + auto obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("a const object can be used in value range-based for") + { + auto const obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("a non-const object can be used in reference range-based for") + { + auto obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto & e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("a const object can be used in const-reference range-based for") + { + auto const obj = type_alias{{1, 2, 3}}; + auto res = 0; + for (auto const & e : obj) + { + res += e; + } + REQUIRE(res == 6); + } + + THEN("using an instance of it in an STL algorithm yields the same results as using an instance of the base type") + { + auto const base_obj = type_alias::base_type{{1, 2, 3}}; + auto const nt_obj = type_alias{base_obj}; + + auto base_res = std::accumulate(begin(base_obj), end(base_obj), 0); + auto nt_res = std::accu |
