aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/tests/CMakeLists.txt2
-rw-r--r--source/tests/src/iterable.cpp1063
-rw-r--r--source/tests/src/iterable_suite.cpp719
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