diff --git a/README.md b/README.md index eea84fb..b2c40f7 100644 --- a/README.md +++ b/README.md @@ -717,16 +717,16 @@ Description | `ranges::chunk_view`
`views::chunk` | ![][c23no] | | | `ranges::chunk_by_view`
`views::chunk_by` | ![][c23no] | | | `ranges::concat_view`
`views::concat` | ![][c26ok] | | - | `ranges::begin` | ![][c20ok] | | - | `ranges::end` | ![][c20ok] | | - | `ranges::cbegin` | ![][c20ok] | | - | `ranges::cend` | ![][c20ok] | | - | `ranges::crbegin` | ![][c20ok] | | - | `ranges::crend` | ![][c20ok] | | - | `ranges::size` | ![][c20ok] | | - | `ranges::ssize` | ![][c20ok] | | - | `ranges::empty` | ![][c20ok] | | - | `ranges::data` | ![][c20ok] | | + | `ranges::begin` | ![][c20ok] | ![][c23ok] | + | `ranges::end` | ![][c20ok] | ![][c23ok] | + | `ranges::cbegin` | ![][c20ok] | ![][c23ok] | + | `ranges::cend` | ![][c20ok] | ![][c23ok] | + | `ranges::crbegin` | ![][c20ok] | ![][c23ok] | + | `ranges::crend` | ![][c20ok] | ![][c23ok] | + | `ranges::size` | ![][c20ok] | ![][c23ok] | + | `ranges::ssize` | ![][c20ok] | ![][c23ok] | + | `ranges::empty` | ![][c20ok] | ![][c23ok] | + | `ranges::data` | ![][c20ok] | ![][c23ok] | | `ranges::cdata` | ![][c20ok] | ![][c23ok] | | `ranges::subrange_kind` | ![][c20ok] | | | `ranges::from_range_t`
`ranges::from_range` | ![][c23ok] | | diff --git a/include/preview/__ranges/begin.h b/include/preview/__ranges/begin.h index 4dbf108..868fcb1 100644 --- a/include/preview/__ranges/begin.h +++ b/include/preview/__ranges/begin.h @@ -68,7 +68,7 @@ struct begin_category : std::conditional_t< disjunction< std::is_lvalue_reference, - enable_borrowed_range> + enable_borrowed_range_t> >::value, typename begin_category_impl::category, return_category<0> diff --git a/include/preview/__ranges/borrowed_range.h b/include/preview/__ranges/borrowed_range.h index 587a523..6a8b167 100644 --- a/include/preview/__ranges/borrowed_range.h +++ b/include/preview/__ranges/borrowed_range.h @@ -22,7 +22,7 @@ struct borrowed_range range, disjunction< std::is_lvalue_reference, - enable_borrowed_range> + enable_borrowed_range_t> > > {}; diff --git a/include/preview/__ranges/cbegin.h b/include/preview/__ranges/cbegin.h index 93ad94d..da3e129 100644 --- a/include/preview/__ranges/cbegin.h +++ b/include/preview/__ranges/cbegin.h @@ -21,7 +21,7 @@ namespace detail { struct cbegin_niebloid { template, - enable_borrowed_range> + enable_borrowed_range_t> >::value, int> = 0> constexpr auto operator()(T&& t) const { return const_iterator( diff --git a/include/preview/__ranges/cdata.h b/include/preview/__ranges/cdata.h index d51ed1c..1ca1d57 100644 --- a/include/preview/__ranges/cdata.h +++ b/include/preview/__ranges/cdata.h @@ -23,7 +23,7 @@ namespace detail { struct cdata_niebloid { template, - enable_borrowed_range> + enable_borrowed_range_t> >::value, int> = 0> constexpr std::remove_reference_t>* operator()(T&& t) const { return preview::ranges::as_const_pointer(ranges::data(possibly_const_range(t))); diff --git a/include/preview/__ranges/cend.h b/include/preview/__ranges/cend.h index 9938939..d8c3225 100644 --- a/include/preview/__ranges/cend.h +++ b/include/preview/__ranges/cend.h @@ -21,7 +21,7 @@ namespace detail { struct cend_niebloid { template, - enable_borrowed_range> + enable_borrowed_range_t> >::value, int> = 0> constexpr auto operator()(T&& t) const { return preview::const_sentinel(ranges::end(possibly_const_range(t))); diff --git a/include/preview/__ranges/crbegin.h b/include/preview/__ranges/crbegin.h index 3581a59..ef13c2b 100644 --- a/include/preview/__ranges/crbegin.h +++ b/include/preview/__ranges/crbegin.h @@ -21,7 +21,7 @@ namespace detail { struct crbegin_niebloid { template, - enable_borrowed_range> + enable_borrowed_range_t> >::value, int> = 0> constexpr auto operator()(T&& t) const { return preview::const_iterator(ranges::rbegin(possibly_const_range(t))); diff --git a/include/preview/__ranges/crend.h b/include/preview/__ranges/crend.h index 638b716..4f24a24 100644 --- a/include/preview/__ranges/crend.h +++ b/include/preview/__ranges/crend.h @@ -21,7 +21,7 @@ namespace detail { struct crend_niebloid { template, - enable_borrowed_range> + enable_borrowed_range_t> >::value, int> = 0> constexpr auto operator()(T&& t) const { return preview::const_sentinel(ranges::rend(possibly_const_range(t))); diff --git a/include/preview/__ranges/data.h b/include/preview/__ranges/data.h index e340e46..39c8f00 100644 --- a/include/preview/__ranges/data.h +++ b/include/preview/__ranges/data.h @@ -11,8 +11,9 @@ #include "preview/__core/decay_copy.h" #include "preview/__iterator/contiguous_iterator.h" #include "preview/__memory/to_address.h" +#include "preview/__ranges/detail/not_incomplete_array.h" #include "preview/__ranges/begin.h" -#include "preview/__type_traits/detail/return_category.h" +#include "preview/__ranges/range_reference_t.h" #include "preview/__type_traits/disjunction.h" #include "preview/__type_traits/void_t.h" @@ -20,66 +21,77 @@ namespace preview { namespace ranges { namespace detail { -using preview::detail::return_category; - -template -struct data_member_check_2 : std::false_type { - using category = return_category<0>; -}; -template -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{})); + } + { + int array[] = {4, 5, 6}; // array has a known bound + EXPECT_FALSE(preview::ranges::empty(array)); + } + { + struct Scanty : private std::vector + { + using std::vector::begin; + using std::vector::end; + using std::vector::push_back; + // Note: both empty() and size() are hidden + }; + + Scanty y; + EXPECT_TRUE (preview::ranges::empty(y)); + y.push_back(42); + EXPECT_FALSE(preview::ranges::empty(y)); + } +} + +TEST(VERSIONED(Ranges), ranges_data) { + std::string s{"Hello world!\n"}; + + char a[20]; // storage for a C-style string + preview::ranges::data(s); + std::strcpy(a, preview::ranges::data(s)); + // [data(s), data(s) + size(s)] is guaranteed to be an NTBS + EXPECT_TRUE((std::strncmp(a, s.c_str(), 20) == 0)); +} + +TEST(VERSIONED(Ranges), ranges_cdata) { + std::string src {"hello world!\n"}; + +// preview::ranges::cdata(src)[0] = 'H'; // error, src.data() is treated as read-only + EXPECT_FALSE((std::is_assignable::value)); + + preview::ranges::data(src)[0] = 'H'; // OK, src.data() is a non-const storage + EXPECT_EQ(src[0], 'H'); + + char dst[20]; // storage for a C-style string + std::strcpy(dst, preview::ranges::cdata(src)); + EXPECT_TRUE((std::strncmp(dst, src.c_str(), 20) == 0)); + // [data(src), data(src) + size(src)] is guaranteed to be an NTBS +} + +TEST(VERSIONED(Ranges), ranges_dangling) { + auto get_array_by_value = [] { + return std::array{0, 1, 0, 1}; + }; + auto dangling_iter = preview::ranges::max_element(get_array_by_value()); + static_assert(std::is_same::value, ""); + static_assert(preview::dereferenceable::value == false, ""); + // *dangling_iter << '\n'; // compilation error: no match for 'operator*' + // (operand type is 'std::ranges::dangling') + + auto get_persistent_array = []() -> const std::array& { + static constexpr std::array a{0, 1, 0, 1}; + return a; + }; + auto valid_iter = preview::ranges::max_element(get_persistent_array()); + static_assert(!std::is_same::value, ""); + EXPECT_EQ(*valid_iter, 1); + + auto get_string_view = [] { return preview::string_view{"alpha"}; }; + auto valid_iter2 = preview::ranges::min_element(get_string_view()); + // OK: std::basic_string_view models borrowed_range + static_assert(!std::is_same::value, ""); + EXPECT_EQ(*valid_iter2, 'a'); +} TEST(VERSIONED(Ranges), to) { auto map = preview::views::iota('A', 'E') | diff --git a/test/ranges_concepts.cc b/test/ranges_concepts.cc new file mode 100644 index 0000000..6eac2f7 --- /dev/null +++ b/test/ranges_concepts.cc @@ -0,0 +1,39 @@ +#include "preview/ranges.h" +#include "gtest.h" + +#include +#include +#include +#include +#include + +#include "preview/algorithm.h" +#include "preview/concepts.h" +#include "preview/span.h" +#include "preview/string_view.h" + + +TEST(VERSIONED(RangesConcepts), range) { + // A minimum range + struct SimpleRange + { + int* begin(); + int* end(); + }; + static_assert(preview::ranges::range::value, ""); + + // not a range: no begin/end + struct NotRange + { + int t {}; + }; + static_assert(!preview::ranges::range::value, ""); + + // not a range: begin does not return an input_or_output_iterator + struct NotRange2 + { + void* begin(); + int* end(); + }; + static_assert(!preview::ranges::range::value, ""); +}