From 83ee08f478917fee918c7ad111378515eb8a896b Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Sat, 22 Jun 2024 18:55:49 +0900 Subject: [PATCH] Add ranges concepts test (#17) * Add ranges concepts test * Update ranges_concepts.cc * Update ranges_concepts.cc * Update gtest.h * Update gtest.h * Update cmake-multi-platform.yml * Update range.h * Update ranges_concepts.cc * Update ranges_concepts.cc * Update ranges_concepts.cc --- .github/workflows/cmake-multi-platform.yml | 2 +- include/preview/__ranges/range.h | 13 +- test/gtest.h | 6 + test/ranges_concepts.cc | 211 ++++++++++++++++++++- 4 files changed, 223 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index b898f12..4e91c40 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -37,7 +37,7 @@ jobs: - name: Test working-directory: build - run: ctest --build-config ${{ matrix.build_type }} + run: ctest --build-config ${{ matrix.build_type }} --output-on-failure ubuntu-gcc: runs-on: ${{ matrix.os }} diff --git a/include/preview/__ranges/range.h b/include/preview/__ranges/range.h index 0ff5a9d..dd8fe08 100644 --- a/include/preview/__ranges/range.h +++ b/include/preview/__ranges/range.h @@ -9,6 +9,8 @@ #include "preview/__ranges/begin.h" #include "preview/__ranges/end.h" +#include "preview/__type_traits/conjunction.h" +#include "preview/__type_traits/is_invocable.h" #include "preview/__type_traits/is_referenceable.h" #include "preview/__type_traits/void_t.h" @@ -16,14 +18,15 @@ namespace preview { namespace ranges { namespace detail { -template::value, typename = void, typename = void> +template::value /* false */> struct is_range : std::false_type {}; template -struct is_range()))>, - void_t()))> - > : std::true_type {}; +struct is_range + : conjunction< + is_invocable, + is_invocable + > {}; } // namespace detail diff --git a/test/gtest.h b/test/gtest.h index 664f156..024bc74 100644 --- a/test/gtest.h +++ b/test/gtest.h @@ -19,4 +19,10 @@ #define EXPECT_EQ_TYPE(type1, type2) \ EXPECT_TRUE((std::is_same::value)) +#define EXPECT_TRUE_TYPE(...) \ + EXPECT_TRUE((__VA_ARGS__::value)) + +#define EXPECT_FALSE_TYPE(...) \ + EXPECT_FALSE((__VA_ARGS__::value)) + #endif //PREVIEW_TEST_GTEST_H_ diff --git a/test/ranges_concepts.cc b/test/ranges_concepts.cc index 6eac2f7..cd187ca 100644 --- a/test/ranges_concepts.cc +++ b/test/ranges_concepts.cc @@ -4,7 +4,17 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "preview/algorithm.h" @@ -12,6 +22,7 @@ #include "preview/span.h" #include "preview/string_view.h" +namespace ranges = preview::ranges; TEST(VERSIONED(RangesConcepts), range) { // A minimum range @@ -20,14 +31,14 @@ TEST(VERSIONED(RangesConcepts), range) { int* begin(); int* end(); }; - static_assert(preview::ranges::range::value, ""); + static_assert(ranges::range::value, ""); // not a range: no begin/end struct NotRange { int t {}; }; - static_assert(!preview::ranges::range::value, ""); + static_assert(!ranges::range::value, ""); // not a range: begin does not return an input_or_output_iterator struct NotRange2 @@ -35,5 +46,199 @@ TEST(VERSIONED(RangesConcepts), range) { void* begin(); int* end(); }; - static_assert(!preview::ranges::range::value, ""); + static_assert(!ranges::range::value, ""); +} + + +template +struct MyRange : std::array {}; + +template +PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(MyRange) = false; + +template +struct MyBorrowedRange : preview::span {}; + +template +PREVIEW_INLINE_VARIABLE constexpr bool ranges::enable_borrowed_range> = true; + +TEST(VERSIONED(RangesConcepts), borrowed_range) { + EXPECT_TRUE_TYPE (ranges::range>); + EXPECT_FALSE_TYPE (ranges::borrowed_range>); + EXPECT_TRUE_TYPE (ranges::range>); + EXPECT_TRUE_TYPE (ranges::borrowed_range>); + +#if PREVIEW_CXX_VERSION >= 17 + auto getMyRangeByValue = []{ return MyRange{{1, 2, 42, 3}}; }; + auto dangling_iter = ranges::max_element(getMyRangeByValue()); + EXPECT_TRUE_TYPE (std::is_same); + EXPECT_FALSE_TYPE (preview::dereferenceable); +// *dangling_iter; // compilation error (i.e. dangling protection works.) + + auto my = MyRange{{1, 2, 42, 3}}; + auto valid_iter = ranges::max_element(my); + EXPECT_EQ(*valid_iter, 42); + + auto getMyBorrowedRangeByValue = [] + { + static int sa[4]{1, 2, 42, 3}; + return MyBorrowedRange{sa}; + }; + auto valid_iter2 = ranges::max_element(getMyBorrowedRangeByValue()); + EXPECT_EQ(*valid_iter2, 42); +#endif +} + +TEST(VERSIONED(RangesConcepts), sized_range) { + EXPECT_TRUE_TYPE(ranges::sized_range); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + EXPECT_TRUE_TYPE(ranges::sized_range>); + + EXPECT_FALSE_TYPE(ranges::sized_range); + EXPECT_FALSE_TYPE(ranges::sized_range>); + EXPECT_FALSE_TYPE(ranges::sized_range>); +} + + +struct ArchetypalView : ranges::view_interface +{ + int* begin(); + int* end(); +}; +TEST(VERSIONED(RangesConcepts), view) { + EXPECT_TRUE_TYPE(ranges::view); + EXPECT_TRUE_TYPE(ranges::view::iterator>>); + EXPECT_TRUE_TYPE(ranges::view>); + EXPECT_TRUE_TYPE(ranges::view>); + + EXPECT_FALSE_TYPE(ranges::view>); +} + +// TODO: Write test +TEST(VERSIONED(RangesConcepts), input_range) {} + +// TODO: Write test +TEST(VERSIONED(RangesConcepts), output_range) {} + +TEST(VERSIONED(RangesConcepts), forward_range) { + const char* str{"not a forward range"}; + const char str2[] = "a forward range"; + + EXPECT_TRUE_TYPE(ranges::forward_range); + EXPECT_TRUE_TYPE(ranges::forward_range); + EXPECT_TRUE_TYPE(ranges::forward_range>); + EXPECT_TRUE_TYPE(ranges::forward_range>); + EXPECT_TRUE_TYPE(ranges::forward_range>); + EXPECT_TRUE_TYPE(ranges::forward_range>); + + EXPECT_FALSE_TYPE(ranges::forward_range); + EXPECT_FALSE_TYPE(ranges::forward_range>); + EXPECT_FALSE_TYPE(ranges::forward_range>>); + EXPECT_FALSE_TYPE(ranges::forward_range>); +} + +TEST(VERSIONED(RangesConcepts), bidirectional_range) { + EXPECT_TRUE_TYPE(ranges::bidirectional_range>); + EXPECT_TRUE_TYPE(ranges::bidirectional_range>); + + // MSVC's hash container models bidirectional range (iterator is from std::list) +#if defined(_MSC_VER) && !defined(__llvm__) && !defined(__INTEL_COMPILER) + EXPECT_TRUE_TYPE(ranges::bidirectional_range>); + EXPECT_TRUE_TYPE(ranges::bidirectional_range>); +#else + EXPECT_FALSE_TYPE(ranges::bidirectional_range>); + EXPECT_FALSE_TYPE(ranges::bidirectional_range>); +#endif + EXPECT_FALSE_TYPE(ranges::bidirectional_range>); +} + +TEST(VERSIONED(RangesConcepts), random_access_range) { + int a[4]; + EXPECT_TRUE_TYPE(ranges::random_access_range>); + EXPECT_TRUE_TYPE(ranges::random_access_range>); + EXPECT_TRUE_TYPE(ranges::random_access_range>); + EXPECT_TRUE_TYPE(ranges::random_access_range>); + EXPECT_TRUE_TYPE(ranges::random_access_range); + EXPECT_TRUE_TYPE(ranges::random_access_range, 42>>); + + EXPECT_FALSE_TYPE(ranges::random_access_range>); + EXPECT_FALSE_TYPE(ranges::random_access_range>); +} + +TEST(VERSIONED(RangesConcepts), contiguous_range) { + int a[4]; + EXPECT_TRUE_TYPE(ranges::contiguous_range>); + EXPECT_TRUE_TYPE(ranges::contiguous_range>); + EXPECT_TRUE_TYPE(ranges::contiguous_range); + EXPECT_TRUE_TYPE(ranges::contiguous_range, 42>>); + + EXPECT_FALSE_TYPE(ranges::contiguous_range>); + EXPECT_FALSE_TYPE(ranges::contiguous_range>); + EXPECT_FALSE_TYPE(ranges::contiguous_range>); + EXPECT_FALSE_TYPE(ranges::contiguous_range>); +} + +TEST(VERSIONED(RangesConcepts), common_range) { + struct A { + char* begin(); + char* end(); + }; + EXPECT_TRUE_TYPE(ranges::common_range); + + struct B { + char* begin(); + bool end(); + }; // not a common_range: begin/end have different types + EXPECT_FALSE_TYPE(ranges::common_range); + + struct C { + char* begin(); + }; // not a common_range, not even a range: has no end() + EXPECT_FALSE_TYPE(ranges::common_range); +} + +template +auto test_viewable_range(T &&) -> ranges::viewable_range; + +TEST(VERSIONED(RangesConcepts), viewable_range) { + auto il = {1, 2, 3}; + int arr []{1, 2, 3}; +#if PREVIEW_CXX_VERSION < 17 + std::vector vec{1, 2, 3}; + ranges::ref_view r{arr}; + ranges::owning_view o{std::string("Hello")}; +#else + std::vector vec{1, 2, 3}; + ranges::ref_view r{arr}; + ranges::owning_view o{std::string("Hello")}; +#endif + + EXPECT_TRUE_TYPE(decltype(test_viewable_range( il ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( arr ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( vec ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( std::move(vec) ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( r ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( std::move(r) ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( std::move(o) ))); + EXPECT_TRUE_TYPE(decltype(test_viewable_range( ranges::ref_view>(o) ))); + + EXPECT_FALSE_TYPE(decltype(test_viewable_range( std::move(il) ))); + EXPECT_FALSE_TYPE(decltype(test_viewable_range( std::move(arr) ))); + EXPECT_FALSE_TYPE(decltype(test_viewable_range( o ))); +} + +TEST(VERSIONED(RangesConcepts), constant_range) { + EXPECT_TRUE_TYPE(ranges::constant_range>); + EXPECT_TRUE_TYPE(ranges::constant_range); + EXPECT_TRUE_TYPE(ranges::constant_range>); + + EXPECT_FALSE_TYPE(ranges::constant_range>); + EXPECT_FALSE_TYPE(ranges::constant_range>); + EXPECT_FALSE_TYPE(ranges::constant_range>); }