-struct data_member_check_2 : std::is_object
{
- using category = return_category<1, P*>;
-};
-
-template
-struct data_member_check : std::false_type {
- using category = return_category<0>;
-};
-template
-struct data_member_check().data()) )>>
- : data_member_check_2().data()) )> {};
-
-
-template
-struct data_ranges_begin_check : std::false_type {
- using category = return_category<0>;
-};
-template
-struct data_ranges_begin_check()) )>>
- : contiguous_iterator()) )>
-{
- using category = return_category<2, decltype( preview::to_address( ranges::begin(std::declval()) ) )>;
-};
+struct data_niebloid {
+ private:
+ template
+ struct is_pointer_to_object : std::false_type {};
+ template
+ struct is_pointer_to_object : std::is_object {};
+
+ template
+ struct member_function_data_is_pointer_to_object
+ : std::false_type {};
+ template
+ struct member_function_data_is_pointer_to_object().data()) )>>
+ : conjunction<
+ is_pointer_to_object().data()) )>,
+ std::is_convertible<
+ decltype( preview_decay_copy(std::declval().data()) ),
+ std::remove_reference_t>*
+ >
+ > {};
+
+ template
+ struct ranges_begin_is_contiguous_iterator
+ : std::false_type {};
+ template
+ struct ranges_begin_is_contiguous_iterator()) )>>
+ : conjunction<
+ contiguous_iterator()) )>,
+ std::is_convertible<
+ decltype( ranges::begin(std::declval()) ),
+ std::remove_reference_t>*
+ >
+ > {};
+
+ template
+ constexpr std::remove_reference_t>*
+ call(T&& t, std::true_type) const {
+ return preview_decay_copy(t.data());
+ }
-template
-struct data_category
- : std::conditional_t<
- data_member_check::value, typename data_member_check::category,
- std::conditional_t<
- data_ranges_begin_check::value, typename data_ranges_begin_check::category,
- return_category<0>
- >>{};
+ template
+ constexpr std::remove_reference_t>*
+ call(T&& t, std::false_type) const {
+ return preview::to_address(ranges::begin(t));
+ }
-struct data_niebloid {
- template,
- ranges::enable_borrowed_range>
+ public:
+ template,
+ disjunction<
+ std::is_lvalue_reference,
+ enable_borrowed_range_t>
+ >,
+ has_typename_type>,
+ disjunction<
+ member_function_data_is_pointer_to_object,
+ ranges_begin_is_contiguous_iterator
+ >
>::value, int> = 0>
- constexpr typename data_category::return_type
+ constexpr std::remove_reference_t>*
operator()(T&& t) const {
- return (*this)(std::forward(t), data_category{});
+ return call(std::forward(t), member_function_data_is_pointer_to_object{});
}
- private:
- template
- constexpr R operator()(T&& t, return_category<1, R>) const {
- return preview_decay_copy(t.data());
- }
+#if PREVIEW_CXX_VERSION < 17
+ // non-const version of std::basic_string::data was introduced since C++17
- template
- constexpr R operator()(T&& t, return_category<2, R>) const {
- return preview::to_address(ranges::begin(t));
+ template
+ constexpr CharT* operator()(std::basic_string& str) const {
+ return const_cast(str.data());
}
+#endif
};
} // namespace detail
diff --git a/include/preview/__ranges/detail/have_cxx20_ranges.h b/include/preview/__ranges/detail/have_cxx20_ranges.h
new file mode 100644
index 0000000..21ffad6
--- /dev/null
+++ b/include/preview/__ranges/detail/have_cxx20_ranges.h
@@ -0,0 +1,16 @@
+# /**
+# * Created by YongGyu Lee on 2024. 6. 22
+# */
+#
+#ifndef PREVIEW_RANGES_DETAIL_HAVE_CXX20_RANGES_H_
+#define PREVIEW_RANGES_DETAIL_HAVE_CXX20_RANGES_H_
+#
+#include "preview/core.h"
+#
+#if PREVIEW_CXX_VERSION >= 20 && (PREVIEW_ANDROID == 0 || (defined(PREVIEW_NDK_VERSION_MAJOR) && PREVIEW_NDK_VERSION_MAJOR >= 26))
+# define PREVIEW_HAVE_CXX20_RANGES 1
+#else
+# define PREVIEW_HAVE_CXX20_RANGES 0
+#endif
+#
+#endif // PREVIEW_RANGES_DETAIL_HAVE_CXX20_RANGES_H_
diff --git a/include/preview/__ranges/enable_borrowed_range.h b/include/preview/__ranges/enable_borrowed_range.h
index bd55cac..2f9fa76 100644
--- a/include/preview/__ranges/enable_borrowed_range.h
+++ b/include/preview/__ranges/enable_borrowed_range.h
@@ -4,16 +4,46 @@
#ifndef PREVIEW_RANGES_ENABLE_BORROWED_RANGE_H_
#define PREVIEW_RANGES_ENABLE_BORROWED_RANGE_H_
-
+#
#include
+#
+#include "preview/core.h"
+#include "preview/__ranges/detail/have_cxx20_ranges.h"
+
+#if PREVIEW_HAVE_CXX20_RANGES
+#include
+#endif
namespace preview {
namespace ranges {
+#if PREVIEW_HAVE_CXX20_RANGES
+template
+PREVIEW_INLINE_VARIABLE constexpr bool enable_borrowed_range = std::ranges::enable_borrowed_range;
+#else
+template
+PREVIEW_INLINE_VARIABLE constexpr bool enable_borrowed_range = false;
+#endif
+
template
-struct enable_borrowed_range : std::false_type {};
+struct enable_borrowed_range_t : std::integral_constant> {};
} // namespace preview
} // namespace ranges
+#if PREVIEW_HAVE_CXX20_RANGES
+# define PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(...) \
+ inline constexpr bool std::ranges::enable_borrowed_range<__VA_ARGS__>
+#else
+# define PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(...) \
+ PREVIEW_INLINE_VARIABLE constexpr bool preview::ranges::enable_borrowed_range<__VA_ARGS__>
+#endif
+
+#if 17 <= PREVIEW_CXX_VERSION && PREVIEW_CXX_VERSION < 20
+#include
+
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(std::basic_string_view) = true;
+#endif
+
#endif // PREVIEW_RANGES_ENABLE_BORROWED_RANGE_H_
diff --git a/include/preview/__ranges/enable_view.h b/include/preview/__ranges/enable_view.h
index 0ecde23..cfd99e7 100644
--- a/include/preview/__ranges/enable_view.h
+++ b/include/preview/__ranges/enable_view.h
@@ -14,6 +14,7 @@
namespace preview {
namespace ranges {
+// TODO: Sync with std::ranges::enable_view
template
struct enable_view : disjunction<
derived_from,
diff --git a/include/preview/__ranges/end.h b/include/preview/__ranges/end.h
index acca752..96d07d0 100644
--- a/include/preview/__ranges/end.h
+++ b/include/preview/__ranges/end.h
@@ -72,7 +72,7 @@ struct end_niebloid {
: std::conditional_t<
disjunction<
std::is_lvalue_reference,
- enable_borrowed_range>
+ enable_borrowed_range_t>
>::value,
typename end_category_impl::category,
return_category<0>
diff --git a/include/preview/__ranges/owning_view.h b/include/preview/__ranges/owning_view.h
index 273188e..144692a 100644
--- a/include/preview/__ranges/owning_view.h
+++ b/include/preview/__ranges/owning_view.h
@@ -2,8 +2,8 @@
// Created by yonggyulee on 2024/01/02.
//
-#ifndef PREVIEW_RANGES_OWINING_VIEW_H_
-#define PREVIEW_RANGES_OWINING_VIEW_H_
+#ifndef PREVIEW_RANGES_OWNING_VIEW_H_
+#define PREVIEW_RANGES_OWNING_VIEW_H_
#include
@@ -112,10 +112,11 @@ owning_view(R&&) -> owning_view;
#endif
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace namespace preview
-#endif // PREVIEW_RANGES_OWINING_VIEW_H_
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::owning_view)
+ = preview::ranges::enable_borrowed_range;
+
+#endif // PREVIEW_RANGES_OWNING_VIEW_H_
diff --git a/include/preview/__ranges/rbegin.h b/include/preview/__ranges/rbegin.h
index d19c17c..0e5cf62 100644
--- a/include/preview/__ranges/rbegin.h
+++ b/include/preview/__ranges/rbegin.h
@@ -74,7 +74,7 @@ struct rbegin_niebloid {
preview::detail::not_incomplete_array,
disjunction<
std::is_lvalue_reference>,
- enable_borrowed_range>
+ enable_borrowed_range_t>
>,
bool_constant<(rbegin_tag::value > 0)>
>::value, int> = 0>
diff --git a/include/preview/__ranges/ref_view.h b/include/preview/__ranges/ref_view.h
index eebc9bc..a433bb1 100644
--- a/include/preview/__ranges/ref_view.h
+++ b/include/preview/__ranges/ref_view.h
@@ -81,10 +81,10 @@ ref_view(R&) -> ref_view;
#endif
-template
-struct enable_borrowed_range> : std::true_type {};
-
} // namespace ranges
} // namespace namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::ref_view) = true;
+
#endif // PREVIEW_RANGES_REF_VIEW_H_
diff --git a/include/preview/__ranges/rend.h b/include/preview/__ranges/rend.h
index 0bf5294..cc6765d 100644
--- a/include/preview/__ranges/rend.h
+++ b/include/preview/__ranges/rend.h
@@ -78,7 +78,7 @@ struct rend_niebloid {
preview::detail::not_incomplete_array,
disjunction<
std::is_lvalue_reference>,
- enable_borrowed_range>
+ enable_borrowed_range_t>
>,
bool_constant<(rend_tag::value > 0)>
>::value, int> = 0>
diff --git a/include/preview/__ranges/subrange.h b/include/preview/__ranges/subrange.h
index b7cfb49..f83ea69 100644
--- a/include/preview/__ranges/subrange.h
+++ b/include/preview/__ranges/subrange.h
@@ -374,9 +374,6 @@ constexpr auto get(subrange&& r) {
return detail::get_subrange::get(std::move(r));
}
-template
-struct enable_borrowed_range> : std::true_type {};
-
} // namespace ranges
namespace internal {
@@ -407,4 +404,7 @@ using ::preview::ranges::get;
} // namespace std
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::subrange) = true;
+
#endif // PREVIEW_RANGES_SUBRANGE_H_
diff --git a/include/preview/__ranges/views/as_const_view.h b/include/preview/__ranges/views/as_const_view.h
index 0cd34bd..25a8ae4 100644
--- a/include/preview/__ranges/views/as_const_view.h
+++ b/include/preview/__ranges/views/as_const_view.h
@@ -80,10 +80,11 @@ as_const_view(R&&) -> as_const_view>;
#endif
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::as_const_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_AS_CONST_VIEW_H_
diff --git a/include/preview/__ranges/views/common_view.h b/include/preview/__ranges/views/common_view.h
index 89b1b85..12e1925 100644
--- a/include/preview/__ranges/views/common_view.h
+++ b/include/preview/__ranges/views/common_view.h
@@ -108,10 +108,11 @@ constexpr common_view> make_common_view(R&& r) {
return common_view>(std::forward(r));
}
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::common_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_COMMON_VIEW_H_
diff --git a/include/preview/__ranges/views/drop_view.h b/include/preview/__ranges/views/drop_view.h
index 8d13567..1a7028f 100644
--- a/include/preview/__ranges/views/drop_view.h
+++ b/include/preview/__ranges/views/drop_view.h
@@ -140,10 +140,11 @@ drop_view(R&&, range_difference_t) -> drop_view>;
#endif
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::drop_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_DROP_VIEW_H_
diff --git a/include/preview/__ranges/views/drop_while_view.h b/include/preview/__ranges/views/drop_while_view.h
index bc3077d..8c8d7c9 100644
--- a/include/preview/__ranges/views/drop_while_view.h
+++ b/include/preview/__ranges/views/drop_while_view.h
@@ -85,10 +85,11 @@ constexpr auto make_drop_while_view(R&& r, Pred&& pred) {
return drop_while_view, std::decay_t>(std::forward(r), std::forward(pred));
}
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::drop_while_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_DROP_WHILE_VIEW_H_
diff --git a/include/preview/__ranges/views/elements_view.h b/include/preview/__ranges/views/elements_view.h
index f5ecd4b..3d3022e 100644
--- a/include/preview/__ranges/views/elements_view.h
+++ b/include/preview/__ranges/views/elements_view.h
@@ -416,10 +416,11 @@ class elements_view : public view_interface> {
V base_;
};
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::elements_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_ELEMENTS_VIEW_H_
diff --git a/include/preview/__ranges/views/empty_view.h b/include/preview/__ranges/views/empty_view.h
index b6956ff..5c10d21 100644
--- a/include/preview/__ranges/views/empty_view.h
+++ b/include/preview/__ranges/views/empty_view.h
@@ -31,9 +31,6 @@ class empty_view : public ranges::view_interface> {
static constexpr bool empty() noexcept { return true; }
};
-template
-struct enable_borrowed_range> : std::true_type {};
-
namespace views {
template
@@ -44,4 +41,7 @@ PREVIEW_INLINE_VARIABLE constexpr empty_view empty{};
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::empty_view) = true;
+
#endif // PREVIEW_RANGES_VIEWS_EMPTY_VIEW_H_
diff --git a/include/preview/__ranges/views/enumerate_view.h b/include/preview/__ranges/views/enumerate_view.h
index 686f31a..e637ed4 100644
--- a/include/preview/__ranges/views/enumerate_view.h
+++ b/include/preview/__ranges/views/enumerate_view.h
@@ -374,10 +374,11 @@ enumerate_view(R&&) -> enumerate_view>;
#endif
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::enumerate_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_ENUMERATE_VIEW_H_
diff --git a/include/preview/__ranges/views/iota_view.h b/include/preview/__ranges/views/iota_view.h
index c8d9731..dfc367f 100644
--- a/include/preview/__ranges/views/iota_view.h
+++ b/include/preview/__ranges/views/iota_view.h
@@ -442,11 +442,6 @@ class iota_view : public view_interface> {
Bound bound_ = Bound();
};
-
-// TODO: Implement constraints
-template
-struct enable_borrowed_range> : std::true_type {};
-
namespace views {
namespace detail {
@@ -478,4 +473,8 @@ PREVIEW_INLINE_VARIABLE constexpr detail::iota_niebloid iota{};
} // namespace ranges
} // namespace preview
+// TODO: Implement constraints
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::iota_view) = true;
+
#endif // PREVIEW_RANGES_VIEWS_IOTA_H_
diff --git a/include/preview/__ranges/views/reverse_view.h b/include/preview/__ranges/views/reverse_view.h
index a374f8d..78b0034 100644
--- a/include/preview/__ranges/views/reverse_view.h
+++ b/include/preview/__ranges/views/reverse_view.h
@@ -114,10 +114,11 @@ constexpr reverse_view> make_reverse_view(R&& r) {
return reverse_view>(std::forward(r));
}
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::reverse_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_REVERSE_VIEW_H_
diff --git a/include/preview/__ranges/views/take_view.h b/include/preview/__ranges/views/take_view.h
index 32d638c..2e8a481 100644
--- a/include/preview/__ranges/views/take_view.h
+++ b/include/preview/__ranges/views/take_view.h
@@ -282,10 +282,11 @@ take_view(R&&, ranges::range_difference_t) -> take_view>;
#endif
-template
-struct enable_borrowed_range> : enable_borrowed_range {};
-
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::take_view)
+ = preview::ranges::enable_borrowed_range;
+
#endif // PREVIEW_RANGES_VIEWS_TAKE_VIEW_H_
diff --git a/include/preview/__ranges/views/zip_view.h b/include/preview/__ranges/views/zip_view.h
index 51b1bee..5351cb3 100644
--- a/include/preview/__ranges/views/zip_view.h
+++ b/include/preview/__ranges/views/zip_view.h
@@ -21,6 +21,7 @@
#include "preview/__iterator/sized_sentinel_for.h"
#include "preview/__ranges/begin.h"
#include "preview/__ranges/bidirectional_range.h"
+#include "preview/__ranges/enable_borrowed_range.h"
#include "preview/__ranges/common_range.h"
#include "preview/__ranges/forward_range.h"
#include "preview/__ranges/input_range.h"
@@ -550,4 +551,8 @@ zip_view(Rs&&...) -> zip_view...>;
} // namespace ranges
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::ranges::zip_view)
+ = preview::conjunction...>::value;
+
#endif // PREVIEW_RANGES_VIEWS_ZIP_VIEW_H_
diff --git a/include/preview/__span/span.h b/include/preview/__span/span.h
index 3e82227..f59a525 100644
--- a/include/preview/__span/span.h
+++ b/include/preview/__span/span.h
@@ -321,9 +321,6 @@ class span : private detail::span_storage_t {
}
};
-template
-struct ranges::enable_borrowed_range> : std::true_type {};
-
template
struct ranges::enable_view> : std::true_type {};
@@ -348,4 +345,7 @@ span(R&&) -> span>>;
} // namespace preview
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::span) = true;
+
#endif // PREVIEW_SPAN_SPAN_H_
diff --git a/include/preview/string_view.h b/include/preview/string_view.h
index adce23c..b682662 100644
--- a/include/preview/string_view.h
+++ b/include/preview/string_view.h
@@ -627,10 +627,6 @@ constexpr wstring_view operator ""_sv(const wchar_t* str, std::size_t len) noexc
} // namespace string_view_literals
} // namespace literals
-template
-struct ranges::enable_borrowed_range>
- : std::true_type {};
-
template
struct ranges::enable_view> : std::true_type {};
@@ -687,4 +683,7 @@ struct hash {
} // namespace std
+template
+PREVIEW_SPECIALIZE_ENABLE_BORROWED_RANGE(preview::basic_string_view) = true;
+
#endif // PREVIEW_STRING_VIEW_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9671d70..48f2e4f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -130,6 +130,8 @@ function(preview_add_multi_version_test name_prefix test_src)
target_compile_options(${name_prefix}_${std}
PRIVATE "/bigobj"
PRIVATE "/WX")
+ target_compile_definitions(${name_prefix}_${std}
+ PRIVATE _CRT_SECURE_NO_WARNINGS)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_compile_options(${name_prefix}_${std}
PRIVATE "-Wall"
diff --git a/test/ranges.cc b/test/ranges.cc
index 242f206..01cba1b 100644
--- a/test/ranges.cc
+++ b/test/ranges.cc
@@ -1,13 +1,277 @@
#include "preview/ranges.h"
-#include "preview/string_view.h"
#include "gtest.h"
#include
+#include
+#include
#include
#include
-// TODO: Write test
-TEST(VERSIONED(Ranges), basics) {}
+#include "preview/algorithm.h"
+#include "preview/concepts.h"
+#include "preview/span.h"
+#include "preview/string_view.h"
+
+TEST(VERSIONED(Ranges), basics) {
+ auto const ints = {0, 1, 2, 3, 4, 5};
+ auto even = [](int i) { return 0 == i % 2; };
+ auto square = [](int i) { return i * i; };
+
+ // the "pipe" syntax of composing the views:
+ for (int i : ints | preview::views::filter(even) | preview::views::transform(square))
+ std::cout << i << ' ';
+
+ auto cr = ints | preview::views::filter(even) | preview::views::transform(square) | preview::views::common;
+ const auto answer = {0, 4, 16};
+ EXPECT_TRUE(std::equal(cr.begin(), cr.end(), answer.begin(), answer.end()));
+
+ std::cout << '\n';
+
+ // a traditional "functional" composing syntax:
+ for (int i : preview::views::transform(preview::views::filter(ints, even), square))
+ std::cout << i << ' ';
+
+ auto t = preview::views::transform(preview::views::filter(ints, even), square);
+ EXPECT_TRUE(std::equal(t.begin(), t.end(), answer.begin(), answer.end()));
+}
+
+TEST(VERSIONED(Ranges), ranges_begin) {
+ std::vector v{3, 1, 4};
+ auto vi = preview::ranges::begin(v);
+ auto vci = preview::ranges::cbegin(v);
+ EXPECT_EQ(*vi, 3);
+ EXPECT_EQ(*vi, *vci);
+
+ EXPECT_EQ(*++vi, 1);
+
+ EXPECT_EQ(*++vci, 1); // OK: vci is modifiable object
+
+ *vi = 42; // OK: vi points to mutable element
+ EXPECT_EQ(*vi, 42);
+ EXPECT_EQ(v[1], 42);
+ EXPECT_FALSE((std::is_assignable::value));
+ // *vci = 13; // Error: vci points to immutable element
+
+ int a[]{-5, 10, 15};
+ auto ai = preview::ranges::begin(a); // works with C-arrays as well
+ EXPECT_EQ(*ai, -5);
+ *ai = 42; // OK
+ EXPECT_EQ(*ai, 42);
+ EXPECT_EQ(a[0], 42);
+}
+
+TEST(VERSIONED(Ranges), ranges_end) {
+ std::vector vec{3, 1, 4};
+ EXPECT_TRUE (preview::ranges::find(vec, 5) == preview::ranges::end(vec));
+
+ int arr[]{5, 10, 15};
+ EXPECT_TRUE (preview::ranges::find(arr, 5) != preview::ranges::end(arr));
+}
+
+TEST(VERSIONED(Ranges), ranges_cbegin) {
+ std::vector v{3, 1, 4};
+ auto vi = preview::ranges::cbegin(v);
+ EXPECT_EQ(3, *vi);
+ ++vi; // OK, constant-iterator object is mutable
+ EXPECT_EQ(1, *vi);
+ EXPECT_FALSE((std::is_assignable::value));
+
+ int a[]{3, 1, 4};
+ auto ai = preview::ranges::cbegin(a); // cbegin works with C-arrays as well
+ EXPECT_EQ(3, *ai);
+ EXPECT_EQ(*(ai + 1), 1);
+ EXPECT_FALSE((std::is_assignable::value));
+ // *ai = 13; // Error: read-only variable is not assignable
+}
+
+TEST(VERSIONED(Ranges), ranges_cend) {
+ std::vector vec{3, 1, 4};
+ int arr[]{5, 10, 15};
+
+ EXPECT_EQ(preview::ranges::find(vec, 5), preview::ranges::cend(vec));
+ EXPECT_NE(preview::ranges::find(arr, 5), preview::ranges::cend(arr));
+}
+
+TEST(VERSIONED(Ranges), ranges_rbegin) {
+ std::vector v = {3, 1, 4};
+ auto vi = preview::ranges::rbegin(v);
+ EXPECT_EQ(*vi, 4);
+ *vi = 42; // OK
+ EXPECT_EQ(*vi, 42);
+ EXPECT_EQ(v.back(), 42);
+
+ int a[] = {-5, 10, 15};
+ auto ai = preview::ranges::rbegin(a);
+ EXPECT_EQ(*ai, 15);
+ *ai = 42; // OK
+ EXPECT_EQ(*ai, 42);
+ EXPECT_EQ(a[2], 42);
+
+ EXPECT_FALSE ((preview::is_invocable>::value));
+ // ill-formed: the argument is a rvalue
+
+ auto si = preview::ranges::rbegin(preview::span{a}); // OK
+ static_assert(preview::ranges::enable_borrowed_range<
+ std::remove_cv_t{a})>>, "");
+ *si = 43; // OK
+ EXPECT_EQ(*si, 43);
+ EXPECT_EQ(a[2], 43);
+}
+
+TEST(VERSIONED(Ranges), ranges_rend) {
+ std::vector v = {3, 1, 4};
+ namespace ranges = preview::ranges;
+ EXPECT_TRUE (ranges::find(ranges::rbegin(v), ranges::rend(v), 5) == ranges::rend(v));
+
+ int a[] = {5, 10, 15};
+ EXPECT_TRUE (ranges::find(ranges::rbegin(a), ranges::rend(a), 5) != ranges::rend(a));
+}
+
+TEST(VERSIONED(Ranges), ranges_crbegin) {
+ std::vector v{3, 1, 4};
+ auto vi = preview::ranges::crbegin(v);
+ EXPECT_EQ(*vi, 4);
+ ++vi; // OK, iterator object is mutable
+ EXPECT_EQ(*vi, 1);
+ EXPECT_FALSE((std::is_assignable::value));
+ // *vi = 13; // Error: underlying element is read-only
+
+ int a[]{-5, 10, 15};
+ auto ai = preview::ranges::crbegin(a);
+ EXPECT_EQ(*ai, 15);
+
+ // auto x_x = preview::ranges::crbegin(std::vector{6, 6, 6});
+ // ill-formed: the argument is a rvalue (see Notes ↑)
+ EXPECT_FALSE((preview::is_invocable>::value));
+
+ auto si = preview::ranges::crbegin(preview::span{a}); // OK
+ EXPECT_EQ(*si, 15);
+ static_assert(
+ preview::ranges::enable_borrowed_range<
+ std::remove_cv_t{a})>
+ >,
+ "");
+}
+
+TEST(VERSIONED(Ranges), ranges_crend) {
+ int a[]{4, 6, -3, 9, 10};
+ const int b[]{10, 9, -3, 6, 4};
+
+ namespace ranges = preview::ranges;
+ EXPECT_TRUE(preview::ranges::equal(
+ ranges::rbegin(a), ranges::rend(a),
+ ranges::begin(b), ranges::end(b)
+ ));
+
+ std::cout << "Vector backwards: ";
+ std::vector v{4, 6, -3, 9, 10};
+ EXPECT_TRUE(std::equal(ranges::rbegin(v), ranges::rend(v), b, b + 5));
+}
+
+TEST(VERSIONED(Ranges), ranges_size) {
+ auto v = std::vector{};
+ EXPECT_EQ(preview::ranges::size(v), 0);
+
+ auto il = {7}; // std::initializer_list
+ EXPECT_EQ(preview::ranges::size(il), 1);
+
+ int array[]{4, 5}; // array has a known bound
+ EXPECT_EQ(preview::ranges::size(array), 2);
+
+ EXPECT_FALSE(std::is_signed::value);
+}
+
+TEST(VERSIONED(Ranges), ranges_ssize) {
+ std::array arr{1, 2, 3, 4, 5};
+ auto s = preview::ranges::ssize(arr);
+ EXPECT_EQ(s, 5);
+ EXPECT_TRUE(std::is_signed::value);
+
+ for (--s; s >= 0; --s) {}
+ EXPECT_EQ(s, -1);
+}
+
+TEST(VERSIONED(Ranges), ranges_empty) {
+ {
+ auto v = std::vector{1, 2, 3};
+ EXPECT_FALSE(preview::ranges::empty(v));
+ v.clear();
+ EXPECT_TRUE (preview::ranges::empty(v));
+ }
+ {
+ auto il = {7, 8, 9};
+ EXPECT_FALSE(preview::ranges::empty(il));
+ EXPECT_TRUE (preview::ranges::empty(std::initializer_list