diff --git a/include/oneapi/dpl/internal/binary_search_impl.h b/include/oneapi/dpl/internal/binary_search_impl.h index dd8daff3f67..e34da66ada7 100644 --- a/include/oneapi/dpl/internal/binary_search_impl.h +++ b/include/oneapi/dpl/internal/binary_search_impl.h @@ -62,17 +62,17 @@ struct __custom_brick using std::get; if constexpr (func == search_algorithm::lower_bound) { - get<2>(acc[idx]) = oneapi::dpl::__internal::__shars_lower_bound(get<0>(acc.tuple()), start_orig, end_orig, + get<2>(acc[idx]) = oneapi::dpl::__internal::__shars_lower_bound(get<0>(acc.base()), start_orig, end_orig, get<1>(acc[idx]), comp); } else if constexpr (func == search_algorithm::upper_bound) { - get<2>(acc[idx]) = oneapi::dpl::__internal::__shars_upper_bound(get<0>(acc.tuple()), start_orig, end_orig, + get<2>(acc[idx]) = oneapi::dpl::__internal::__shars_upper_bound(get<0>(acc.base()), start_orig, end_orig, get<1>(acc[idx]), comp); } else { - auto value = oneapi::dpl::__internal::__shars_lower_bound(get<0>(acc.tuple()), start_orig, end_orig, + auto value = oneapi::dpl::__internal::__shars_lower_bound(get<0>(acc.base()), start_orig, end_orig, get<1>(acc[idx]), comp); get<2>(acc[idx]) = (value != end_orig) && (get<1>(acc[idx]) == get<0>(acc[value])); } diff --git a/include/oneapi/dpl/pstl/hetero/dpcpp/parallel_backend_sycl_reduce_then_scan.h b/include/oneapi/dpl/pstl/hetero/dpcpp/parallel_backend_sycl_reduce_then_scan.h index aa709954cb0..654267ac82f 100644 --- a/include/oneapi/dpl/pstl/hetero/dpcpp/parallel_backend_sycl_reduce_then_scan.h +++ b/include/oneapi/dpl/pstl/hetero/dpcpp/parallel_backend_sycl_reduce_then_scan.h @@ -88,7 +88,7 @@ struct __extract_range_from_zip auto operator()(const _InRng& __in_rng) const { - return std::get<_EleId>(__in_rng.tuple()); + return std::get<_EleId>(__in_rng.base()); } }; @@ -186,7 +186,7 @@ struct __write_red_by_seg using std::get; // Get source tuple - auto&& __tuple = __out_rng.tuple(); + auto&& __tuple = __out_rng.base(); auto __out_keys = get<0>(__tuple); auto __out_values = get<1>(__tuple); @@ -386,7 +386,7 @@ struct __gen_set_mask operator()(const _InRng& __in_rng, std::size_t __id) const { // Get tuple from source range - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); // First we must extract individual sequences from zip iterator because they may not have the same length, // dereferencing is dangerous @@ -642,13 +642,13 @@ struct __get_bounds_partitioned operator()(const _Rng& __in_rng, const _IndexT __id) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); auto __rng_tmp_diag = std::get<2>(__tuple); // set a temp storage sequence using _SizeType = std::common_type_t< - std::make_unsigned_t(__in_rng.tuple())))>, - std::make_unsigned_t(__in_rng.tuple())))>, + std::make_unsigned_t(__in_rng.base())))>, + std::make_unsigned_t(__in_rng.base())))>, std::make_unsigned_t>; // Establish bounds of ranges for the tile from sparse partitioning pass kernel @@ -677,7 +677,7 @@ struct __get_bounds_simple operator()(const _Rng& __in_rng, const _IndexT) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); const auto __rng1 = std::get<0>(__tuple); // first sequence const auto __rng2 = std::get<1>(__tuple); // second sequence @@ -771,7 +771,7 @@ struct __gen_set_balanced_path calc_and_store_balanced_path(_InRng& __in_rng, _IndexT __id, _BoundsProviderLocal __get_bounds_local) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); // First we must extract individual sequences from zip iterator because they may not have the same length, // dereferencing is dangerous @@ -819,7 +819,7 @@ struct __gen_set_balanced_path operator()(const _InRng& __in_rng, _IndexT __id, TempData& __temp_data) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); // First we must extract individual sequences from zip iterator because they may not have the same length, // dereferencing is dangerous @@ -892,7 +892,7 @@ struct __gen_set_op_from_known_balanced_path operator()(const _InRng& __in_rng, _IndexT __id, _TempData& __output_data) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); // First we must extract individual sequences from zip iterator because they may not have the same length, // dereferencing is dangerous @@ -973,7 +973,7 @@ struct __gen_red_by_seg_reduce_input operator()(const _InRng& __in_rng, std::size_t __id, TempData&) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); const auto __in_keys = std::get<0>(__tuple); const auto __in_vals = std::get<1>(__tuple); @@ -1000,8 +1000,8 @@ struct __gen_scan_by_seg_reduce_input auto operator()(const _InRng& __in_rng, std::size_t __id, TempData&) const { - // Get source tuple - auto&& __tuple = __in_rng.tuple(); + // Get source base + auto&& __tuple = __in_rng.base(); const auto __in_keys = std::get<0>(__tuple); const auto __in_vals = std::get<1>(__tuple); @@ -1030,7 +1030,7 @@ struct __gen_red_by_seg_scan_input operator()(const _InRng& __in_rng, std::size_t __id, TempData&) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); const auto __in_keys = std::get<0>(__tuple); const auto __in_vals = std::get<1>(__tuple); @@ -1083,7 +1083,7 @@ struct __gen_scan_by_seg_scan_input operator()(const _InRng& __in_rng, std::size_t __id, TempData&) const { // Get source tuple - auto&& __tuple = __in_rng.tuple(); + auto&& __tuple = __in_rng.base(); const auto __in_keys = std::get<0>(__tuple); const auto __in_vals = std::get<1>(__tuple); diff --git a/include/oneapi/dpl/pstl/hetero/dpcpp/sycl_traits.h b/include/oneapi/dpl/pstl/hetero/dpcpp/sycl_traits.h index d176fa29440..29def1d9f48 100644 --- a/include/oneapi/dpl/pstl/hetero/dpcpp/sycl_traits.h +++ b/include/oneapi/dpl/pstl/hetero/dpcpp/sycl_traits.h @@ -24,6 +24,10 @@ #ifndef _ONEDPL_SYCL_TRAITS_H #define _ONEDPL_SYCL_TRAITS_H +#if _ONEDPL_CPP20_RANGES_PRESENT +# include +#endif + #if _ONEDPL_SYCL_DEVICE_COPYABLE_SPECIALIZATION_BROKEN // Prior to the particular version of SYCL library implementation, sycl::is_device_copyable relied upon a second // template parameter to resolve ambiguity with the general is_trivially_copyable trait. This does not follow the SYCL @@ -926,6 +930,41 @@ struct sycl::is_device_copyable<_ONEDPL_SPECIALIZE_FOR(oneapi::dpl::permutation_ { }; +// zip_view device copyable specializations + +namespace oneapi::dpl::__ranges +{ + +template +class zip_view; + +} // namespace oneapi::dpl::__ranges + +template +struct sycl::is_device_copyable<_ONEDPL_SPECIALIZE_FOR(oneapi::dpl::__ranges::zip_view, _Ranges...)> + : oneapi::dpl::__internal::__are_all_device_copyable<_Ranges...> +{ +}; + +#if _ONEDPL_CPP20_RANGES_PRESENT + +namespace oneapi::dpl::ranges::__internal +{ + +template + requires((std::ranges::view<_Views> && ...) && (sizeof...(_Views) > 0)) +class zip_view; + +} // namespace oneapi::dpl::ranges::__internal + +template +struct sycl::is_device_copyable<_ONEDPL_SPECIALIZE_FOR(oneapi::dpl::ranges::__internal::zip_view, _Views...)> + : oneapi::dpl::__internal::__are_all_device_copyable<_Views...> +{ +}; + +#endif // _ONEDPL_CPP20_RANGES_PRESENT + #undef _ONEDPL_SPECIALIZE_FOR #endif // _ONEDPL_SYCL_TRAITS_H diff --git a/include/oneapi/dpl/pstl/hetero/dpcpp/unseq_backend_sycl.h b/include/oneapi/dpl/pstl/hetero/dpcpp/unseq_backend_sycl.h index f1da4c2cb26..c051c904876 100644 --- a/include/oneapi/dpl/pstl/hetero/dpcpp/unseq_backend_sycl.h +++ b/include/oneapi/dpl/pstl/hetero/dpcpp/unseq_backend_sycl.h @@ -691,7 +691,7 @@ struct __create_mask _ValueType operator()(const _Idx __idx, const oneapi::dpl::__ranges::zip_view<_Ranges...>& __input) const { - bool __mask_value = __pred(std::get<0>(__input.tuple()), __idx); + bool __mask_value = __pred(std::get<0>(__input.base()), __idx); std::get<1>(__input[__idx]) = __mask_value; return _ValueType(__mask_value); } @@ -1279,7 +1279,7 @@ class __brick_set_op using std::get; // Get source tuple - auto&& __tuple = __inout_acc.tuple(); + auto&& __tuple = __inout_acc.base(); auto __a = get<0>(__tuple); // first sequence auto __b = get<1>(__tuple); // second sequence diff --git a/include/oneapi/dpl/pstl/hetero/dpcpp/utils_ranges_sycl.h b/include/oneapi/dpl/pstl/hetero/dpcpp/utils_ranges_sycl.h index 1fa148e79ad..215eff8bb30 100644 --- a/include/oneapi/dpl/pstl/hetero/dpcpp/utils_ranges_sycl.h +++ b/include/oneapi/dpl/pstl/hetero/dpcpp/utils_ranges_sycl.h @@ -253,6 +253,12 @@ using val_t = typename ::std::iterator_traits<_Iter>::value_type; //range/zip_view/all_view/ variadic utilities +#if _ONEDPL_CPP20_RANGES_PRESENT +namespace _dpl_ranges_zip = oneapi::dpl::ranges::__internal; +#else +namespace _dpl_ranges_zip = oneapi::dpl::__ranges; +#endif //_ONEDPL_CPP20_RANGES_PRESENT + //forward declaration required for _require_access_args template void @@ -272,10 +278,10 @@ struct _require_access_args template void -__require_access_zip(sycl::handler& __cgh, oneapi::dpl::__ranges::zip_view<_Ranges...>& __zip) +__require_access_zip(sycl::handler& __cgh, _dpl_ranges_zip::zip_view<_Ranges...>& __zip) { const ::std::size_t __num_ranges = sizeof...(_Ranges); - oneapi::dpl::__ranges::invoke(__zip.tuple(), _require_access_args{__cgh}, + oneapi::dpl::__ranges::invoke(__zip.base(), _require_access_args{__cgh}, ::std::make_index_sequence<__num_ranges>()); } @@ -295,7 +301,7 @@ __require_access_range(sycl::handler& __cgh, oneapi::dpl::__ranges::all_view void -__require_access_range(sycl::handler& __cgh, zip_view<_Ranges...>& zip_rng) +__require_access_range(sycl::handler& __cgh, _dpl_ranges_zip::zip_view<_Ranges...>& zip_rng) { __require_access_zip(__cgh, zip_rng); } diff --git a/include/oneapi/dpl/pstl/onedpl_config.h b/include/oneapi/dpl/pstl/onedpl_config.h index 123dd1d9c5c..7140d32750e 100644 --- a/include/oneapi/dpl/pstl/onedpl_config.h +++ b/include/oneapi/dpl/pstl/onedpl_config.h @@ -292,6 +292,21 @@ # define _ONEDPL_CPP26_DEFAULT_VALUE_TYPE_PRESENT 0 #endif +// std::views::all on rvalue non-view ranges requires P2415R2 owning_view. +// __cpp_lib_ranges >= 202110L +// - libstdc++ (GCC or Clang+libstdc++): available since GCC 12 +// - libc++ (Clang+libc++): available since LLVM 16 +// - MSVC STL: available since C++23 +#if defined(__cpp_lib_ranges) +# define _ONEDPL_CPP20_OWNING_VIEW_PRESENT (__cpp_lib_ranges >= 202110L) +#elif defined(__GLIBCXX__) +# define _ONEDPL_CPP20_OWNING_VIEW_PRESENT (__GLIBCXX__ >= 20220728) +#elif defined(_LIBCPP_VERSION) +# define _ONEDPL_CPP20_OWNING_VIEW_PRESENT (_LIBCPP_VERSION >= 16000) +#else +# define _ONEDPL_CPP20_OWNING_VIEW_PRESENT (_ONEDPL___cplusplus >= 202302L) +#endif + // When C++20 concepts are available, we must use std::tuple as a proxy reference to satisfy iterator concepts, which // requires the changes to std::tuple in P2321R2 and the tuple-like basic_common_reference specialization in P2165R4. #define _ONEDPL_CAN_USE_STD_TUPLE_PROXY_ITERATOR \ diff --git a/include/oneapi/dpl/pstl/ranges_defs.h b/include/oneapi/dpl/pstl/ranges_defs.h index 39f67ed8589..a6980443f1b 100644 --- a/include/oneapi/dpl/pstl/ranges_defs.h +++ b/include/oneapi/dpl/pstl/ranges_defs.h @@ -21,6 +21,8 @@ #if _ONEDPL_CPP20_RANGES_PRESENT #include +//support zip_view (like in C++23) for C++20 +#include "zip_view_impl.h" #endif #include "utils_ranges.h" @@ -43,7 +45,11 @@ namespace ranges using oneapi::dpl::__ranges::all_view; #endif // _ONEDPL_BACKEND_SYCL using oneapi::dpl::__ranges::guard_view; +#if _ONEDPL_CPP20_RANGES_PRESENT +using oneapi::dpl::ranges::__internal::zip_view; +#else using oneapi::dpl::__ranges::zip_view; +#endif //_ONEDPL_CPP20_RANGES_PRESENT //views using __nanorange::nano::ranges::drop_view; @@ -72,9 +78,20 @@ using __nanorange::nano::views::take; using __nanorange::nano::views::transform; using __nanorange::nano::subrange; +#if _ONEDPL_CPP20_RANGES_PRESENT +using oneapi::dpl::ranges::__internal::zip; +#endif //_ONEDPL_CPP20_RANGES_PRESENT } // namespace views } // namespace ranges + +#if _ONEDPL_CPP20_RANGES_PRESENT +namespace views +{ +using oneapi::dpl::ranges::__internal::zip; +} // namespace views +#endif //_ONEDPL_CPP20_RANGES_PRESENT + } // namespace experimental } // namespace dpl } // namespace oneapi diff --git a/include/oneapi/dpl/pstl/tuple_impl.h b/include/oneapi/dpl/pstl/tuple_impl.h index babb1bacf69..15a6c6630ee 100644 --- a/include/oneapi/dpl/pstl/tuple_impl.h +++ b/include/oneapi/dpl/pstl/tuple_impl.h @@ -416,7 +416,12 @@ struct tuple return get_impl()(::std::move(*this)); } - tuple() = default; + template , std::is_default_constructible...>, int> = 0> + tuple() : holder{}, next{} + { + } //The std::tuple value-initializes all elements, so we also follow this. tuple(const tuple& other) = default; tuple(tuple&& other) = default; template > @@ -499,6 +504,15 @@ struct tuple return *this; } + template + const tuple& + operator=(const tuple& other) const + { + holder.value = other.holder.value; + next = other.next; + return *this; + } + // if T1 is deduced with reference, compiler generates deleted operator= and, // since "template operator=" is not considered as operator= overload // the deleted operator= has a preference during lookup @@ -592,6 +606,11 @@ struct tuple<> { return *this; } + const tuple& + operator=(const std::tuple<>&) const + { + return *this; + } friend constexpr bool operator==(const tuple&, const tuple&) { diff --git a/include/oneapi/dpl/pstl/utils_ranges.h b/include/oneapi/dpl/pstl/utils_ranges.h index 13ae811f66a..2453d0288f8 100644 --- a/include/oneapi/dpl/pstl/utils_ranges.h +++ b/include/oneapi/dpl/pstl/utils_ranges.h @@ -381,7 +381,7 @@ class zip_view } _tuple_ranges_t - tuple() const + base() const { return __m_ranges; } diff --git a/include/oneapi/dpl/pstl/zip_view_impl.h b/include/oneapi/dpl/pstl/zip_view_impl.h new file mode 100644 index 00000000000..3bb952da11c --- /dev/null +++ b/include/oneapi/dpl/pstl/zip_view_impl.h @@ -0,0 +1,587 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +#ifndef _ONEDPL_ZIP_VIEW_IMPL_H +#define _ONEDPL_ZIP_VIEW_IMPL_H + +#if _ONEDPL_CPP20_RANGES_PRESENT + +# include +# include + +# include "tuple_impl.h" +# include "iterator_impl.h" + +namespace oneapi +{ +namespace dpl +{ + +namespace ranges +{ + +namespace __internal +{ + +template +using __maybe_const = std::conditional_t<_Const, const _T, _T>; + +template +concept __all_forward = (std::ranges::forward_range<__maybe_const<_C, _Views>> && ...); + +template +concept __all_bidirectional = (std::ranges::bidirectional_range<__maybe_const<_C, _Views>> && ...); + +template +concept __all_random_access = (std::ranges::random_access_range<__maybe_const<_C, _Views>> && ...); + +// Determine when a zip_view can be a "common range" (where begin() and end() return the same type). +// This is true in three cases: +// 1. Only one range is being zipped and it's a common range +// 2. All ranges are common ranges but NOT all bidirectional (simpler iteration logic) +// 3. All ranges are both random-access AND sized (can calculate end position directly) +// For details see https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2321r2.html#when-is-zip_view-a-common_range +template +concept __zip_is_common = + (sizeof...(_Rs) == 1 && (std::ranges::common_range<_Rs> && ...)) || + (!(std::ranges::bidirectional_range<_Rs> && ...) && (std::ranges::common_range<_Rs> && ...)) || + ((std::ranges::random_access_range<_Rs> && ...) && (std::ranges::sized_range<_Rs> && ...)); + +template +struct __declare_iterator_category +{ +}; + +template + requires __all_forward<_Const, _Views...> +struct __declare_iterator_category<_Const, _Views...> +{ + using iterator_category = std::input_iterator_tag; +}; + +template +concept __simple_view = std::ranges::view<_R> && std::ranges::range && + std::same_as, std::ranges::iterator_t> && + std::same_as, std::ranges::sentinel_t>; + +template +void +__apply_to_tuple_impl(_F __f, _Tuple& __t, std::index_sequence<_Ip...>) +{ + (void(__f(std::get<_Ip>(__t))), ...); +} + +template +decltype(auto) +__apply_to_tuple_impl(_ReturnAdapter __tr, _F __f, _Tuple& __t, std::index_sequence<_Ip...>) +{ + return __tr(__f(std::get<_Ip>(__t))...); +} + +template +void +__apply_to_tuples_impl(_F __f, _Tuple1& __t1, _Tuple2& __t2, std::index_sequence<_Ip...>) +{ + (__f(std::get<_Ip>(__t1), std::get<_Ip>(__t2)), ...); +} + +template +void +__apply_to_tuple(_F __f, _Tuple& __t) +{ + __apply_to_tuple_impl(__f, __t, std::make_index_sequence>{}); +} + +template +decltype(auto) +__apply_to_tuple(_F __f, _Tuple& __t, _ReturnAdapter __tr) +{ + return __apply_to_tuple_impl(__tr, __f, __t, std::make_index_sequence>{}); +} + +template +void +__apply_to_tuples(_F __f, _Tuple1& __t1, _Tuple2& __t2) +{ + static_assert(std::tuple_size_v<_Tuple1> == std::tuple_size_v<_Tuple2>); + + __apply_to_tuples_impl(__f, __t1, __t2, std::make_index_sequence>{}); +} + +template + requires((std::ranges::view<_Views> && ...) && (sizeof...(_Views) > 0)) +class zip_view : public std::ranges::view_interface> +{ + template + using __tuple_type = oneapi::dpl::__internal::tuple<_Types...>; + + public: + zip_view() = default; + constexpr explicit zip_view(_Views... __views) : __views(std::move(__views)...) {} + + //forward declaration of sentinel classes + template + class sentinel; + + template + class iterator : public __internal::__declare_iterator_category<_Const, _Views...> + { + public: + using iterator_concept = std::conditional_t< + __internal::__all_random_access<_Const, _Views...>, std::random_access_iterator_tag, + std::conditional_t<__internal::__all_bidirectional<_Const, _Views...>, std::bidirectional_iterator_tag, + std::conditional_t<__internal::__all_forward<_Const, _Views...>, + std::forward_iterator_tag, std::input_iterator_tag>>>; + + using value_type = __tuple_type>...>; + using difference_type = + std::common_type_t>...>; + + private: + using __reference_type = + __tuple_type>...>; + using __rvalue_reference_type = + __tuple_type>...>; + + using __iterators_type = __tuple_type>...>; + + public: + iterator() = default; + constexpr iterator(iterator __i) + requires _Const && + (std::convertible_to, + std::ranges::iterator_t<__internal::__maybe_const<_Const, _Views>>> && + ...) + : __current(std::move(__i.__current)) + { + } + + private: + constexpr explicit iterator(__iterators_type __current) : __current(std::move(__current)) {} + + template + static constexpr _Tp + __abs(_Tp __t) + { + return __t < 0 ? -__t : __t; + } + + public: + template + operator oneapi::dpl::zip_iterator<_Iterators...>() const + { + auto __adaptor = [](auto&&... __iterators) -> decltype(auto) { + return oneapi::dpl::make_zip_iterator(std::forward(__iterators)...); + }; + return __internal::__apply_to_tuple([](auto __it) -> decltype(auto) { return __it; }, __current, __adaptor); + } + + constexpr decltype(auto) + operator*() const + { + auto __tr = [](auto&&... __args) -> decltype(auto) { + return __reference_type(std::forward(__args)...); + }; + return __internal::__apply_to_tuple([](auto& __it) -> decltype(auto) { return *__it; }, __current, __tr); + } + + constexpr decltype(auto) + operator[](difference_type __n) const + requires __internal::__all_random_access<_Const, _Views...> + { + return *(*this + __n); + } + + constexpr iterator& + operator++() + { + __internal::__apply_to_tuple([](auto& __it) -> decltype(auto) { return ++__it; }, __current); + return *this; + } + + constexpr void + operator++(int) + { + ++*this; + } + + constexpr iterator + operator++(int) + requires __internal::__all_forward<_Const, _Views...> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr iterator& + operator--() + requires __internal::__all_bidirectional<_Const, _Views...> + { + __internal::__apply_to_tuple([](auto& __it) { return --__it; }, __current); + return *this; + } + + constexpr iterator + operator--(int) + requires __internal::__all_bidirectional<_Const, _Views...> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + constexpr iterator& + operator+=(difference_type __n) + requires __internal::__all_random_access<_Const, _Views...> + { + __internal::__apply_to_tuple([__n](auto& __it) { return __it += __n; }, __current); + return *this; + } + + constexpr iterator& + operator-=(difference_type __n) + requires __internal::__all_random_access<_Const, _Views...> + { + __internal::__apply_to_tuple([__n](auto& __it) { return __it -= __n; }, __current); + return *this; + } + + friend constexpr bool + operator==(const iterator& __x, const iterator& __y) + requires(std::equality_comparable>> && + ...) + { + if constexpr (__internal::__all_bidirectional<_Const, _Views...>) + { + return __x.__current == __y.__current; + } + else + { + return __x.__compare_equal(__y, std::make_index_sequence()); + } + } + + template + requires(std::sentinel_for>, + std::ranges::iterator_t<__internal::__maybe_const<_Const, _Views>>> && + ...) + friend constexpr bool + operator==(const iterator& __x, const sentinel<_OtherConst>& __y) + { + return __x.__compare_with_sentinels(__y.__get_end(), std::make_index_sequence()); + } + + friend constexpr auto + operator<=>(const iterator& __x, const iterator& __y) + requires __internal::__all_random_access<_Const, _Views...> + { + if (__x.__current < __y.__current) + return std::weak_ordering::less; + else if (__x.__current == __y.__current) + return std::weak_ordering::equivalent; + return std::weak_ordering::greater; //__x.current > __y.__current + } + + friend constexpr auto + operator-(const iterator& __x, const iterator& __y) + requires(std::sized_sentinel_for>, + std::ranges::iterator_t<__internal::__maybe_const<_Const, _Views>>> && + ...) + { + auto __calc_val = [&](std::index_sequence<_In...>) { + return std::ranges::min( + {difference_type(std::get<_In>(__x.__current) - std::get<_In>(__y.__current))...}, std::less{}, + [](auto __a) { return iterator::__abs(__a); }); + }; + + return __calc_val(std::make_index_sequence()); + } + + template + requires(std::sized_sentinel_for>, + std::ranges::iterator_t<__internal::__maybe_const<_Const, _Views>>> && + ...) + friend constexpr difference_type + operator-(const iterator& __x, const sentinel<_OtherConst>& __y) + { + auto __calc_val = [&](std::index_sequence<_In...>) { + return std::ranges::min( + {difference_type(std::get<_In>(__x.__current) - std::get<_In>(__y.__get_end()))...}, std::less{}, + [](auto __a) { return iterator::__abs(__a); }); + }; + + return __calc_val(std::make_index_sequence()); + } + + template + requires(std::sized_sentinel_for>, + std::ranges::iterator_t<__internal::__maybe_const<_Const, _Views>>> && + ...) + friend constexpr difference_type + operator-(const sentinel<_OtherConst>& __y, const iterator& __x) + { + return -(__x - __y); + } + + friend constexpr iterator + operator+(iterator __it, difference_type __n) + requires __internal::__all_random_access<_Const, _Views...> + { + return __it += __n; + } + + friend constexpr iterator + operator+(difference_type __n, iterator __it) + requires __internal::__all_random_access<_Const, _Views...> + { + return __it += __n; + } + + friend constexpr iterator + operator-(iterator __it, difference_type __n) + requires __internal::__all_random_access<_Const, _Views...> + { + return __it -= __n; + } + + friend constexpr decltype(auto) + iter_move(const iterator& __x) noexcept( + (noexcept(std::ranges::iter_move( + std::declval>&>())) && + ...) && + (std::is_nothrow_move_constructible_v< + std::ranges::range_rvalue_reference_t<__internal::__maybe_const<_Const, _Views>>> && + ...)) + { + auto __tr = [](auto&&... __args) -> decltype(auto) { + return __rvalue_reference_type(std::forward(__args)...); + }; + return __internal::__apply_to_tuple(std::ranges::iter_move, __x.__current, __tr); + } + + friend constexpr void + iter_swap(const iterator& __x, const iterator& __y) noexcept( + (noexcept(std::ranges::iter_swap( + std::declval>&>(), + std::declval>&>())) && + ...)) + requires(std::indirectly_swappable>> && + ...) + { + __internal::__apply_to_tuples(std::ranges::iter_swap, __x.__current, __y.__current); + } + + private: + template + constexpr bool + __compare_equal(const iterator& __y, std::index_sequence<_In...>) const + { + return ((std::get<_In>(__current) == std::get<_In>(__y.__current)) || ...); + } + + template + constexpr bool + __compare_with_sentinels(const _SentinelsTuple& __sentinels, std::index_sequence<_In...>) const + { + return ((std::get<_In>(__current) == std::get<_In>(__sentinels)) || ...); + } + + friend class zip_view; + + __iterators_type __current; + }; // class iterator + + template + class sentinel + { + using difference_type = + std::common_type_t>...>; + + template + constexpr explicit sentinel(_Sentinels... __sentinels) : __end(std::move(__sentinels)...) + { + } + + public: + sentinel() = default; + constexpr sentinel(sentinel __i) + requires _Const && + (std::convertible_to, + std::ranges::sentinel_t<__internal::__maybe_const<_Const, _Views>>> && + ...) + : __end(std::move(__i.__end)) + { + } + + private: + friend class zip_view; + +# if defined(_MSC_VER) + //required for CL compiler, which does not find the friend iterator class + public: +# endif + decltype(auto) + __get_end() const + { + return __end; + } + + __tuple_type>...> __end; + }; // class sentinel + + constexpr auto + begin() + requires(!(__internal::__simple_view<_Views> && ...)) + { + using __iterators_type = __tuple_type>...>; + auto __tr = [](auto&&... __args) { + return iterator(__iterators_type(std::forward(__args)...)); + }; + return __internal::__apply_to_tuple(std::ranges::begin, __views, __tr); + } + + constexpr auto + begin() const + requires(std::ranges::range && ...) + { + using __iterators_type = __tuple_type>...>; + auto __tr = [](auto&&... __args) { + return iterator(__iterators_type(std::forward(__args)...)); + }; + return __internal::__apply_to_tuple(std::ranges::begin, __views, __tr); + } + + constexpr auto + end() + requires(!(__internal::__simple_view<_Views> && ...)) + { + if constexpr (!__internal::__zip_is_common<_Views...>) + { + auto __tr = [](auto&&... __args) { return sentinel(std::forward(__args)...); }; + return __internal::__apply_to_tuple(std::ranges::end, __views, __tr); + } + else if constexpr ((std::ranges::random_access_range<_Views> && ...)) + { + auto __it = begin(); + __it += static_cast(size()); + return __it; + } + else + { + using __iterators_type = __tuple_type>...>; + auto __tr = [](auto&&... __args) { + return iterator(__iterators_type(std::forward(__args)...)); + }; + return __internal::__apply_to_tuple(std::ranges::end, __views, __tr); + } + } + + constexpr auto + end() const + requires(std::ranges::range && ...) + { + if constexpr (!__internal::__zip_is_common) + { + auto __tr = [](auto&&... __args) { return sentinel(std::forward(__args)...); }; + return __internal::__apply_to_tuple(std::ranges::end, __views, __tr); + } + else if constexpr ((std::ranges::random_access_range && ...)) + { + auto __it = begin(); + __it += static_cast(size()); + return __it; + } + else + { + using __iterators_type = __tuple_type>...>; + auto __tr = [](auto&&... __args) { + return iterator(__iterators_type(std::forward(__args)...)); + }; + return __internal::__apply_to_tuple(std::ranges::end, __views, __tr); + } + } + + constexpr auto + size() + requires(std::ranges::sized_range<_Views> && ...) + { + auto __tr = [](auto... __args) { + using _CT = std::make_unsigned_t>; + return std::ranges::min({_CT(__args)...}); + }; + + return __internal::__apply_to_tuple(std::ranges::size, __views, __tr); + } + + constexpr auto + size() const + requires(std::ranges::sized_range && ...) + { + auto __tr = [](auto... __args) { + using _CT = std::make_unsigned_t>; + return std::ranges::min({_CT(__args)...}); + }; + + return __internal::__apply_to_tuple(std::ranges::size, __views, __tr); + } + + const __tuple_type<_Views...>& + base() const + { + return __views; // Exposing the tuple of views for use in SYCL access requirement checks. Not part of the public API. + } + + private: + __tuple_type<_Views...> __views; +}; // class zip_view + +template +zip_view(_Rs&&...) -> zip_view...>; + +struct zip_fn +{ + template + constexpr auto + operator()(_Ranges&&... __rs) const + -> decltype(oneapi::dpl::ranges::__internal::zip_view...>( + std::forward<_Ranges>(__rs)...)) + { + return oneapi::dpl::ranges::__internal::zip_view...>(std::forward<_Ranges>(__rs)...); + } + + constexpr auto + operator()() const + { + return std::ranges::empty_view>{}; + } +}; + +inline constexpr oneapi::dpl::ranges::__internal::zip_fn zip{}; + +} // namespace __internal + +} // namespace ranges + +} // namespace dpl +} // namespace oneapi + +template +inline constexpr bool std::ranges::enable_borrowed_range> = + (std::ranges::enable_borrowed_range<_Ranges> && ...); + +#endif //_ONEDPL_CPP20_RANGES_PRESENT + +#endif //_ONEDPL_ZIP_VIEW_IMPL_H diff --git a/test/general/implementation_details/internal_tuple.pass.cpp b/test/general/implementation_details/internal_tuple.pass.cpp index ff5535120ed..ed230379f38 100644 --- a/test/general/implementation_details/internal_tuple.pass.cpp +++ b/test/general/implementation_details/internal_tuple.pass.cpp @@ -93,6 +93,19 @@ main() test_tuple(std::tuple{1, 2, 3}, std::tuple{1, 2, 3}); test_tuple(std::tuple{1, 2, 3}, std::tuple{0, 2, 4}); test_tuple(std::tuple<>{}, std::tuple<>{}); + + //checking const assignment operator + { + int x(5); + int y(6); + int a(7); + int b(8); + + const oneapi::dpl::__internal::tuple tup1(x, y); + oneapi::dpl::__internal::tuple tup2(a, b); + + tup1 = tup2; + } return TestUtils::done(); } diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.arithmetic.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.arithmetic.pass.cpp new file mode 100644 index 00000000000..e1485e19fd1 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.arithmetic.pass.cpp @@ -0,0 +1,156 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// x += n; +// x + n; +// n + x; +// x -= n; +// x - n; +// x - y; +// All the arithmetic operators have the constraint `requires all-random-access;`, +// except `operator-(x, y)` which instead has the constraint +// `requires (sized_sentinel_for>, +// iterator_t>> && ...);` + + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +concept canPlusEqual = requires(T& t, U& u) { t += u; }; + +template +concept canMinusEqual = requires(T& t, U& u) { t -= u; }; + +void test() { + int buffer1[5] = {1, 2, 3, 4, 5}; + int buffer2[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + + SizedRandomAccessView a{buffer1}; + static_assert(std::ranges::random_access_range); + std::array b{4.1, 3.2, 4.3, 0.1, 0.2}; + static_assert(std::ranges::contiguous_range); + { + // operator+(x, n) and operator+= + dpl_ranges::zip_view v(a, b); + auto it1 = v.begin(); + + auto it2 = it1 + 3; + auto [x2, y2] = *it2; + assert(&x2 == &(a[3])); + assert(&y2 == &(b[3])); + + auto it3 = 3 + it1; + auto [x3, y3] = *it3; + assert(&x3 == &(a[3])); + assert(&y3 == &(b[3])); + + it1 += 3; + assert(it1 == it2); + auto [x1, y1] = *it2; + assert(&x1 == &(a[3])); + assert(&y1 == &(b[3])); + + using Iter = decltype(it1); + static_assert(canPlusEqual); + } + + { + // operator-(x, n) and operator-= + dpl_ranges::zip_view v(a, b); + auto it1 = v.end(); + + auto it2 = it1 - 3; + auto [x2, y2] = *it2; + assert(&x2 == &(a[2])); + assert(&y2 == &(b[2])); + + it1 -= 3; + assert(it1 == it2); + auto [x1, y1] = *it2; + assert(&x1 == &(a[2])); + assert(&y1 == &(b[2])); + + using Iter = decltype(it1); + static_assert(canMinusEqual); + } + + { + // operator-(x, y) + dpl_ranges::zip_view v(a, b); + assert((v.end() - v.begin()) == 5); + + auto it1 = v.begin() + 2; + auto it2 = v.end() - 1; + assert((it1 - it2) == -2); + } + { + // in this case sentinel is computed by getting each of the underlying sentinels, so the distance + // between begin and end for each of the underlying iterators can be different + dpl_ranges::zip_view v{ForwardSizedView(buffer1), ForwardSizedView(buffer2)}; + using View = decltype(v); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::random_access_range); + + auto it1 = v.begin(); + auto it2 = v.end(); + + // it1 : + // it2 : + assert((it1 - it2) == -5); + assert((it2 - it1) == 5); + } + + { + // One of the ranges is not random access + dpl_ranges::zip_view v(a, b, ForwardSizedView{buffer1}); + using Iter = decltype(v.begin()); + static_assert(!std::invocable, Iter, std::intptr_t>); + static_assert(!std::invocable, std::intptr_t, Iter>); + static_assert(!canPlusEqual); + static_assert(!std::invocable, Iter, std::intptr_t>); + static_assert(std::invocable, Iter, Iter>); + static_assert(!canMinusEqual); + } + + { + // One of the ranges does not have sized sentinel + dpl_ranges::zip_view v(a, b, InputCommonView{buffer1}); + using Iter = decltype(v.begin()); + static_assert(!std::invocable, Iter, Iter>); + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.compare.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.compare.pass.cpp new file mode 100644 index 00000000000..bd2448df23a --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.compare.pass.cpp @@ -0,0 +1,271 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// friend constexpr bool operator==(const iterator& x, const iterator& y) +// requires (equality_comparable>> && ...); +// friend constexpr bool operator<(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr bool operator>(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr bool operator<=(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr bool operator>=(const iterator& x, const iterator& y) +// requires all-random-access; +// friend constexpr auto operator<=>(const iterator& x, const iterator& y) +// requires all-random-access && +// (three_way_comparable>> && ...); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +// This is for testing that zip iterator never calls underlying iterator's >, >=, <=, !=. +// The spec indicates that zip iterator's >= is negating zip iterator's < instead of calling underlying iterator's >=. +// Declare all the operations >, >=, <= etc to make it satisfy random_access_iterator concept, +// but not define them. If the zip iterator's >,>=, <=, etc isn't implemented in the way defined by the standard +// but instead calling underlying iterator's >,>=,<=, we will get a linker error for the runtime tests and +// non-constant expression for the compile time tests. +struct LessThanIterator { + int* it_ = nullptr; + LessThanIterator() = default; + constexpr LessThanIterator(int* it) : it_(it) {} + + using iterator_category = std::random_access_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + constexpr int& operator*() const { return *it_; } + constexpr int& operator[](difference_type n) const { return it_[n]; } + constexpr LessThanIterator& operator++() { + ++it_; + return *this; + } + constexpr LessThanIterator& operator--() { + --it_; + return *this; + } + constexpr LessThanIterator operator++(int) { return LessThanIterator(it_++); } + constexpr LessThanIterator operator--(int) { return LessThanIterator(it_--); } + + constexpr LessThanIterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + constexpr LessThanIterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + + constexpr friend LessThanIterator operator+(LessThanIterator x, difference_type n) { + x += n; + return x; + } + constexpr friend LessThanIterator operator+(difference_type n, LessThanIterator x) { + x += n; + return x; + } + constexpr friend LessThanIterator operator-(LessThanIterator x, difference_type n) { + x -= n; + return x; + } + constexpr friend difference_type operator-(LessThanIterator x, LessThanIterator y) { return x.it_ - y.it_; } + + constexpr friend bool operator==(LessThanIterator const&, LessThanIterator const&) = default; + friend bool operator!=(LessThanIterator const&, LessThanIterator const&); + + constexpr friend bool operator<(LessThanIterator const& x, LessThanIterator const& y) { return x.it_ < y.it_; } + friend bool operator<=(LessThanIterator const&, LessThanIterator const&); + friend bool operator>(LessThanIterator const&, LessThanIterator const&); + friend bool operator>=(LessThanIterator const&, LessThanIterator const&); +}; +static_assert(std::random_access_iterator); + +struct SmallerThanRange : IntBufferView { + using IntBufferView::IntBufferView; + constexpr LessThanIterator begin() const { return {buffer_}; } + constexpr LessThanIterator end() const { return {buffer_ + size_}; } +}; +static_assert(std::ranges::random_access_range); + +struct ForwardCommonView : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = forward_iterator; + + constexpr iterator begin() const { return iterator(buffer_); } + constexpr iterator end() const { return iterator(buffer_ + size_); } +}; + +constexpr void compareOperatorTest(auto&& iter1, auto&& iter2) { + assert(!(iter1 < iter1)); + assert(iter1 < iter2); + assert(!(iter2 < iter1)); + assert(iter1 <= iter1); + assert(iter1 <= iter2); + assert(!(iter2 <= iter1)); + assert(!(iter1 > iter1)); + assert(!(iter1 > iter2)); + assert(iter2 > iter1); + assert(iter1 >= iter1); + assert(!(iter1 >= iter2)); + assert(iter2 >= iter1); + assert(iter1 == iter1); + assert(!(iter1 == iter2)); + assert(iter2 == iter2); + assert(!(iter1 != iter1)); + assert(iter1 != iter2); + assert(!(iter2 != iter2)); +} + +constexpr void inequalityOperatorsDoNotExistTest(auto&& iter1, auto&& iter2) { + using Iter1 = decltype(iter1); + using Iter2 = decltype(iter2); + static_assert(!std::is_invocable_v, Iter1, Iter2>); + static_assert(!std::is_invocable_v, Iter1, Iter2>); + static_assert(!std::is_invocable_v, Iter1, Iter2>); + static_assert(!std::is_invocable_v, Iter1, Iter2>); +} + +void test() { +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // Test a new-school iterator with operator<=>; the iterator should also have operator<=>. + using It = three_way_contiguous_iterator; + using SubRange = std::ranges::subrange; + static_assert(std::three_way_comparable); + using R = dpl_ranges::zip_view; + static_assert(std::three_way_comparable>); + + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8, 9}; + auto r = dpl_ranges::views::zip(SubRange(It(a), It(a + 4)), SubRange(It(b), It(b + 5))); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + + assert((iter1 <=> iter2) == std::strong_ordering::less); + assert((iter1 <=> iter1) == std::strong_ordering::equal); + assert((iter2 <=> iter1) == std::strong_ordering::greater); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + + { + // Test an old-school iterator with no operator<=>; the transform iterator shouldn't have + // operator<=> either. + using It = random_access_iterator; + using Subrange = std::ranges::subrange; + static_assert(!std::three_way_comparable); + using R = dpl_ranges::zip_view; +#ifdef _LIBCPP_VERSION + // libc++ hasn't implemented LWG-3692 "zip_view::iterator's operator<=> is overconstrained" + static_assert(!std::three_way_comparable>); +#else + static_assert(std::three_way_comparable>); +#endif + + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8, 9}; + auto r = dpl_ranges::views::zip(Subrange(It(a), It(a + 4)), Subrange(It(b), It(b + 5))); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + } + + { + // non random_access_range + int buffer1[1] = {1}; + int buffer2[2] = {1, 2}; + + dpl_ranges::zip_view v{InputCommonView(buffer1), InputCommonView(buffer2)}; + using View = decltype(v); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + static_assert(std::ranges::common_range); + + auto it1 = v.begin(); + auto it2 = v.end(); + assert(it1 != it2); + + ++it1; + assert(it1 == it2); + + inequalityOperatorsDoNotExistTest(it1, it2); + } + + { + // in this case sentinel is computed by getting each of the underlying sentinel, so only one + // underlying iterator is comparing equal + int buffer1[1] = {1}; + int buffer2[2] = {1, 2}; + dpl_ranges::zip_view v{ForwardCommonView(buffer1), ForwardCommonView(buffer2)}; + using View = decltype(v); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::bidirectional_range); + + auto it1 = v.begin(); + auto it2 = v.end(); + assert(it1 != it2); + + ++it1; + // it1: + // it2: + assert(it1 == it2); + + inequalityOperatorsDoNotExistTest(it1, it2); + } + + { + // only < and == are needed + int a[] = {1, 2, 3, 4}; + int b[] = {5, 6, 7, 8, 9}; + auto r = dpl_ranges::views::zip(SmallerThanRange(a), SmallerThanRange(b)); + auto iter1 = r.begin(); + auto iter2 = iter1 + 1; + + compareOperatorTest(iter1, iter2); + } + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // underlying iterator does not support == + using IterNoEqualView = BasicView, sentinel_wrapper>>; + int buffer[] = {1}; + dpl_ranges::zip_view r(IterNoEqualView{buffer}); + auto it = r.begin(); + using Iter = decltype(it); + static_assert(!weakly_equality_comparable_with); + inequalityOperatorsDoNotExistTest(it, it); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.ctor.other.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.ctor.other.pass.cpp new file mode 100644 index 00000000000..bf7d87c4d80 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.ctor.other.pass.cpp @@ -0,0 +1,75 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr iterator(iterator i) +// requires Const && (convertible_to, +// iterator_t>> && ...); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +using ConstIterIncompatibleView = BasicView, forward_iterator, + random_access_iterator, random_access_iterator>; +static_assert(!std::convertible_to, + std::ranges::iterator_t>); + +void test() { + int buffer[3] = {1, 2, 3}; + + { + dpl_ranges::zip_view v(NonSimpleCommon{buffer}); + auto iter1 = v.begin(); + std::ranges::iterator_t iter2 = iter1; + assert(iter1 == iter2); + + static_assert(!std::is_same_v); + + // We cannot create a non-const iterator from a const iterator. + static_assert(!std::constructible_from); + } + + { + // underlying non-const to const not convertible + dpl_ranges::zip_view v(ConstIterIncompatibleView{buffer}); + auto iter1 = v.begin(); + auto iter2 = std::as_const(v).begin(); + + static_assert(!std::is_same_v); + + static_assert(!std::constructible_from); + static_assert(!std::constructible_from); + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.decrement.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.decrement.pass.cpp new file mode 100644 index 00000000000..ce7dd994988 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.decrement.pass.cpp @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr iterator& operator--() requires all-bidirectional; +// constexpr iterator operator--(int) requires all-bidirectional; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +concept canDecrement = requires(Iter it) { --it; } || requires(Iter it) { it--; }; + +struct NonBidi : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = forward_iterator; + constexpr iterator begin() const { return iterator(buffer_); } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(iterator(buffer_ + size_)); } +}; + +void test() { + std::array a{1, 2, 3, 4}; + std::array b{4.1, 3.2, 4.3}; + { + // all random access + dpl_ranges::zip_view v(a, b, std::views::iota(0, 5)); + auto it = v.end(); + using Iter = decltype(it); + + static_assert(std::is_same_v); + auto& it_ref = --it; + assert(&it_ref == &it); + + assert(&(std::get<0>(*it)) == &(a[2])); + assert(&(std::get<1>(*it)) == &(b[2])); + assert(std::get<2>(*it) == 2); + + static_assert(std::is_same_v); + it--; + assert(&(std::get<0>(*it)) == &(a[1])); + assert(&(std::get<1>(*it)) == &(b[1])); + assert(std::get<2>(*it) == 1); + } + + { + // all bidi+ + int buffer[2] = {1, 2}; + + dpl_ranges::zip_view v(BidiCommonView{buffer}, std::views::iota(0, 5)); + auto it = v.begin(); + using Iter = decltype(it); + + ++it; + ++it; + + static_assert(std::is_same_v); + auto& it_ref = --it; + assert(&it_ref == &it); + + assert(it == ++v.begin()); + + static_assert(std::is_same_v); + auto tmp = it--; + assert(it == v.begin()); + assert(tmp == ++v.begin()); + } + + { + // non bidi + int buffer[3] = {4, 5, 6}; + dpl_ranges::zip_view v(a, NonBidi{buffer}); + using Iter = std::ranges::iterator_t; + static_assert(!canDecrement); + } +} + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.deref.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.deref.pass.cpp new file mode 100644 index 00000000000..70c7333f672 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.deref.pass.cpp @@ -0,0 +1,105 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr auto operator*() const; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +using tuple_type = oneapi::dpl::__internal::tuple; + +void test() { + std::array a{1, 2, 3, 4}; + std::array b{4.1, 3.2, 4.3}; + { + // single range + dpl_ranges::zip_view v(a); + auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + static_assert(std::is_same_v>); + } + + { + // operator* is const + dpl_ranges::zip_view v(a); + const auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + } + + { + // two ranges with different types + dpl_ranges::zip_view v(a, b); + auto it = v.begin(); + auto [x, y] = *it; + assert(&x == &(a[0])); + assert(&y == &(b[0])); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + + x = 5; + y = 0.5; + assert(a[0] == 5); + assert(b[0] == 0.5); // exact comparison is safe: 0.5 is exactly representable in all FP precisions + } + + { + // underlying range with prvalue range_reference_t + dpl_ranges::zip_view v(a, b, std::views::iota(0, 5)); + auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(b[0])); + assert(std::get<2>(*it) == 0); + static_assert(std::is_same_v>); + } + + { + // const-correctness + dpl_ranges::zip_view v(a, std::as_const(a)); + auto it = v.begin(); + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(a[0])); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } +} + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.increment.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.increment.pass.cpp new file mode 100644 index 00000000000..cdb10ce62bf --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.increment.pass.cpp @@ -0,0 +1,150 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr iterator& operator++(); +// constexpr void operator++(int); +// constexpr iterator operator++(int) requires all_forward; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct InputRange : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = cpp20_input_iterator; + constexpr iterator begin() const { return iterator(buffer_); } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(iterator(buffer_ + size_)); } +}; + +void test() { + std::array a{1, 2, 3, 4}; + std::array b{4.1, 3.2, 4.3}; + { + // random/contiguous + dpl_ranges::zip_view v(a, b, std::views::iota(0, 5)); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(b[0])); + assert(std::get<2>(*it) == 0); + + static_assert(std::is_same_v); + + auto& it_ref = ++it; + assert(&it_ref == &it); + + assert(&(std::get<0>(*it)) == &(a[1])); + assert(&(std::get<1>(*it)) == &(b[1])); + assert(std::get<2>(*it) == 1); + + static_assert(std::is_same_v); + auto original = it; + auto copy = it++; + assert(original == copy); + assert(&(std::get<0>(*it)) == &(a[2])); + assert(&(std::get<1>(*it)) == &(b[2])); + assert(std::get<2>(*it) == 2); + } + + { + // bidi + int buffer[2] = {1, 2}; + + dpl_ranges::zip_view v(BidiCommonView{buffer}); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(buffer[0])); + + static_assert(std::is_same_v); + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(buffer[1])); + + static_assert(std::is_same_v); + auto original = it; + auto copy = it++; + assert(copy == original); + assert(&(std::get<0>(*it)) == &(buffer[2])); + } + + { + // forward + int buffer[2] = {1, 2}; + + dpl_ranges::zip_view v(ForwardSizedView{buffer}); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(buffer[0])); + + static_assert(std::is_same_v); + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(buffer[1])); + + static_assert(std::is_same_v); + auto original = it; + auto copy = it++; + assert(copy == original); + assert(&(std::get<0>(*it)) == &(buffer[2])); + } + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // all input+ + int buffer[3] = {4, 5, 6}; + dpl_ranges::zip_view v(a, InputRange{buffer}); + auto it = v.begin(); + using Iter = decltype(it); + + assert(&(std::get<0>(*it)) == &(a[0])); + assert(&(std::get<1>(*it)) == &(buffer[0])); + + static_assert(std::is_same_v); + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(a[1])); + assert(&(std::get<1>(*it)) == &(buffer[1])); + + static_assert(std::is_same_v); + it++; + assert(&(std::get<0>(*it)) == &(a[2])); + assert(&(std::get<1>(*it)) == &(buffer[2])); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +} + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.it_ctor.default.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.it_ctor.default.pass.cpp new file mode 100644 index 00000000000..b225298f2a4 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.it_ctor.default.pass.cpp @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// iterator() = default; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct PODIter { + int i; // deliberately uninitialised + + using iterator_category = std::random_access_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + constexpr int operator*() const { return i; } + + constexpr PODIter& operator++() { return *this; } + constexpr void operator++(int) {} + + friend constexpr bool operator==(const PODIter&, const PODIter&) = default; +}; + +struct IterDefaultCtrView : std::ranges::view_base { + PODIter begin() const; + PODIter end() const; +}; + +struct IterNoDefaultCtrView : std::ranges::view_base { + cpp20_input_iterator begin() const; + sentinel_wrapper> end() const; +}; + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +template +using zip_iter = std::ranges::iterator_t>; + +static_assert(!std::default_initializable>); +static_assert(!std::default_initializable>); +static_assert(!std::default_initializable>); +static_assert(std::default_initializable>); +static_assert(std::default_initializable>); + +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + +void test() { + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + using ZipIter = zip_iter; + { + ZipIter iter; + auto [x] = *iter; + assert(x == 0); // PODIter has to be initialised to have value 0 + } + + { + ZipIter iter = {}; + auto [x] = *iter; + assert(x == 0); // PODIter has to be initialised to have value 0 + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +} + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.iter_move.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.iter_move.pass.cpp new file mode 100644 index 00000000000..ff0b4e97c58 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.iter_move.pass.cpp @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// friend constexpr auto iter_move(const iterator& i) noexcept(see below); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +using tuple_type = oneapi::dpl::__internal::tuple; + +struct ThrowingMove { + ThrowingMove() = default; + ThrowingMove(ThrowingMove&&) {} +}; + +void test() { + { + // underlying iter_move noexcept + std::array a1{1, 2, 3, 4}; + const std::array a2{3.0, 4.0}; + + dpl_ranges::zip_view v(a1, a2, std::views::iota(3L)); + assert(std::ranges::iter_move(v.begin()) == std::make_tuple(1, 3.0, 3L)); + static_assert(std::is_same_v>); + + auto it = v.begin(); + static_assert(noexcept(std::ranges::iter_move(it))); + } + + { + // underlying iter_move may throw + auto throwingMoveRange = + std::views::iota(0, 2) | std::views::transform([](auto) noexcept { return ThrowingMove{}; }); + dpl_ranges::zip_view v(throwingMoveRange); + auto it = v.begin(); + static_assert(!noexcept(std::ranges::iter_move(it))); + } + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // underlying iterators' iter_move are called through ranges::iter_move + adltest::IterMoveSwapRange r1{}, r2{}; + assert(r1.iter_move_called_times == 0); + assert(r2.iter_move_called_times == 0); + dpl_ranges::zip_view v(r1, r2); + auto it = v.begin(); + { + [[maybe_unused]] auto&& i = std::ranges::iter_move(it); + assert(r1.iter_move_called_times == 1); + assert(r2.iter_move_called_times == 1); + } + { + [[maybe_unused]] auto&& i = std::ranges::iter_move(it); + assert(r1.iter_move_called_times == 2); + assert(r2.iter_move_called_times == 2); + } + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.iter_swap.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.iter_swap.pass.cpp new file mode 100644 index 00000000000..479efd33f8d --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.iter_swap.pass.cpp @@ -0,0 +1,104 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below) +// requires (indirectly_swappable>> && ...); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct ThrowingMove { + ThrowingMove() = default; + ThrowingMove(ThrowingMove&&) {} + ThrowingMove& operator=(ThrowingMove&&){return *this;} +}; + +void test() { + { + std::array a1{1, 2, 3, 4}; + // Use dyadic rationals to avoid x87 excess-precision issues with exact FP comparisons on 32-bit + std::array a2{0.5, 0.25, 0.125}; + dpl_ranges::zip_view v(a1, a2); + auto iter1 = v.begin(); + auto iter2 = ++v.begin(); + + std::ranges::iter_swap(iter1, iter2); + + assert(a1[0] == 2); + assert(a1[1] == 1); + assert(a2[0] == 0.25); + assert(a2[1] == 0.5); + + auto [x1, y1] = *iter1; + assert(&x1 == &a1[0]); + assert(&y1 == &a2[0]); + + auto [x2, y2] = *iter2; + assert(&x2 == &a1[1]); + assert(&y2 == &a2[1]); + + static_assert(noexcept(std::ranges::iter_swap(iter1, iter2))); + } + + { + // underlying iter_swap may throw + std::array iterSwapMayThrow{}; + dpl_ranges::zip_view v(iterSwapMayThrow); + auto iter1 = v.begin(); + auto iter2 = ++v.begin(); + static_assert(!noexcept(std::ranges::iter_swap(iter1, iter2))); + } + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // underlying iterators' iter_move are called through ranges::iter_swap + adltest::IterMoveSwapRange r1, r2; + assert(r1.iter_swap_called_times == 0); + assert(r2.iter_swap_called_times == 0); + + dpl_ranges::zip_view v{r1, r2}; + auto it1 = v.begin(); + auto it2 = std::ranges::next(it1, 3); + + std::ranges::iter_swap(it1, it2); + assert(r1.iter_swap_called_times == 2); + assert(r2.iter_swap_called_times == 2); + + std::ranges::iter_swap(it1, it2); + assert(r1.iter_swap_called_times == 4); + assert(r2.iter_swap_called_times == 4); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.member_types.compile.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.member_types.compile.pass.cpp new file mode 100644 index 00000000000..46d9186ce97 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.member_types.compile.pass.cpp @@ -0,0 +1,226 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// Iterator traits and member typedefs in zip_view::. + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +using tuple_type = oneapi::dpl::__internal::tuple; + +template +struct ForwardView : std::ranges::view_base { + forward_iterator begin() const; + sentinel_wrapper> end() const; +}; + +template +struct InputView : std::ranges::view_base { + cpp17_input_iterator begin() const; + sentinel_wrapper> end() const; +}; + +template +concept HasIterCategory = requires { typename T::iterator_category; }; + +template +struct DiffTypeIter { + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = T; + + int operator*() const; + DiffTypeIter& operator++(); + void operator++(int); + friend constexpr bool operator==(DiffTypeIter, DiffTypeIter) = default; +}; + +template +struct DiffTypeRange { + DiffTypeIter begin() const; + DiffTypeIter end() const; +}; + +struct Foo {}; +struct Bar {}; + +struct ConstVeryDifferentRange { + int* begin(); + int* end(); + + forward_iterator begin() const; + forward_iterator end() const; +}; + +void test() { + int buffer[] = {1, 2, 3, 4}; + { + // 2 views should have pair value_type + // random_access_iterator_tag + dpl_ranges::zip_view v(buffer, buffer); + using Iter = decltype(v.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + static_assert(HasIterCategory); + } + + { + // !=2 views should have tuple value_type + dpl_ranges::zip_view v(buffer, buffer, buffer); + using Iter = decltype(v.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(HasIterCategory); + } + + { + // bidirectional_iterator_tag + dpl_ranges::zip_view v(BidiCommonView{buffer}); + using Iter = decltype(v.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + } + + { + // forward_iterator_tag + using Iter = std::ranges::iterator_t>>; + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(HasIterCategory); + } + + { + // nested zip_view + dpl_ranges::zip_view v(buffer, buffer); + dpl_ranges::zip_view v2(buffer, v); + using Iter = decltype(v2.begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>>); +#else + static_assert(std::is_same_v>>); +#endif + static_assert(HasIterCategory); + } + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // input_iterator_tag + using Iter = std::ranges::iterator_t>>; + + static_assert(std::is_same_v); + static_assert(!HasIterCategory); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + + #if __GNUC__ && _ONEDPL_GCC_VERSION >= 120100 + { + // difference_type of single view + dpl_ranges::zip_view v{DiffTypeRange{}}; + using Iter = decltype(v.begin()); + static_assert(std::is_same_v); + } + + { + // difference_type of multiple views should be the common type + dpl_ranges::zip_view v{DiffTypeRange{}, DiffTypeRange{}}; + using Iter = decltype(v.begin()); + static_assert(std::is_same_v>); + } + #endif + + const std::array foos{Foo{}}; + std::array bars{Bar{}, Bar{}}; + { + // value_type of single view + dpl_ranges::zip_view v{foos}; + using Iter = decltype(v.begin()); + static_assert(std::is_same_v>); + } + + { + // value_type of multiple views with different value_type + dpl_ranges::zip_view v{foos, bars}; + using Iter = decltype(v.begin()); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + + #if __GNUC__ && _ONEDPL_GCC_VERSION >= 120100 + { + // const-iterator different from iterator + dpl_ranges::zip_view v{ConstVeryDifferentRange{}}; + using Iter = decltype(v.begin()); + using ConstIter = decltype(std::as_const(v).begin()); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + } + #endif +} + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() +{ +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.singular.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.singular.pass.cpp new file mode 100644 index 00000000000..cf77efd33fa --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.singular.pass.cpp @@ -0,0 +1,111 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: no-exceptions + +// If the invocation of any non-const member function of `iterator` exits via an +// exception, the iterator acquires a singular value. + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable : 4702) // unreachable code (MSVC) +#endif + +#include + +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct ThrowOnIncrementIterator { + int* it_; + + using value_type = int; + using difference_type = std::intptr_t; + using iterator_concept = std::input_iterator_tag; + + ThrowOnIncrementIterator() = default; + explicit ThrowOnIncrementIterator(int* it) : it_(it) {} + + ThrowOnIncrementIterator& operator++() { + ++it_; + throw 5; + return *this; + } + + void operator++(int) { ++it_; } + + int& operator*() const { return *it_; } + + friend bool operator==(ThrowOnIncrementIterator const&, ThrowOnIncrementIterator const&) = default; +}; + +struct ThrowOnIncrementView : IntBufferView { + ThrowOnIncrementIterator begin() const { return ThrowOnIncrementIterator{buffer_}; } + ThrowOnIncrementIterator end() const { return ThrowOnIncrementIterator{buffer_ + size_}; } +}; + +// Cannot run the test at compile time because it is not allowed to throw exceptions +void test() { + int buffer[] = {1, 2, 3}; + { + // zip iterator should be able to be destroyed after member function throws + dpl_ranges::zip_view v{ThrowOnIncrementView{buffer}}; + auto it = v.begin(); + try { + ++it; + assert(false); // should not be reached as the above expression should throw. + } catch (int e) { + assert(e == 5); + } + } + + { + // zip iterator should be able to be assigned after member function throws + dpl_ranges::zip_view v{ThrowOnIncrementView{buffer}}; + auto it = v.begin(); + try { + ++it; + assert(false); // should not be reached as the above expression should throw. + } catch (int e) { + assert(e == 5); + } + it = v.begin(); + auto [x] = *it; + assert(x == 1); + } +} + +#if defined(_MSC_VER) + #pragma warning(pop) //unreachable code +#endif + +#endif //_ENABLE_STD_RANGES_TESTING + +int main(int, char**) { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/iterator/zip_view.subscript.pass.cpp b/test/parallel_api/ranges/range.zip/iterator/zip_view.subscript.pass.cpp new file mode 100644 index 00000000000..56fa61a68de --- /dev/null +++ b/test/parallel_api/ranges/range.zip/iterator/zip_view.subscript.pass.cpp @@ -0,0 +1,84 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr auto operator[](difference_type n) const requires +// all_random_access + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +using tuple_type = oneapi::dpl::__internal::tuple; + +void test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + // random_access_range + dpl_ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0)); + auto it = v.begin(); + assert(it[0] == *it); + assert(it[2] == *(it + 2)); + assert(it[4] == *(it + 4)); + +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + + { + // contiguous_range + dpl_ranges::zip_view v(ContiguousCommonView{buffer}, ContiguousCommonView{buffer}); + auto it = v.begin(); + assert(it[0] == *it); + assert(it[2] == *(it + 2)); + assert(it[4] == *(it + 4)); + +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v>); +#else + static_assert(std::is_same_v>); +#endif + } + + { + // non random_access_range + dpl_ranges::zip_view v(BidiCommonView{buffer}); + auto iter = v.begin(); + const auto canSubscript = [](auto&& it) { return requires { it[0]; }; }; + static_assert(!canSubscript(iter)); + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/zip_view.eq.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/zip_view.eq.pass.cpp new file mode 100644 index 00000000000..c11c2facb3e --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/zip_view.eq.pass.cpp @@ -0,0 +1,166 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// template +// requires sentinel_for, iterator_t>> +// friend constexpr bool operator==(const iterator& x, const sentinel& y); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +using Iterator = random_access_iterator; +using ConstIterator = random_access_iterator; + +template +struct ComparableSentinel { + + using Iter = std::conditional_t; + Iter iter_; + + explicit ComparableSentinel() = default; + constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {} + + constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); } + + constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) { + return base(i) == base(s.iter_); + } +}; + +struct ComparableView : IntBufferView { + using IntBufferView::IntBufferView; + + constexpr auto begin() { return Iterator(buffer_); } + constexpr auto begin() const { return ConstIterator(buffer_); } + constexpr auto end() { return ComparableSentinel(Iterator(buffer_ + size_)); } + constexpr auto end() const { return ComparableSentinel(ConstIterator(buffer_ + size_)); } +}; + +struct ConstIncompatibleView : std::ranges::view_base { + cpp17_input_iterator begin(); + forward_iterator begin() const; + sentinel_wrapper> end(); + sentinel_wrapper> end() const; +}; + +void test() { + int buffer1[4] = {1, 2, 3, 4}; + int buffer2[5] = {1, 2, 3, 4, 5}; + int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + // simple-view: const and non-const have the same iterator/sentinel type + dpl_ranges::zip_view v{SimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; + static_assert(!std::ranges::common_range); + static_assert(simple_view); + + assert(v.begin() != v.end()); + assert(v.begin() + 1 != v.end()); + assert(v.begin() + 2 != v.end()); + assert(v.begin() + 3 != v.end()); + assert(v.begin() + 4 == v.end()); + } + + { + // !simple-view: const and non-const have different iterator/sentinel types + dpl_ranges::zip_view v{NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + assert(v.begin() != v.end()); + assert(v.begin() + 4 == v.end()); + + // const_iterator (const int*) converted to iterator (int*) + assert(v.begin() + 4 == std::as_const(v).end()); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(weakly_equality_comparable_with); + static_assert(!weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + } + + { + // underlying const/non-const sentinel can be compared with both const/non-const iterator + dpl_ranges::zip_view v{ComparableView(buffer1), ComparableView(buffer2)}; + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + assert(v.begin() != v.end()); + assert(v.begin() + 4 == v.end()); + assert(std::as_const(v).begin() + 4 == v.end()); + assert(std::as_const(v).begin() + 4 == std::as_const(v).end()); + assert(v.begin() + 4 == std::as_const(v).end()); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + } + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // underlying const/non-const sentinel cannot be compared with non-const/const iterator + dpl_ranges::zip_view v{ComparableView(buffer1), ConstIncompatibleView{}}; + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(weakly_equality_comparable_with); + static_assert(!weakly_equality_comparable_with); + static_assert(!weakly_equality_comparable_with); + static_assert(weakly_equality_comparable_with); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/zip_view.minus.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/zip_view.minus.pass.cpp new file mode 100644 index 00000000000..9b8189d5e60 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/zip_view.minus.pass.cpp @@ -0,0 +1,248 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// template +// requires(sized_sentinel_for>, +// iterator_t>>&&...) +// friend constexpr common_type_t>...> +// operator-(const iterator&, const sentinel&) +// +// template +// requires(sized_sentinel_for>, +// iterator_t>>&&...) +// friend constexpr common_type_t>...> +// operator-(const sentinel&, const iterator&) + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +struct convertible_forward_sized_iterator { + Base it_ = nullptr; + + using iterator_category = std::forward_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + convertible_forward_sized_iterator() = default; + constexpr convertible_forward_sized_iterator(Base it) : it_(it) {} + + template U> + constexpr convertible_forward_sized_iterator(const convertible_forward_sized_iterator& it) : it_(it.it_) {} + + constexpr decltype(*Base{}) operator*() const { return *it_; } + + constexpr convertible_forward_sized_iterator& operator++() { + ++it_; + return *this; + } + constexpr convertible_forward_sized_iterator operator++(int) { return convertible_forward_sized_iterator(it_++); } + + friend constexpr bool operator==(const convertible_forward_sized_iterator&, + const convertible_forward_sized_iterator&) = default; + + friend constexpr difference_type operator-(const convertible_forward_sized_iterator& x, + const convertible_forward_sized_iterator& y) { + return x.it_ - y.it_; + } +}; +static_assert(std::forward_iterator>); + +template +struct convertible_sized_sentinel { + Base base_; + explicit convertible_sized_sentinel() = default; + constexpr convertible_sized_sentinel(const Base& it) : base_(it) {} + + template U> + constexpr convertible_sized_sentinel(const convertible_sized_sentinel& other) : base_(other.base_) {} + + template + requires(std::convertible_to || std::convertible_to) + friend constexpr bool operator==(const convertible_sized_sentinel& s, const U& base) { + return s.base_ == base; + } + template + requires(std::convertible_to || std::convertible_to) + friend constexpr auto operator-(const convertible_sized_sentinel& s, const U& i) { + return s.base_ - i; + } + + template + requires(std::convertible_to || std::convertible_to) + friend constexpr auto operator-(const U& i, const convertible_sized_sentinel& s) { + return i - s.base_; + } +}; +static_assert(std::sized_sentinel_for>, + convertible_forward_sized_iterator<>>); +static_assert(std::sized_sentinel_for>, + convertible_forward_sized_iterator>); +static_assert(std::sized_sentinel_for>, + convertible_forward_sized_iterator>); + +struct ConstCompatibleForwardSized : IntBufferView { + using IntBufferView::IntBufferView; + + using iterator = convertible_forward_sized_iterator; + using const_iterator = convertible_forward_sized_iterator; + + constexpr iterator begin() { return {buffer_}; } + constexpr const_iterator begin() const { return {buffer_}; } + constexpr convertible_sized_sentinel end() { return iterator{buffer_ + size_}; } + constexpr convertible_sized_sentinel end() const { return const_iterator{buffer_ + size_}; } +}; + +// clang-format off +template +concept HasMinus = std::invocable,const T&, const U&>; + +template +concept SentinelHasMinus = HasMinus, std::ranges::iterator_t>; +// clang-format on + +void test() { + int buffer1[5] = {1, 2, 3, 4, 5}; + + { + // simple-view + dpl_ranges::zip_view v{ForwardSizedNonCommon(buffer1)}; + static_assert(!std::ranges::common_range); + static_assert(simple_view); + + auto it = v.begin(); + auto st = v.end(); + assert(st - it == 5); + assert(st - std::ranges::next(it, 1) == 4); + + assert(it - st == -5); + assert(std::ranges::next(it, 1) - st == -4); + static_assert(SentinelHasMinus); + } + + { + // shortest range + dpl_ranges::zip_view v(std::views::iota(0, 3), ForwardSizedNonCommon(buffer1)); + static_assert(!std::ranges::common_range); + auto it = v.begin(); + auto st = v.end(); + assert(st - it == 3); + assert(st - std::ranges::next(it, 1) == 2); + + assert(it - st == -3); + assert(std::ranges::next(it, 1) - st == -2); + static_assert(SentinelHasMinus); + } + + { + // underlying sentinel does not model sized_sentinel_for + dpl_ranges::zip_view v(std::views::iota(0), SizedRandomAccessView(buffer1)); + static_assert(!std::ranges::common_range); + static_assert(!SentinelHasMinus); + } + + { + // const incompatible: + // underlying const sentinels cannot subtract underlying iterators + // underlying sentinels cannot subtract underlying const iterators + dpl_ranges::zip_view v(NonSimpleForwardSizedNonCommon{buffer1}); + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + auto it = v.begin(); + auto const_it = std::as_const(v).begin(); + auto st = v.end(); + auto const_st = std::as_const(v).end(); + assert(it - st == -5); + assert(st - it == 5); + assert(const_it - const_st == -5); + assert(const_st - const_it == 5); + + static_assert(!HasMinus); + static_assert(!HasMinus); + static_assert(!HasMinus); + static_assert(!HasMinus); + } + + { + // const compatible allow non-const to const conversion + dpl_ranges::zip_view v(ConstCompatibleForwardSized{buffer1}); + static_assert(!std::ranges::common_range); + static_assert(!simple_view); + + using Iter = std::ranges::iterator_t; + using ConstIter = std::ranges::iterator_t; + static_assert(!std::is_same_v); + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v); + + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + static_assert(HasMinus); + + auto it = v.begin(); + auto const_it = std::as_const(v).begin(); + auto st = v.end(); + auto const_st = std::as_const(v).end(); + + assert(it - st == -5); + assert(st - it == 5); + assert(const_it - const_st == -5); + assert(const_st - const_it == 5); + assert(it - const_st == -5); + assert(const_st - it == 5); + assert(const_it - st == -5); + assert(st - const_it == 5); + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/zip_view.sen_ctor.default.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/zip_view.sen_ctor.default.pass.cpp new file mode 100644 index 00000000000..94bfcf6fd6e --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/zip_view.sen_ctor.default.pass.cpp @@ -0,0 +1,67 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// sentinel() = default; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct PODSentinel { + bool b; // deliberately uninitialised + + friend constexpr bool operator==(int*, const PODSentinel& s) { return s.b; } +}; + +struct Range : std::ranges::view_base { + int* begin() const; + PODSentinel end(); +}; + +template +struct print_type; + +void test() { + { + using R = dpl_ranges::zip_view; + using Sentinel = std::ranges::sentinel_t; + static_assert(!std::is_same_v>); + + std::ranges::iterator_t it; + + Sentinel s1; + assert(it != s1); // PODSentinel.b is initialised to false + + Sentinel s2 = {}; + assert(it != s2); // PODSentinel.b is initialised to false + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif //_ENABLE_STD_RANGES_TESTING + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/sentinel/zip_view.sen_ctor.other.pass.cpp b/test/parallel_api/ranges/range.zip/sentinel/zip_view.sen_ctor.other.pass.cpp new file mode 100644 index 00000000000..30708376c66 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/sentinel/zip_view.sen_ctor.other.pass.cpp @@ -0,0 +1,89 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr sentinel(sentinel s); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include "../types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +struct convertible_sentinel_wrapper { + explicit convertible_sentinel_wrapper() = default; + constexpr convertible_sentinel_wrapper(const T& it) : it_(it) {} + + template + requires std::convertible_to + constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper& other) : it_(other.it_) {} + + constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) { + return self.it_ == other; + } + T it_; +}; + +struct NonSimpleNonCommonConvertibleView : IntBufferView { + using IntBufferView::IntBufferView; + + constexpr int* begin() { return buffer_; } + constexpr const int* begin() const { return buffer_; } + constexpr convertible_sentinel_wrapper end() { return convertible_sentinel_wrapper(buffer_ + size_); } + constexpr convertible_sentinel_wrapper end() const { + return convertible_sentinel_wrapper(buffer_ + size_); + } +}; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +static_assert(std::convertible_to, + std::ranges::sentinel_t>); +static_assert(!simple_view); + +void test() { + int buffer1[4] = {1, 2, 3, 4}; + int buffer2[5] = {1, 2, 3, 4, 5}; + dpl_ranges::zip_view v{NonSimpleNonCommonConvertibleView(buffer1), NonSimpleNonCommonConvertibleView(buffer2)}; + static_assert(!std::ranges::common_range); + auto sent1 = v.end(); + std::ranges::sentinel_t sent2 = sent1; + static_assert(!std::is_same_v); + + assert(v.begin() != sent2); + assert(std::as_const(v).begin() != sent2); + assert(v.begin() + 4 == sent2); + assert(std::as_const(v).begin() + 4 == sent2); + + // Cannot create a non-const iterator from a const iterator. + static_assert(!std::constructible_from); +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/types.h b/test/parallel_api/ranges/range.zip/types.h new file mode 100644 index 00000000000..ce6633c135d --- /dev/null +++ b/test/parallel_api/ranges/range.zip/types.h @@ -0,0 +1,442 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H +#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H + +#include +#include + +#include "support/test_macros.h" +#include "support/test_iterators_cpp17.h" +#include "support/test_range.h" + +template +struct BufferView : std::ranges::view_base { + T* buffer_ = nullptr; + std::size_t size_ = 0; + + BufferView() = default; + template + constexpr BufferView(T (&b)[N]) : buffer_(b), size_(N) {} +}; + +using IntBufferView = BufferView; + +template +struct Common : IntBufferView { + using IntBufferView::IntBufferView; + + constexpr int* begin() + requires(!Simple) + { + return buffer_; + } + constexpr const int* begin() const { return buffer_; } + constexpr int* end() + requires(!Simple) + { + return buffer_ + size_; + } + constexpr const int* end() const { return buffer_ + size_; } +}; +using SimpleCommon = Common; +using NonSimpleCommon = Common; + +using SimpleCommonRandomAccessSized = SimpleCommon; +using NonSimpleCommonRandomAccessSized = NonSimpleCommon; + +static_assert(std::ranges::common_range>); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); +static_assert(simple_view); +static_assert(!simple_view); + +template +struct CommonNonRandom : IntBufferView { + using IntBufferView::IntBufferView; + using const_iterator = forward_iterator; + using iterator = forward_iterator; + constexpr iterator begin() + requires(!Simple) { + return iterator(buffer_); + } + constexpr const_iterator begin() const { return const_iterator(buffer_); } + constexpr iterator end() + requires(!Simple) { + return iterator(buffer_ + size_); + } + constexpr const_iterator end() const { return const_iterator(buffer_ + size_); } +}; + +using SimpleCommonNonRandom = CommonNonRandom; +using NonSimpleCommonNonRandom = CommonNonRandom; + +static_assert(std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +static_assert(simple_view); +static_assert(!simple_view); + +template +struct NonCommon : IntBufferView { + using IntBufferView::IntBufferView; + constexpr int* begin() + requires(!Simple) { + return buffer_; + } + constexpr const int* begin() const { return buffer_; } + constexpr sentinel_wrapper end() + requires(!Simple) { + return sentinel_wrapper(buffer_ + size_); + } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } +}; + +using SimpleNonCommon = NonCommon; +using NonSimpleNonCommon = NonCommon; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +static_assert(simple_view); +static_assert(!simple_view); + +template +struct NonCommonSized : IntBufferView { + using IntBufferView::IntBufferView; + constexpr int* begin() + requires(!Simple) { + return buffer_; + } + constexpr const int* begin() const { return buffer_; } + constexpr sentinel_wrapper end() + requires(!Simple) { + return sentinel_wrapper(buffer_ + size_); + } + constexpr sentinel_wrapper end() const { return sentinel_wrapper(buffer_ + size_); } + constexpr std::size_t size() const { return size_; } +}; + +using SimpleNonCommonSized = NonCommonSized; +using SimpleNonCommonRandomAccessSized = SimpleNonCommonSized; +using NonSimpleNonCommonSized = NonCommonSized; +using NonSimpleNonCommonRandomAccessSized = NonSimpleNonCommonSized; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); +static_assert(simple_view); +static_assert(!simple_view); + +template +struct NonCommonNonRandom : IntBufferView { + using IntBufferView::IntBufferView; + + using const_iterator = forward_iterator; + using iterator = forward_iterator; + + constexpr iterator begin() + requires(!Simple) { + return iterator(buffer_); + } + constexpr const_iterator begin() const { return const_iterator(buffer_); } + constexpr sentinel_wrapper end() + requires(!Simple) { + return sentinel_wrapper(iterator(buffer_ + size_)); + } + constexpr sentinel_wrapper end() const { + return sentinel_wrapper(const_iterator(buffer_ + size_)); + } +}; + +using SimpleNonCommonNonRandom = NonCommonNonRandom; +using NonSimpleNonCommonNonRandom = NonCommonNonRandom; + +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::sized_range); +static_assert(simple_view); +static_assert(!simple_view); + +template +struct BasicView : IntBufferView { + using IntBufferView::IntBufferView; + + constexpr NonConstIter begin() + requires(!std::is_same_v) { + return NonConstIter(buffer_); + } + constexpr Iter begin() const { return Iter(buffer_); } + + constexpr NonConstSent end() + requires(!std::is_same_v) { + if constexpr (std::is_same_v) { + return NonConstIter(buffer_ + size_); + } else { + return NonConstSent(NonConstIter(buffer_ + size_)); + } + } + + constexpr Sent end() const { + if constexpr (std::is_same_v) { + return Iter(buffer_ + size_); + } else { + return Sent(Iter(buffer_ + size_)); + } + } +}; + +template +struct forward_sized_iterator { + Base it_ = nullptr; + + using iterator_category = std::forward_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + using pointer = Base; + using reference = decltype(*Base{}); + + forward_sized_iterator() = default; + constexpr forward_sized_iterator(Base it) : it_(it) {} + + constexpr reference operator*() const { return *it_; } + + constexpr forward_sized_iterator& operator++() { + ++it_; + return *this; + } + constexpr forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); } + + friend constexpr bool operator==(const forward_sized_iterator&, const forward_sized_iterator&) = default; + + friend constexpr difference_type operator-(const forward_sized_iterator& x, const forward_sized_iterator& y) { + return x.it_ - y.it_; + } +}; +static_assert(std::forward_iterator>); +static_assert(std::sized_sentinel_for, forward_sized_iterator<>>); + +using ForwardSizedView = BasicView>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(simple_view); + +using NonSimpleForwardSizedView = BasicView, forward_sized_iterator, + forward_sized_iterator, forward_sized_iterator>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(!simple_view); + +using ForwardSizedNonCommon = BasicView, sized_sentinel>>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(simple_view); + +using NonSimpleForwardSizedNonCommon = + BasicView, sized_sentinel>, + forward_sized_iterator, sized_sentinel>>; +static_assert(std::ranges::forward_range); +static_assert(std::ranges::sized_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::random_access_range); +static_assert(!simple_view); + +struct SizedRandomAccessView : IntBufferView { + using IntBufferView::IntBufferView; + using iterator = random_access_iterator; + + constexpr auto begin() const { return iterator(buffer_); } + constexpr auto end() const { return sized_sentinel(iterator(buffer_ + size_)); } + + constexpr decltype(auto) operator[](std::size_t n) const { return *(begin() + n); } +}; +static_assert(std::ranges::view); +static_assert(std::ranges::random_access_range); +static_assert(std::ranges::sized_range); + +using NonSizedRandomAccessView = + BasicView, sentinel_wrapper>>; +static_assert(!std::ranges::contiguous_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::sized_range); +static_assert(simple_view); + +using NonSimpleNonSizedRandomAccessView = + BasicView, sentinel_wrapper>, + random_access_iterator, sentinel_wrapper> >; +static_assert(!std::ranges::contiguous_range); +static_assert(std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::sized_range); +static_assert(!simple_view); + +using ContiguousCommonView = BasicView; +static_assert(std::ranges::contiguous_range); +static_assert(std::ranges::common_range); +static_assert(std::ranges::sized_range); + +using ContiguousNonCommonView = BasicView>; +static_assert(std::ranges::contiguous_range); +static_assert(!std::ranges::common_range); +static_assert(!std::ranges::sized_range); + +using ContiguousNonCommonSized = BasicView>; + +static_assert(std::ranges::contiguous_range); +static_assert(!std::ranges::common_range); +static_assert(std::ranges::sized_range); + +using InputCommonView = BasicView>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(std::ranges::common_range); +static_assert(simple_view); + +using NonSimpleInputCommonView = BasicView, common_input_iterator, + common_input_iterator, common_input_iterator>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(std::ranges::common_range); +static_assert(!simple_view); + +using InputNonCommonView = BasicView, sentinel_wrapper>>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(!std::ranges::common_range); +static_assert(simple_view); + +using NonSimpleInputNonCommonView = + BasicView, sentinel_wrapper>, + common_input_iterator, sentinel_wrapper>>; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); +static_assert(!std::ranges::common_range); +static_assert(!simple_view); + +using BidiCommonView = BasicView>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +static_assert(simple_view); + +using NonSimpleBidiCommonView = BasicView, bidirectional_iterator, + bidirectional_iterator, bidirectional_iterator>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +static_assert(!simple_view); + +struct SizedBidiCommon : BidiCommonView { + using BidiCommonView::BidiCommonView; + std::size_t size() const { return base(end()) - base(begin()); } +}; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +static_assert(simple_view); + +struct NonSimpleSizedBidiCommon : NonSimpleBidiCommonView { + using NonSimpleBidiCommonView::NonSimpleBidiCommonView; + std::size_t size() const { return base(end()) - base(begin()); } +}; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(std::ranges::common_range); +static_assert(!simple_view); + +using BidiNonCommonView = BasicView, sentinel_wrapper>>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(simple_view); + +using NonSimpleBidiNonCommonView = + BasicView, sentinel_wrapper>, + bidirectional_iterator, sentinel_wrapper>>; +static_assert(!std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(!simple_view); + +using SizedBidiNonCommonView = BasicView, sized_sentinel>>; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(simple_view); + +using NonSimpleSizedBidiNonCommonView = + BasicView, sized_sentinel>, + bidirectional_iterator, sized_sentinel>>; +static_assert(std::ranges::sized_range); +static_assert(std::ranges::bidirectional_range); +static_assert(!std::ranges::random_access_range); +static_assert(!std::ranges::common_range); +static_assert(!simple_view); + +namespace adltest{ +struct iter_move_swap_iterator { + + std::reference_wrapper iter_move_called_times; + std::reference_wrapper iter_swap_called_times; + int i = 0; + + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = std::intptr_t; + + constexpr int operator*() const { return i; } + + constexpr iter_move_swap_iterator& operator++() { + ++i; + return *this; + } + constexpr void operator++(int) { ++i; } + + friend constexpr bool operator==(const iter_move_swap_iterator& x, std::default_sentinel_t) { return x.i == 5; } + + friend constexpr int iter_move(iter_move_swap_iterator const& it) { + ++it.iter_move_called_times; + return it.i; + } + friend constexpr void iter_swap(iter_move_swap_iterator const& x, iter_move_swap_iterator const& y) { + ++x.iter_swap_called_times; + ++y.iter_swap_called_times; + } +}; + +struct IterMoveSwapRange { + int iter_move_called_times = 0; + int iter_swap_called_times = 0; + constexpr auto begin() { return iter_move_swap_iterator{iter_move_called_times, iter_swap_called_times}; } + constexpr auto end() const { return std::default_sentinel; } +}; +} // namespace adltest + +#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H diff --git a/test/parallel_api/ranges/range.zip/zip_view.begin.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.begin.pass.cpp new file mode 100644 index 00000000000..f9b2acafdde --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.begin.pass.cpp @@ -0,0 +1,125 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr auto begin() requires (!(simple-view && ...)); +// constexpr auto begin() const requires (range && ...); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include +#include +#include +#include "types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +concept HasConstBegin = requires(const T& ct) { ct.begin(); }; + +template +concept HasBegin = requires(T& t) { t.begin(); }; + +template +concept HasConstAndNonConstBegin = + HasConstBegin && + requires(T& t, const T& ct) { requires !std::same_as; }; + +template +concept HasOnlyNonConstBegin = HasBegin && ! +HasConstBegin; + +template +concept HasOnlyConstBegin = HasConstBegin && ! +HasConstAndNonConstBegin; + +struct NoConstBeginView : std::ranges::view_base { + int* begin(); + int* end(); +}; + +template + using tuple_type = oneapi::dpl::__internal::tuple; + +void test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + { + // all underlying iterators should be at the begin position + dpl_ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.)); + std::same_as> decltype(auto) val = *v.begin(); + assert(val == std::make_tuple(1, 0, 2.0)); + assert(&(std::get<0>(val)) == &buffer[0]); + } + + { + // with empty range + dpl_ranges::zip_view v(SizedRandomAccessView{buffer}, std::ranges::empty_view()); + assert(v.begin() == v.end()); + } + + { + // underlying ranges all model simple-view + dpl_ranges::zip_view v(SimpleCommon{buffer}, SimpleCommon{buffer}); + static_assert(std::is_same_v); + assert(v.begin() == std::as_const(v).begin()); + auto [x, y] = *std::as_const(v).begin(); + assert(&x == &buffer[0]); + assert(&y == &buffer[0]); + + using View = decltype(v); + static_assert(HasOnlyConstBegin); + static_assert(!HasOnlyNonConstBegin); + static_assert(!HasConstAndNonConstBegin); + } + + { + // not all underlying ranges model simple-view + dpl_ranges::zip_view v(SimpleCommon{buffer}, NonSimpleNonCommon{buffer}); + static_assert(!std::is_same_v); + + assert(v.begin() == std::as_const(v).begin()); + auto [x, y] = *std::as_const(v).begin(); + assert(&x == &buffer[0]); + assert(&y == &buffer[0]); + + using View = decltype(v); + static_assert(!HasOnlyConstBegin); + static_assert(!HasOnlyNonConstBegin); + static_assert(HasConstAndNonConstBegin); + } + + { + // underlying const R is not a range + using View = dpl_ranges::zip_view; + static_assert(!HasOnlyConstBegin); + static_assert(HasOnlyNonConstBegin); + static_assert(!HasConstAndNonConstBegin); + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.borrowing.compile.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.borrowing.compile.pass.cpp new file mode 100644 index 00000000000..f96176c5cdf --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.borrowing.compile.pass.cpp @@ -0,0 +1,56 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// template +// inline constexpr bool enable_borrowed_range> = +// (enable_borrowed_range && ...); + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING +#include + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct Borrowed : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(std::ranges::borrowed_range); + +struct NonBorrowed : std::ranges::view_base { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::borrowed_range); + +// test borrowed_range +static_assert(std::ranges::borrowed_range>); +static_assert(std::ranges::borrowed_range>); +static_assert(!std::ranges::borrowed_range>); +static_assert(!std::ranges::borrowed_range>); +static_assert(!std::ranges::borrowed_range>); +#endif + +int main() { + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.cpo.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.cpo.pass.cpp new file mode 100644 index 00000000000..87b64fb9aef --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.cpo.pass.cpp @@ -0,0 +1,98 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// std::views::zip + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include +#include +#include +#include + +#include "types.h" + +#include + +namespace dpl = oneapi::dpl; +namespace dpl_exp = oneapi::dpl::experimental; + +template +using tuple_type = oneapi::dpl::__internal::tuple; + +static_assert(std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert( + std::is_invocable_v>); +static_assert(!std::is_invocable_v); + +void test() { + { + // zip zero arguments + auto v = dpl_exp::views::zip(); + assert(std::ranges::empty(v)); + static_assert(std::is_same_v>>); + } + + { + // zip a view + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::same_as> decltype(auto) v = + dpl_exp::views::zip(SizedRandomAccessView{buffer}); + assert(std::ranges::size(v) == 8); + static_assert(std::is_same_v, tuple_type>); + } + + { + // zip a viewable range + std::array a{1, 2, 3}; + std::same_as>>> decltype(auto) v = + dpl_exp::views::zip(a); + assert(&(std::get<0>(*v.begin())) == &(a[0])); + static_assert(std::is_same_v, tuple_type>); + } + + { + // zip the zip_view + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::same_as> decltype(auto) v = + dpl_exp::views::zip(SizedRandomAccessView{buffer}, SizedRandomAccessView{buffer}); + + std::same_as< + dpl_exp::ranges::zip_view>> decltype(auto) v2 = + dpl_exp::views::zip(v); + +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + static_assert(std::is_same_v, tuple_type>>); +#else + static_assert(std::is_same_v, tuple_type>>); +#endif + } +} + +#endif //_ENABLE_STD_RANGES_TESTING +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.ctad.compile.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.ctad.compile.pass.cpp new file mode 100644 index 00000000000..85f0c1fda61 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.ctad.compile.pass.cpp @@ -0,0 +1,62 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// template +// zip_view(Rs&&...) -> zip_view...>; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +struct Container { + int* begin() const; + int* end() const; +}; + +struct View : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +#if __GNUC__ && _ONEDPL_GCC_VERSION >= 120100 +void testCTAD() { + static_assert(std::is_same_v>>); + + static_assert(std::is_same_v, View>>); + + Container c{}; + static_assert(std::is_same_v< + decltype(dpl_ranges::zip_view(Container{}, View{}, c)), + dpl_ranges::zip_view, View, std::ranges::ref_view>>); +} +#endif + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() +{ + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} \ No newline at end of file diff --git a/test/parallel_api/ranges/range.zip/zip_view.ctor.default.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.ctor.default.pass.cpp new file mode 100644 index 00000000000..52bc63c732e --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.ctor.default.pass.cpp @@ -0,0 +1,91 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// zip_view() = default; + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include +#include + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +using tuple_type = oneapi::dpl::__internal::tuple; + +constexpr int buff[] = {1, 2, 3}; + +struct DefaultConstructibleView : std::ranges::view_base { + constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 3) {} + constexpr int const* begin() const { return begin_; } + constexpr int const* end() const { return end_; } + +private: + int const* begin_; + int const* end_; +}; + +struct NoDefaultCtrView : std::ranges::view_base { + NoDefaultCtrView() = delete; + int* begin() const; + int* end() const; +}; + +// The default constructor requires all underlying views to be default constructible. +// It is implicitly required by the tuple's constructor. If any of the iterators are +// not default constructible, zip iterator's =default would be implicitly deleted. +static_assert(std::is_default_constructible_v>); +static_assert( + std::is_default_constructible_v>); +# if !TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE +static_assert(!std::is_default_constructible_v>); +static_assert(!std::is_default_constructible_v>); +static_assert(!std::is_default_constructible_v>); +# endif + +int test() { + { + using View = dpl_ranges::zip_view; + View v = View(); // the default constructor is not explicit + assert(v.size() == 3); + auto it = v.begin(); +#ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet + using Value = std::pair; +#else + using Value = tuple_type; +#endif + assert(*it++ == Value(buff[0], buff[0])); + assert(*it++ == Value(buff[1], buff[1])); + assert(*it == Value(buff[2], buff[2])); + } + + return 0; +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.ctor.views.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.ctor.views.pass.cpp new file mode 100644 index 00000000000..e3107b18cc0 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.ctor.views.pass.cpp @@ -0,0 +1,114 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr explicit zip_view(Views...) + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include "types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +template +void conversion_test(T); + +template +concept implicitly_constructible_from = requires(Args&&... args) { conversion_test({std::move(args)...}); }; + +// test constructor is explicit +static_assert(std::constructible_from, SimpleCommon>); +static_assert(!implicitly_constructible_from, SimpleCommon>); + +static_assert(std::constructible_from, SimpleCommon, SimpleCommon>); +static_assert( + !implicitly_constructible_from, SimpleCommon, SimpleCommon>); + +struct MoveAwareView : std::ranges::view_base { + int moves = 0; + constexpr MoveAwareView() = default; + constexpr MoveAwareView(MoveAwareView&& other) : moves(other.moves + 1) { other.moves = 1; } + constexpr MoveAwareView& operator=(MoveAwareView&& other) { + moves = other.moves + 1; + other.moves = 0; + return *this; + } + constexpr const int* begin() const { return &moves; } + constexpr const int* end() const { return &moves + 1; } +}; + +template +constexpr void constructorTest(auto&& buffer1, auto&& buffer2) { + dpl_ranges::zip_view v{View1{buffer1}, View2{buffer2}}; + auto [i, j] = *v.begin(); + assert(i == buffer1[0]); + assert(j == buffer2[0]); +} + +int test() { + + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + int buffer2[4] = {9, 8, 7, 6}; + + { + // constructor from views + dpl_ranges::zip_view v(SizedRandomAccessView{buffer}, std::views::iota(0), std::ranges::single_view(2.)); + auto [i, j, k] = *v.begin(); + assert(i == 1); + assert(j == 0); + assert(k == 2.0); + } + + { + // arguments are moved once + MoveAwareView mv; + dpl_ranges::zip_view v{std::move(mv), MoveAwareView{}}; + auto [numMoves1, numMoves2] = *v.begin(); + assert(numMoves1 == 2); // one move from the local variable to parameter, one move from parameter to member + assert(numMoves2 == 1); + } + + // input and forward + { + constructorTest(buffer, buffer2); + } + + // bidi and random_access + { + constructorTest(buffer, buffer2); + } + + // contiguous + { + constructorTest(buffer, buffer2); + } + + return 0; +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.end.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.end.pass.cpp new file mode 100644 index 00000000000..e3e65f8c2f1 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.end.pass.cpp @@ -0,0 +1,409 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr auto end() requires(!(simple-view && ...)) +// constexpr auto end() const requires(range&&...) + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include + +#include "types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +// ID | simple | common | bidi | random | sized | #views | v.end() | as_const(v) +// | | | | access | | | | .end() +// ---|--------|--------|------|--------|-------|--------|----------------|--------------- +// 1 | Y | Y | Y | Y | Y | 1 | iterator | iterator +// 2 | Y | Y | Y | Y | Y | >1 | iterator | iterator +// 3 | Y | N | Y | Y | N | 1 | sentinel | sentinel +// 4 | Y | N | Y | Y | N | >1 | sentinel | sentinel +// 5 | Y | Y | Y | N | Y | 1 | iterator | iterator +// 6 | Y | Y | Y | N | Y | >1 | sentinel | sentinel +// 7 | Y | Y | Y | N | N | 1 | iterator | iterator +// 8 | Y | Y | Y | N | N | >1 | sentinel | sentinel +// 9 | Y | Y | N | N | Y | 1 | iterator | iterator +// 10 | Y | Y | N | N | Y | >1 | iterator | iterator +// 11 | Y | Y | N | N | N | 1 | iterator | iterator +// 12 | Y | Y | N | N | N | >1 | iterator | iterator +// 13 | Y | N | Y | Y | Y | 1 | iterator | iterator +// 14 | Y | N | Y | Y | Y | >1 | iterator | iterator +// 15 | Y | N | Y | N | Y | 1 | sentinel | sentinel +// 16 | Y | N | Y | N | Y | >1 | sentinel | sentinel +// 17 | Y | N | Y | N | N | 1 | sentinel | sentinel +// 18 | Y | N | Y | N | N | >1 | sentinel | sentinel +// 19 | Y | N | N | N | Y | 1 | sentinel | sentinel +// 20 | Y | N | N | N | Y | >1 | sentinel | sentinel +// 21 | Y | N | N | N | N | 1 | sentinel | sentinel +// 22 | Y | N | N | N | N | >1 | sentinel | sentinel +// 23 | N | Y | Y | Y | Y | 1 | iterator| iterator +// 24 | N | Y | Y | Y | Y | >1 | iterator| iterator +// 25 | N | N | Y | Y | N | 1 | sentinel| sentinel +// 26 | N | N | Y | Y | N | >1 | sentinel| sentinel +// 27 | N | Y | Y | N | Y | 1 | iterator| iterator +// 28 | N | Y | Y | N | Y | >1 | sentinel| sentinel +// 29 | N | Y | Y | N | N | 1 | iterator| iterator +// 30 | N | Y | Y | N | N | >1 | sentinel| sentinel +// 31 | N | Y | N | N | Y | 1 | iterator| iterator +// 32 | N | Y | N | N | Y | >1 | iterator| iterator +// 33 | N | Y | N | N | N | 1 | iterator| iterator +// 34 | N | Y | N | N | N | >1 | iterator| iterator +// 35 | N | N | Y | Y | Y | 1 | iterator| iterator +// 36 | N | N | Y | Y | Y | >1 | iterator| iterator +// 37 | N | N | Y | N | Y | 1 | sentinel| sentinel +// 38 | N | N | Y | N | Y | >1 | sentinel| sentinel +// 39 | N | N | Y | N | N | 1 | sentinel| sentinel +// 40 | N | N | Y | N | N | >1 | sentinel| sentinel +// 41 | N | N | N | N | Y | 1 | sentinel| sentinel +// 42 | N | N | N | N | Y | >1 | sentinel| sentinel +// 43 | N | N | N | N | N | 1 | sentinel| sentinel +// 44 | N | N | N | N | N | >1 | sentinel| sentinel + +void test() { + int buffer1[5] = {1, 2, 3, 4, 5}; + int buffer2[1] = {1}; + int buffer3[3] = {1, 2, 3}; + { + // test ID 1 + dpl_ranges::zip_view v{SimpleCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 2 + dpl_ranges::zip_view v{SimpleCommonRandomAccessSized(buffer1), SimpleCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 3 + dpl_ranges::zip_view v{NonSizedRandomAccessView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 4 + dpl_ranges::zip_view v{NonSizedRandomAccessView(buffer1), NonSizedRandomAccessView(buffer3)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 3 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 5 + dpl_ranges::zip_view v{SizedBidiCommon(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 6 + dpl_ranges::zip_view v{SizedBidiCommon(buffer1), SizedBidiCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 7 + dpl_ranges::zip_view v{BidiCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 8 + dpl_ranges::zip_view v{BidiCommonView(buffer1), BidiCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 9 + dpl_ranges::zip_view v{ForwardSizedView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 10 + dpl_ranges::zip_view v{ForwardSizedView(buffer1), ForwardSizedView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 11 + dpl_ranges::zip_view v{InputCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 12 + dpl_ranges::zip_view v{InputCommonView(buffer1), InputCommonView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 13 + dpl_ranges::zip_view v{SimpleNonCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 14 + dpl_ranges::zip_view v{SimpleNonCommonRandomAccessSized(buffer1), SimpleNonCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 15 + dpl_ranges::zip_view v{SizedBidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 16 + dpl_ranges::zip_view v{SizedBidiNonCommonView(buffer1), SizedBidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 17 + dpl_ranges::zip_view v{BidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 18 + dpl_ranges::zip_view v{BidiNonCommonView(buffer1), BidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 19 + dpl_ranges::zip_view v{ForwardSizedNonCommon(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 20 + dpl_ranges::zip_view v{ForwardSizedNonCommon(buffer1), ForwardSizedNonCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 21 + dpl_ranges::zip_view v{InputNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 22 + dpl_ranges::zip_view v{InputNonCommonView(buffer1), InputNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(std::is_same_v); + } + { + // test ID 23 + dpl_ranges::zip_view v{NonSimpleCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 24 + dpl_ranges::zip_view v{NonSimpleCommonRandomAccessSized(buffer1), NonSimpleCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 25 + dpl_ranges::zip_view v{NonSimpleNonSizedRandomAccessView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 26 + dpl_ranges::zip_view v{NonSimpleNonSizedRandomAccessView(buffer1), NonSimpleNonSizedRandomAccessView(buffer3)}; + static_assert(!std::ranges::common_range); + assert(v.begin() + 3 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 27 + dpl_ranges::zip_view v{NonSimpleSizedBidiCommon(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 28 + dpl_ranges::zip_view v{NonSimpleSizedBidiCommon(buffer1), NonSimpleSizedBidiCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 29 + dpl_ranges::zip_view v{NonSimpleBidiCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 30 + dpl_ranges::zip_view v{NonSimpleBidiCommonView(buffer1), NonSimpleBidiCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 31 + dpl_ranges::zip_view v{NonSimpleForwardSizedView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 32 + dpl_ranges::zip_view v{NonSimpleForwardSizedView(buffer1), NonSimpleForwardSizedView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 33 + dpl_ranges::zip_view v{NonSimpleInputCommonView(buffer1)}; + static_assert(std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 34 + dpl_ranges::zip_view v{NonSimpleInputCommonView(buffer1), NonSimpleInputCommonView(buffer2)}; + static_assert(std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 35 + dpl_ranges::zip_view v{NonSimpleNonCommonRandomAccessSized(buffer1)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 5 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 36 + dpl_ranges::zip_view v{NonSimpleNonCommonRandomAccessSized(buffer1), NonSimpleNonCommonRandomAccessSized(buffer2)}; + static_assert(std::ranges::common_range); + assert(v.begin() + 1 == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 37 + dpl_ranges::zip_view v{NonSimpleSizedBidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 38 + dpl_ranges::zip_view v{NonSimpleSizedBidiNonCommonView(buffer1), NonSimpleSizedBidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 39 + dpl_ranges::zip_view v{NonSimpleBidiNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 40 + dpl_ranges::zip_view v{NonSimpleBidiNonCommonView(buffer1), NonSimpleBidiNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 41 + dpl_ranges::zip_view v{NonSimpleForwardSizedNonCommon(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 42 + dpl_ranges::zip_view v{NonSimpleForwardSizedNonCommon(buffer1), NonSimpleForwardSizedNonCommon(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 43 + dpl_ranges::zip_view v{NonSimpleInputNonCommonView(buffer1)}; + static_assert(!std::ranges::common_range); + assert(std::ranges::next(v.begin(), 5) == v.end()); + static_assert(!std::is_same_v); + } + { + // test ID 44 + dpl_ranges::zip_view v{NonSimpleInputNonCommonView(buffer1), NonSimpleInputNonCommonView(buffer2)}; + static_assert(!std::ranges::common_range); + assert(++v.begin() == v.end()); + static_assert(!std::is_same_v); + } + { + // end should go to the minimum length when zip is common and random_access sized + dpl_ranges::zip_view v(std::views::iota(0, 4), std::views::iota(0, 8)); + auto it = --(v.end()); + auto [x, y] = *it; + assert(x == 3); + assert(y == 3); // y should not go to the end "7" + } +} +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.general.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.general.pass.cpp new file mode 100644 index 00000000000..56020498303 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.general.pass.cpp @@ -0,0 +1,82 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// Some basic examples of how zip_view might be used in the wild. This is a general +// collection of sample algorithms and functions that try to mock general usage of +// this view. + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include +#include +#include +#include + +#include "types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +int main() { + +#if _ONEDPL_CPP20_OWNING_VIEW_PRESENT + { + dpl_ranges::zip_view v{ + std::array{1, 2}, + std::vector{4, 5, 6}, + std::array{7}, + }; + assert(std::ranges::size(v) == 1); + assert(*v.begin() == std::make_tuple(1, 4, 7)); + } +#endif + + { + using namespace std::string_literals; + std::vector v{1, 2, 3, 4}; + std::array a{"abc"s, "def"s, "gh"s}; + auto view = dpl_ranges::views::zip(v, a); + auto it = view.begin(); + assert(&(std::get<0>(*it)) == &(v[0])); + assert(&(std::get<1>(*it)) == &(a[0])); + + ++it; + assert(&(std::get<0>(*it)) == &(v[1])); + assert(&(std::get<1>(*it)) == &(a[1])); + + ++it; + assert(&(std::get<0>(*it)) == &(v[2])); + assert(&(std::get<1>(*it)) == &(a[2])); + + ++it; + assert(it == view.end()); + } + + return TestUtils::done(1); +} + +#else + +int main() { + return TestUtils::done(0); //test skipped +} +#endif //_ENABLE_STD_RANGES_TESTING diff --git a/test/parallel_api/ranges/range.zip/zip_view.range.concept.compile.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.range.concept.compile.pass.cpp new file mode 100644 index 00000000000..4d30d609ce4 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.range.concept.compile.pass.cpp @@ -0,0 +1,349 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// test if zip_view models input_range, forward_range, bidirectional_range, +// random_access_range, contiguous_range, common_range +// sized_range + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include +#include +#include +#include +#include + +#include "types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +void testConceptPair() { + int buffer1[2] = {1, 2}; + int buffer2[3] = {1, 2, 3}; + { + dpl_ranges::zip_view v{ContiguousCommonView{buffer1}, ContiguousCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ContiguousNonCommonView{buffer1}, ContiguousNonCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ContiguousNonCommonSized{buffer1}, ContiguousNonCommonSized{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{SizedRandomAccessView{buffer1}, ContiguousCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{SizedRandomAccessView{buffer1}, SizedRandomAccessView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{NonSizedRandomAccessView{buffer1}, NonSizedRandomAccessView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiCommonView{buffer1}, SizedRandomAccessView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiCommonView{buffer1}, BidiCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiCommonView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiNonCommonView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ForwardSizedView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ForwardSizedNonCommon{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{InputCommonView{buffer1}, ForwardSizedView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{InputCommonView{buffer1}, InputCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{InputNonCommonView{buffer1}, InputCommonView{buffer2}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } +} + +void testConceptTuple() { + int buffer1[2] = {1, 2}; + int buffer2[3] = {1, 2, 3}; + int buffer3[4] = {1, 2, 3, 4}; + + { + dpl_ranges::zip_view v{ContiguousCommonView{buffer1}, ContiguousCommonView{buffer2}, + ContiguousCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ContiguousNonCommonView{buffer1}, ContiguousNonCommonView{buffer2}, + ContiguousNonCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ContiguousNonCommonSized{buffer1}, ContiguousNonCommonSized{buffer2}, + ContiguousNonCommonSized{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{SizedRandomAccessView{buffer1}, ContiguousCommonView{buffer2}, + ContiguousCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{SizedRandomAccessView{buffer1}, SizedRandomAccessView{buffer2}, + SizedRandomAccessView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{NonSizedRandomAccessView{buffer1}, NonSizedRandomAccessView{buffer2}, + NonSizedRandomAccessView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::random_access_range); + static_assert(!std::ranges::contiguous_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiCommonView{buffer1}, SizedRandomAccessView{buffer2}, SizedRandomAccessView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiCommonView{buffer1}, BidiCommonView{buffer2}, BidiCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::bidirectional_range); + static_assert(!std::ranges::random_access_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{BidiNonCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ForwardSizedView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{ForwardSizedNonCommon{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::forward_range); + static_assert(!std::ranges::bidirectional_range); + static_assert(!std::ranges::common_range); + static_assert(std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{InputCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{InputCommonView{buffer1}, InputCommonView{buffer2}, InputCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } + + { + dpl_ranges::zip_view v{InputNonCommonView{buffer1}, InputCommonView{buffer2}, InputCommonView{buffer3}}; + using View = decltype(v); + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::sized_range); + } +} + +using OutputIter = cpp17_output_iterator; + +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +static_assert(std::output_iterator); + +struct OutputView : std::ranges::view_base { + OutputIter begin() const; + sentinel_wrapper end() const; +}; +static_assert(std::ranges::output_range); +static_assert(!std::ranges::input_range); + +template +concept zippable = requires { + typename dpl_ranges::zip_view; +}; + +// output_range is not supported +static_assert(!zippable); +static_assert(!zippable); +static_assert(zippable); +#endif // !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); //test skipped +} diff --git a/test/parallel_api/ranges/range.zip/zip_view.size.pass.cpp b/test/parallel_api/ranges/range.zip/zip_view.size.pass.cpp new file mode 100644 index 00000000000..6bcb29cc2b9 --- /dev/null +++ b/test/parallel_api/ranges/range.zip/zip_view.size.pass.cpp @@ -0,0 +1,114 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// constexpr auto size() requires(sized_range&&...) +// constexpr auto size() const requires(sized_range&&...) + +#include "support/test_config.h" +#include "support/utils.h" + +#if _ENABLE_STD_RANGES_TESTING + +#include + +#include +#include +#include + +#include "types.h" + +#include + +namespace dpl_ranges = oneapi::dpl::experimental::ranges; + +int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; +struct View : std::ranges::view_base { + std::size_t size_ = 0; + constexpr View(std::size_t s) : size_(s) {} + constexpr auto begin() const { return buffer; } + constexpr auto end() const { return buffer + size_; } +}; + +struct SizedNonConst : std::ranges::view_base { + using iterator = forward_iterator; + std::size_t size_ = 0; + constexpr SizedNonConst(std::size_t s) : size_(s) {} + constexpr auto begin() const { return iterator{buffer}; } + constexpr auto end() const { return iterator{buffer + size_}; } + constexpr std::size_t size() { return size_; } +}; + +struct StrangeSizeView : std::ranges::view_base { + constexpr auto begin() const { return buffer; } + constexpr auto end() const { return buffer + 8; } + + constexpr auto size() { return 5; } + constexpr auto size() const { return 6; } +}; + +void test() { +#if !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // single range + dpl_ranges::zip_view v(View(8)); + assert(v.size() == 8); + assert(std::as_const(v).size() == 8); + } + + { + // multiple ranges same type + dpl_ranges::zip_view v(View(2), View(3)); + assert(v.size() == 2); + assert(std::as_const(v).size() == 2); + } + + { + // multiple ranges different types + dpl_ranges::zip_view v(std::views::iota(0, 500), View(3)); + assert(v.size() == 3); + assert(std::as_const(v).size() == 3); + } + + { + // const-view non-sized range + dpl_ranges::zip_view v(SizedNonConst(2), View(3)); + assert(v.size() == 2); + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::sized_range); + } +#endif //!_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN + { + // const/non-const has different sizes + dpl_ranges::zip_view v(StrangeSizeView{}); + assert(v.size() == 5); + assert(std::as_const(v).size() == 6); + } + + { + // underlying range not sized + dpl_ranges::zip_view v(InputCommonView{buffer}); + static_assert(!std::ranges::sized_range); + static_assert(!std::ranges::sized_range); + } +} + +#endif //_ENABLE_STD_RANGES_TESTING + +int main() { +#if _ENABLE_STD_RANGES_TESTING + test(); +#endif + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/sort_ranges_sycl.pass.cpp b/test/parallel_api/ranges/sort_ranges_sycl.pass.cpp index c86cf0ada5b..eb58938d62e 100644 --- a/test/parallel_api/ranges/sort_ranges_sycl.pass.cpp +++ b/test/parallel_api/ranges/sort_ranges_sycl.pass.cpp @@ -13,6 +13,11 @@ // //===----------------------------------------------------------------------===// +// MSVC error: SYCL kernel cannot call an undefined function without SYCL_EXTERNAL attribute +// A reason is the vectorised implementation of __std_min_8u(_First, _Last), called from std::sort +// As workaround we suppress the vectorised implementation. +#define _USE_STD_VECTOR_ALGORITHMS 0 + #include "support/test_config.h" #include diff --git a/test/parallel_api/ranges/std_ranges_test.h b/test/parallel_api/ranges/std_ranges_test.h index fada10fc586..01f140b9ddf 100644 --- a/test/parallel_api/ranges/std_ranges_test.h +++ b/test/parallel_api/ranges/std_ranges_test.h @@ -258,6 +258,14 @@ struct all_dangling_in_result template constexpr bool all_dangling_in_result_v = all_dangling_in_result<_ReturnType>::value; +void call_with_host_policies(auto algo, auto... args) +{ + algo(oneapi::dpl::execution::seq, args...); + algo(oneapi::dpl::execution::unseq, args...); + algo(oneapi::dpl::execution::par, args...); + algo(oneapi::dpl::execution::par_unseq, args...); +} + template struct test @@ -283,98 +291,7 @@ struct test private: - template - using TmpContainerType = std::array; - - // Test dangling iterators in return types for call with temporary data - template - constexpr void - test_dangling_pointers_arg_1(Policy&& exec, Algo&& algo, Args&& ...args) - { - // Check dangling iterators in return types for call with temporary data - if constexpr (!supress_dangling_iterators_check>) - { - using T = typename Container::value_type; - - // Check dangling with temporary containers in implementation - using res_ret_t = decltype(algo(CLONE_TEST_POLICY_IDX(exec, idx), - std::declval>(), - args...)); - - if constexpr (!std::is_fundamental_v) - { - if constexpr (!all_dangling_in_result_v) - static_assert(!std::is_same_v, "res_ret_t is expected to be or consist of std::ranges::dangling"); - } - } - } - - // Test dangling iterators in return types for call with temporary data - template - constexpr void - test_dangling_pointers_args_2(Policy&& exec, Algo&& algo, Args&& ...args) - { - // Check dangling iterators in return types for call with temporary data - if constexpr (!supress_dangling_iterators_check>) - { - using T = typename Container::value_type; - - // Check dangling with temporary containers in implementation - using res_ret_t = decltype(algo(CLONE_TEST_POLICY_IDX(exec, idx), - std::declval>(), - std::declval>(), - args...)); - - if constexpr (!std::is_fundamental_v) - { - if constexpr (!all_dangling_in_result_v) - static_assert(!std::is_same_v, "res_ret_t is expected to be or consist of std::ranges::dangling"); - } - } - } - - // Test dangling iterators in return types for call with temporary data - template - constexpr void - test_dangling_pointers_args_3(Policy&& exec, Algo&& algo, Args&& ...args) - { - // Check dangling iterators in return types for call with temporary data - if constexpr (!supress_dangling_iterators_check>) - { - using T = typename Container::value_type; - - // Check dangling with temporary containers in implementation - using res_ret_t = decltype(algo(CLONE_TEST_POLICY_IDX(exec, idx), - std::declval>(), - std::declval>(), - std::declval>(), - args...)); - - if constexpr (!std::is_fundamental_v) - { - if constexpr (!all_dangling_in_result_v) - static_assert(!std::is_same_v, "res_ret_t is expected to be or consist of std::ranges::dangling"); - } - } - } - - // Test dangling iterators in return types for call with temporary data - template - constexpr void - test_dangling_pointers(Policy&& exec, Algo&& algo, Args&& ...args) - { - static_assert(ArgsSize == 1 || ArgsSize == 2 || ArgsSize == 3, - "The test for dangling pointers is not implemented for this number of algorithm arguments"); - - if constexpr (ArgsSize == 1) - test_dangling_pointers_arg_1(std::forward(exec), std::forward(algo), std::forward(args)...); - - else if constexpr (ArgsSize == 2) - test_dangling_pointers_args_2(std::forward(exec), std::forward(algo), std::forward(args)...); - - else if constexpr (ArgsSize == 3) - test_dangling_pointers_args_3(std::forward(exec), std::forward(algo), std::forward(args)...); - } + using rvalue_container_t = std::array; template void @@ -408,8 +325,23 @@ struct test EXPECT_EQ_N(cont_exp().begin(), cont_in().begin(), n, (std::string("data mismatch with ") + typeid(Algo).name() + typeid(decltype(tr_in(std::declval()()))).name() + sizes).c_str()); - // Test dangling iterators in return types for call with temporary data - test_dangling_pointers<1, 100>(exec, algo, std::forward(args)...); + if constexpr(!supress_dangling_iterators_check>) + { +#if _ONEDPL_CPP20_OWNING_VIEW_PRESENT // Otherwise, `tr_in = std::views::all` leads to a compile error for `rvalue_container_t`. + // Check dangling iterators in return types for call with r-value ranges; + // TransIn may modify the non-borrowed range to a borrowed one, so we need to check it. + if constexpr(!std::ranges::borrowed_range()))>) + { + using res_ret_t = decltype(algo(exec, tr_in(std::declval()), args...)); + + if constexpr(!std::is_fundamental_v) + { + static_assert(all_dangling_in_result_v, + "res_ret_t is expected to be or consist of std::ranges::dangling"); + } + } +#endif //_ONEDPL_CPP20_OWNING_VIEW_PRESENT + } } template(exec, algo, std::forward(args)...); + if constexpr(!supress_dangling_iterators_check>) + { +#if _ONEDPL_CPP20_OWNING_VIEW_PRESENT // Otherwise, `tr_in = std::views::all` leads to a compile error for `rvalue_container_t`. + // Check dangling iterators in return types for call with r-value ranges; + // TransIn and TransOut may modify the non-borrowed range to a borrowed one, so we need to check it. + if constexpr(!std::ranges::borrowed_range()))> + && !std::ranges::borrowed_range()))>) + { + using res_ret_t = decltype(algo(exec, tr_in(std::declval()), + tr_out(std::declval()), args...)); + + if constexpr(!std::is_fundamental_v) + { + static_assert(all_dangling_in_result_v, + "res_ret_t is expected to be or consist of std::ranges::dangling"); + } + } +#endif //_ONEDPL_CPP20_OWNING_VIEW_PRESENT + } } public: @@ -587,8 +536,24 @@ struct test typeid(decltype(tr_in(std::declval()()))).name() + sizes).c_str()); } - // Test dangling iterators in return types for call with temporary data - test_dangling_pointers<2, 300>(exec, algo, std::forward(args)...); + if constexpr(!supress_dangling_iterators_check>) + { +#if _ONEDPL_CPP20_OWNING_VIEW_PRESENT // Otherwise, `tr_in = std::views::all` leads to a compile error for `rvalue_container_t`. + // Check dangling iterators in return types for call with r-value ranges; + // TransIn may modify the non-borrowed range to a borrowed one, so we need to check it. + if constexpr(!std::ranges::borrowed_range()))>) + { + using res_ret_t = decltype(algo(exec, tr_in(std::declval()), + tr_in(std::declval()), args...)); + + if constexpr(!std::is_fundamental_v) + { + static_assert(all_dangling_in_result_v, + "res_ret_t is expected to be or consist of std::ranges::dangling"); + } + } +#endif //_ONEDPL_CPP20_OWNING_VIEW_PRESENT + } } template(exec, algo, std::forward(args)...); + if constexpr(!supress_dangling_iterators_check>) + { +#if _ONEDPL_CPP20_OWNING_VIEW_PRESENT // Otherwise, `tr_in = std::views::all` leads to a compile error for `rvalue_container_t`. + // Check dangling iterators in return types for call with r-value ranges; + // TransIn and TransOut may modify the non-borrowed range to a borrowed one, so we need to check it. + if constexpr(!std::ranges::borrowed_range()))> + && !std::ranges::borrowed_range()))>) + { + using res_ret_t = decltype(algo(exec, tr_in(std::declval()), + tr_in(std::declval()), + tr_out(std::declval()), args...)); + + if constexpr(!std::is_fundamental_v) + { + static_assert(all_dangling_in_result_v, + "res_ret_t is expected to be or consist of std::ranges::dangling"); + } + } +#endif //_ONEDPL_CPP20_OWNING_VIEW_PRESENT + } } public: diff --git a/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp new file mode 100644 index 00000000000..ba02cd6d314 --- /dev/null +++ b/test/parallel_api/ranges/std_ranges_zip_view.pass.cpp @@ -0,0 +1,179 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// MSVC error: SYCL kernel cannot call an undefined function without SYCL_EXTERNAL attribute +// A reason is the vectorised implementation of __std_min_8u(_First, _Last), called from std::sort +// As workaround we suppress the vectorised implementation. +#define _USE_STD_VECTOR_ALGORITHMS 0 + +#include "std_ranges_test.h" +#include + +#if _ENABLE_STD_RANGES_TESTING +#include + +void test_zip_view_base_op() +{ + namespace dpl_ranges = oneapi::dpl::ranges; + namespace dpl_ranges_exp = oneapi::dpl::experimental::ranges; + + constexpr int max_n = 100; + std::vector vec1(max_n); + std::vector vec2(max_n/2); + + auto zip_view = dpl_ranges_exp::views::zip(vec1, vec2); + + static_assert(std::is_trivially_copyable_v); + + static_assert(std::random_access_iterator); + static_assert(std::sentinel_for); + + EXPECT_TRUE(zip_view.end() - zip_view.begin() == max_n/2, + "Difference operation between an iterator and a sentinel (zip_view) returns a wrong result."); + + EXPECT_TRUE(zip_view[2] == *(zip_view.begin() + 2), + "Subscription or dereferencing operation for zip_view returns a wrong result."); + + EXPECT_TRUE(std::ranges::size(zip_view) == max_n/2, "zip_view::size method returns a wrong result."); + EXPECT_TRUE((bool)zip_view, "zip_view::operator bool() method returns a wrong result."); + + EXPECT_TRUE(zip_view[0] == zip_view.front(), "zip_view::front method returns a wrong result."); + EXPECT_TRUE(zip_view[zip_view.size() - 1] == zip_view.back(), "zip_view::back method returns a wrong result."); + EXPECT_TRUE(!zip_view.empty(), "zip_view::empty() method returns a wrong result."); + + using zip_view_t = dpl_ranges_exp::zip_view>; + static_assert(std::is_trivially_copyable_v); + + auto zip_view_0 = zip_view_t(); + EXPECT_TRUE(!zip_view_0.empty(), "zip_view::empty() method returns a wrong result."); +} +#endif //_ENABLE_STD_RANGES_TESTING + +std::int32_t +main() +{ +#if _ENABLE_STD_RANGES_TESTING + + test_zip_view_base_op(); + + namespace dpl_ranges = oneapi::dpl::ranges; + namespace dpl_ranges_exp = oneapi::dpl::experimental::ranges; + +// Suppress warnings about array bounds in GCC, due to static analysis limitations; +// A false positive in case of std::sort call: +// https://github.com/gcc-mirror/gcc/blob/releases/gcc-13/libstdc++-v3/include/bits/stl_algo.h#L1859 +#if defined(__GNUC__) || defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Warray-bounds" +#elif defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable : 6385) // array bounds (MSVC) +#endif + + constexpr int max_n = 10; + int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + auto zip_view = dpl_ranges_exp::views::zip(data, std::views::iota(0, max_n)) | std::views::take(5); + assert(zip_view.size() == 5); + assert(zip_view.begin() + 5 == zip_view.end()); + std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](auto&& val) ->decltype(auto) { return std::get<0>(val); }); + for(int i = 0; i < zip_view.size(); ++i) + EXPECT_TRUE(std::get<0>(zip_view[i]) == i*i && std::get<1>(zip_view[i]) == i, "Wrong effect for std::ranges::for_each with zip_view."); + + test_std_ranges::call_with_host_policies(dpl_ranges::for_each, zip_view, test_std_ranges::f_mutuable, + [](const auto& val) { return std::get<1>(val); }); + + { + int data2[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto zip_view_sort = dpl_ranges_exp::views::zip(data2, data2); + + [[maybe_unused]] oneapi::dpl::zip_iterator zip_it = zip_view_sort.begin(); //check conversion to oneapi::dpl::zip_iterator + + [[maybe_unused]] auto it1 = zip_view_sort.begin(); + [[maybe_unused]] auto it2 = zip_view_sort.end(); + assert(it2 - it1 == max_n); + std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, + [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); }); + + for(int i = 0; i < max_n; ++i) + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i && std::get<1>(zip_view_sort[i]) == max_n - 1 - i, + "Wrong effect for std::sort with zip_view."); + + std::ranges::sort(zip_view_sort, std::less{}, [](auto&& val) { return std::get<0>(val); }); + for(int i = 0; i < max_n; ++i) + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == i && std::get<1>(zip_view_sort[i]) == i, + "Wrong effect for std::ranges::sort with zip_view."); + + static_assert(std::ranges::random_access_range); + static_assert(std::random_access_iterator); + + test_std_ranges::call_with_host_policies(dpl_ranges::sort, zip_view_sort, std::greater{}, + [](const auto& val) { return std::get<0>(val); }); + + for(int i = 0; i < max_n; ++i) + EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i && std::get<1>(zip_view_sort[i]) == max_n - 1 - i, + "Wrong effect for oneapi::dpl::ranges::sort with zip_view."); + } + +#if defined(__GNUC__) || defined(__clang__) + #pragma GCC diagnostic pop //Warray-bounds +#elif defined(_MSC_VER) + #pragma warning(pop) +#endif + +#if TEST_DPCPP_BACKEND_PRESENT + { + const char* err_msg = "Wrong effect for oneapi::dpl::ranges::sort with zip_view and a device policy."; + + const int n = test_std_ranges::medium_size; + std::vector vals(n), keys(n); + + //test with random number and projection usage + std::default_random_engine gen{std::random_device{}()}; + std::uniform_real_distribution dist(0.0, 100.0); + + std::generate(vals.begin(), vals.end(), [&] { return dist(gen); }); + std::generate(keys.begin(), keys.end(), [&] { return dist(gen); }); + + std::vector vals_exp(vals); + std::vector keys_exp(keys); + + auto exec = TestUtils::get_dpcpp_test_policy(); + { + using namespace test_std_ranges; + usm_subrange cont_vals(exec, vals.data(), n); + usm_subrange cont_keys(exec, keys.data(), n); + auto view_vals = cont_vals(); + auto view_keys = cont_keys(); + auto view_s = dpl_ranges_exp::views::zip(view_vals, view_keys); + + //call Range based sort with a device policy + dpl_ranges::stable_sort(exec, view_s, std::ranges::greater{}, [](const auto& a) { return std::get<1>(a);}); + + //call a reference sort function + auto first = oneapi::dpl::make_zip_iterator(vals_exp.begin(), keys_exp.begin()); + std::stable_sort(first, first + n, [](const auto& a, const auto& b) { return std::get<1>(a) > std::get<1>(b);}); + } + + //result check + EXPECT_EQ_N(vals_exp.begin(), vals.begin(), n, err_msg); + EXPECT_EQ_N(keys_exp.begin(), keys.begin(), n, err_msg); + } +#endif //TEST_DPCPP_BACKEND_PRESENT + +#endif //_ENABLE_STD_RANGES_TESTING + + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/std_ranges_zip_view_algo.pass.cpp b/test/parallel_api/ranges/std_ranges_zip_view_algo.pass.cpp new file mode 100644 index 00000000000..4d8c1a5ce8c --- /dev/null +++ b/test/parallel_api/ranges/std_ranges_zip_view_algo.pass.cpp @@ -0,0 +1,62 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +// MSVC error: SYCL kernel cannot call an undefined function without SYCL_EXTERNAL attribute +// A reason is the vectorised implementation of __std_min_8u(_First, _Last), called from std::sort +// As workaround we suppress the vectorised implementation. +#define _USE_STD_VECTOR_ALGORITHMS 0 + +#include "std_ranges_test.h" + +std::int32_t +main() +{ +#if _ENABLE_STD_RANGES_TESTING + using namespace test_std_ranges; + namespace dpl_ranges = oneapi::dpl::ranges; + namespace dpl_ranges_exp = oneapi::dpl::experimental::ranges; + + const int n = medium_size; + + auto zip_proj = [](auto&& val) ->decltype(auto) { return std::get<0>(val); }; + + //find_if with zip_view + test_range_algo<0>{n}.test_view_host(dpl_ranges_exp::views::zip, dpl_ranges::find_if, std::ranges::find_if, pred, zip_proj); + + //sort with zip_view + test_range_algo<1>{n}.test_view_host(dpl_ranges_exp::views::zip, dpl_ranges::sort, std::ranges::sort, std::less{}, zip_proj); + + //count_if with zip_view + test_range_algo<2>{n}.test_view_host(dpl_ranges_exp::views::zip, dpl_ranges::count_if, std::ranges::count_if, pred, zip_proj); + +#if TEST_DPCPP_BACKEND_PRESENT + auto exec = TestUtils::get_dpcpp_test_policy(); + + //find_if with zip_view + test_range_algo<0>{n}.test_view_hetero(CLONE_TEST_POLICY(exec), dpl_ranges_exp::views::zip, dpl_ranges::find_if, std::ranges::find_if, pred, zip_proj); + + //sort with zip_view + test_range_algo<1>{n}.test_view_hetero(CLONE_TEST_POLICY(exec), dpl_ranges_exp::views::zip, dpl_ranges::sort, std::ranges::sort, std::less{}, zip_proj); + + //count_if with zip_view + test_range_algo<2>{n}.test_view_hetero(CLONE_TEST_POLICY(exec), dpl_ranges_exp::views::zip, dpl_ranges::count_if, std::ranges::count_if, pred, zip_proj); +#endif //TEST_DPCPP_BACKEND_PRESENT + + +#endif //_ENABLE_STD_RANGES_TESTING + + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} + diff --git a/test/parallel_api/ranges/zip_view.pass.cpp b/test/parallel_api/ranges/zip_view.pass.cpp index b6adee222ae..882159ff11f 100644 --- a/test/parallel_api/ranges/zip_view.pass.cpp +++ b/test/parallel_api/ranges/zip_view.pass.cpp @@ -22,52 +22,97 @@ #endif #include "support/utils.h" +#include "support/utils_device_copyable.h" #include std::int32_t main() { + bool run = false; + #if _ENABLE_RANGES_TESTING - constexpr int max_n = 10; - char data[max_n] = {'b', 'e', 'g', 'f', 'c', 'd', 'a', 'j', 'i', 'h'}; - int key[max_n] = {1, 4, 6, 5, 2, 3, 0, 9, 8, 7}; using namespace oneapi::dpl::experimental::ranges; - //the name nano::ranges::views::all is not injected into oneapi::dpl::experimental::ranges namespace - auto view = __nanorange::nano::views::all(data); - auto z = zip_view(view, __nanorange::nano::views::all(key)); - - //check access - EXPECT_TRUE(::std::get<0>(z[2]) == 'g', "wrong effect with zip_view"); - - int64_t max_int32p2 = (size_t)::std::numeric_limits::max() + 2L; - - auto base_view = views::iota(::std::int64_t(0), max_int32p2); - - //avoiding allocating large amounts of memory, just reusing small data container - auto transform_data_idx = [&max_n, &data](auto idx) { return data[idx % max_n]; }; - auto data_large_view = views::transform(base_view, transform_data_idx); - - //avoiding allocating large amounts of memory, just reusing small data container - auto transform_key_idx = [&max_n, &key](auto idx) { return key[idx % max_n]; }; - auto key_large_view = views::transform(base_view, transform_key_idx); - - auto large_z = zip_view(data_large_view, key_large_view); - - //check that zip_view ranges can be larger than a signed 32 bit integer - size_t i = large_z.size() - 1; - - auto expected_key = key[i % max_n]; - auto actual_key = ::std::get<1>(large_z[i]); - EXPECT_EQ(expected_key, actual_key, "wrong effect with zip_view bracket operator"); - - char expected_data = data[i % max_n]; - char actual_data = ::std::get<0>(large_z[i]); - EXPECT_EQ(expected_data, actual_data, "wrong effect with zip_view bracket operator"); - -#endif //_ENABLE_RANGES_TESTING - - return TestUtils::done(_ENABLE_RANGES_TESTING); + #if !(_ONEDPL_CPP20_RANGES_PRESENT && TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE) + run = true; + { + constexpr int max_n = 10; + char data[max_n] = {'b', 'e', 'g', 'f', 'c', 'd', 'a', 'j', 'i', 'h'}; + int key[max_n] = {1, 4, 6, 5, 2, 3, 0, 9, 8, 7}; + + //the name nano::ranges::views::all is not injected into oneapi::dpl::experimental::ranges namespace + auto view = __nanorange::nano::views::all(data); + auto z = zip_view(view, __nanorange::nano::views::all(key)); + + //check access + EXPECT_TRUE(std::get<0>(z[2]) == 'g', "wrong effect with zip_view"); + + int64_t max_int32p2 = (size_t)std::numeric_limits::max() + 2L; + + auto base_view = views::iota(std::int64_t(0), max_int32p2); + + //avoiding allocating large amounts of memory, just reusing small data container + auto transform_data_idx = [&max_n, &data](auto idx) { return data[idx % max_n]; }; + auto data_large_view = views::transform(base_view, transform_data_idx); + + //avoiding allocating large amounts of memory, just reusing small data container + auto transform_key_idx = [&max_n, &key](auto idx) { return key[idx % max_n]; }; + auto key_large_view = views::transform(base_view, transform_key_idx); + + auto large_z = zip_view(data_large_view, key_large_view); + + //check that zip_view ranges can be larger than a signed 32 bit integer + size_t i = large_z.size() - 1; + + auto expected_key = key[i % max_n]; + auto actual_key = std::get<1>(large_z[i]); + EXPECT_EQ(expected_key, actual_key, "wrong effect with zip_view bracket operator"); + + char expected_data = data[i % max_n]; + char actual_data = std::get<0>(large_z[i]); + EXPECT_EQ(expected_data, actual_data, "wrong effect with zip_view bracket operator"); + } + #endif // !(_ONEDPL_CPP20_RANGES_PRESENT && TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE) + +#if _ONEDPL_CPP20_RANGES_PRESENT + run = true; + { + //check basic zip_view construction and access with std C++20 views + auto v1 = std::views::iota(0, 5); + auto v2 = std::views::iota(10, 15); + auto z = zip_view(v1, v2); + + EXPECT_TRUE(std::get<0>(z[0]) == 0, "wrong effect with zip_view (std ranges)"); + EXPECT_TRUE(std::get<1>(z[0]) == 10, "wrong effect with zip_view (std ranges)"); + EXPECT_TRUE(std::get<0>(z[3]) == 3, "wrong effect with zip_view (std ranges)"); + EXPECT_TRUE(std::get<1>(z[3]) == 13, "wrong effect with zip_view (std ranges)"); + EXPECT_EQ(5u, z.size(), "wrong size with zip_view (std ranges)"); + } +#endif // _ONEDPL_CPP20_RANGES_PRESENT + +#if TEST_DPCPP_BACKEND_PRESENT + run = true; + { + // zip_view: device copyable if all ranges are device copyable + static_assert( + sycl::is_device_copyable_v< + zip_view>, + "zip_view is not device copyable with device copyable ranges"); + + static_assert(!sycl::is_device_copyable_v>, + "zip_view is device copyable with non device copyable ranges"); + + static_assert( + !sycl::is_device_copyable_v>, + "zip_view is device copyable with non device copyable ranges"); + } + +#endif // TEST_DPCPP_BACKEND_PRESENT +#endif // _ENABLE_RANGES_TESTING + + return TestUtils::done(run); } diff --git a/test/support/double_move_tracker.h b/test/support/double_move_tracker.h new file mode 100644 index 00000000000..fac575d9df0 --- /dev/null +++ b/test/support/double_move_tracker.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H +#define TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H + +#include + +#include "test_macros.h" + +namespace support { + +struct double_move_tracker { + TEST_CONSTEXPR double_move_tracker() : moved_from_(false) {} + + double_move_tracker(double_move_tracker const&) = default; + + TEST_CONSTEXPR_CXX14 double_move_tracker(double_move_tracker&& other) : moved_from_(false) { + assert(!other.moved_from_); + other.moved_from_ = true; + } + + double_move_tracker& operator=(double_move_tracker const&) = default; + + TEST_CONSTEXPR_CXX14 double_move_tracker& operator=(double_move_tracker&& other) { + assert(!other.moved_from_); + other.moved_from_ = true; + moved_from_ = false; + return *this; + } + +private: + bool moved_from_; +}; + +} // namespace support + +#endif // TEST_SUPPORT_DOUBLE_MOVE_TRACKER_H diff --git a/test/support/test_config.h b/test/support/test_config.h index a40ca227029..7998bfe38e0 100644 --- a/test/support/test_config.h +++ b/test/support/test_config.h @@ -1,345 +1,349 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Copyright (C) Intel Corporation -// -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// This file incorporates work covered by the following copyright and permission -// notice: -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// -//===----------------------------------------------------------------------===// - -#ifndef _TEST_CONFIG_H -#define _TEST_CONFIG_H - -// Any include from standard library required to have correct state of _GLIBCXX_RELEASE -#if __has_include() -# include -#else -# include -#endif - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// *** When updating we must audit each usage to ensure that the issue still exists in the latest version *** - -// -// This section contains macros representing the "Latest" version of compilers, STL implementations, etc. for use in -// broken macros to represent the latest version of something which still has an ongoing issue. The intention is to -// update this section regularly to reflect the latest version. -// -// When such an issue is fixed, we must replace the usage of these "Latest" macros with the appropriate version number -// before updating to the newest version in this section. - -#define _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER 20260000 - -#define _PSTL_TEST_LATEST_MSVC_STL_VERSION 145 - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -#define _PSTL_TEST_STRING(X) _PSTL_TEST_STRING_AUX(oneapi/dpl/X) -#define _PSTL_TEST_STRING_AUX(X) #X -//to support the optional including: , , or , , -#define _PSTL_TEST_HEADER(HEADER_ID) _PSTL_TEST_STRING(HEADER_ID) - -#if defined(_MSC_VER) && defined(_DEBUG) -#define _SCL_SECURE_NO_WARNINGS //to prevent the compilation warning. Microsoft STL implementation has specific checking of an iterator range in DEBUG mode for the containers from the standard library. -#endif - -// ICC 18 (Windows) has encountered an unexpected problem on some tests -#define _PSTL_ICC_18_VC141_TEST_SIMD_LAMBDA_RELEASE_BROKEN \ - (!_DEBUG && __INTEL_COMPILER >= 1800 && __INTEL_COMPILER < 1900 && _MSC_VER == 1910) -// ICC 18 doesn't vectorize the loop -#define _PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN (!_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER == 1800) -// ICC 18 generates wrong result with omp simd early_exit -#define _PSTL_ICC_18_TEST_EARLY_EXIT_AVX_RELEASE_BROKEN \ - (!_DEBUG && __INTEL_COMPILER == 1800 && __AVX__ && !__AVX2__ && !__AVX512__) -// ICC 19 has encountered an unexpected problem: Segmentation violation signal raised -#define _PSTL_ICC_19_TEST_IS_PARTITIONED_RELEASE_BROKEN \ - (!PSTL_USE_DEBUG && (__linux__ || __APPLE__) && __INTEL_COMPILER == 1900) -// ICC 19 generates wrong result with UDS on Windows -#define _PSTL_ICC_19_TEST_SIMD_UDS_WINDOWS_RELEASE_BROKEN (__INTEL_COMPILER == 1900 && _MSC_VER && !_DEBUG) -// ICPC compiler generates wrong "openMP simd" code for a user defined scan operation(UDS) -#define _PSTL_ICC_TEST_SIMD_UDS_BROKEN \ - (__INTEL_COMPILER && __INTEL_COMPILER_BUILD_DATE < 20211123) -// ICC 18,19 generate wrong result -#define _PSTL_ICC_18_19_TEST_SIMD_MONOTONIC_WINDOWS_RELEASE_BROKEN \ - ((__INTEL_COMPILER == 1800 || __INTEL_COMPILER == 1900) && _MSC_VER && !_DEBUG) -// ICC 18,19 generate wrong result with for_loop_strided and reverse iterators -#define _PSTL_ICC_18_19_TEST_REVERSE_ITERATOR_WITH_STRIDE_BROKEN \ - (__i386__ && (__INTEL_COMPILER == 1800 || __INTEL_COMPILER == 1900)) -// VC14 uninitialized_fill with no policy has broken implementation -#define _PSTL_STD_UNINITIALIZED_FILL_BROKEN (_MSC_VER == 1900) -// GCC10 produces wrong answer calling exclusive_scan using vectorized polices -#define TEST_GCC10_EXCLUSIVE_SCAN_BROKEN (_GLIBCXX_RELEASE == 10) -// GCC7 std::get doesn't return const rvalue reference from const rvalue reference of tuple -#define _PSTL_TEST_GCC7_RVALUE_TUPLE_GET_BROKEN (_GLIBCXX_RELEASE > 0 && _GLIBCXX_RELEASE < 8) - -#define _PSTL_SYCL_TEST_USM 1 - -#define TEST_SYCL_HEADER_PRESENT (__has_include() || __has_include()) -#define TEST_SYCL_LANGUAGE_VERSION_PRESENT (SYCL_LANGUAGE_VERSION || CL_SYCL_LANGUAGE_VERSION) -#define TEST_SYCL_AVAILABLE (TEST_SYCL_HEADER_PRESENT && TEST_SYCL_LANGUAGE_VERSION_PRESENT) - -// If SYCL is available, and DPCPP backend is not explicitly turned off, enable its testing -#if TEST_SYCL_AVAILABLE && !defined(ONEDPL_USE_DPCPP_BACKEND) -# define TEST_DPCPP_BACKEND_PRESENT 1 -// If DPCPP backend was explicitly requested, enable its testing, even if SYCL availability has not been proven -// this can be used to force DPCPP backend testing for environments where SYCL_LANGUAGE_VERSION is not predefined -#elif ONEDPL_USE_DPCPP_BACKEND -# define TEST_DPCPP_BACKEND_PRESENT 1 -// Define to 0 in other cases since some tests may rely at the macro value at runtime -#else -# define TEST_DPCPP_BACKEND_PRESENT 0 -#endif - -#ifdef __SYCL_UNNAMED_LAMBDA__ -#define TEST_UNNAMED_LAMBDAS 1 -#else -#define TEST_UNNAMED_LAMBDAS 0 -#endif - -// The TEST_EXPLICIT_KERNEL_NAMES macro may be defined on CMake level in CMakeLists.txt -// so we should check here if it is defined or not -#ifndef TEST_EXPLICIT_KERNEL_NAMES -# if __SYCL_UNNAMED_LAMBDA__ -# define TEST_EXPLICIT_KERNEL_NAMES 0 -# else -# define TEST_EXPLICIT_KERNEL_NAMES 1 -# endif // __SYCL_UNNAMED_LAMBDA__ -#endif // !TEST_EXPLICIT_KERNEL_NAMES - -// Enables full scope of testing -#ifndef TEST_LONG_RUN -#define TEST_LONG_RUN 0 -#endif - -// Enable check compilation with different policy value category -#ifndef TEST_CHECK_COMPILATION_WITH_DIFF_POLICY_VAL_CATEGORY -# define TEST_CHECK_COMPILATION_WITH_DIFF_POLICY_VAL_CATEGORY (!__SYCL_UNNAMED_LAMBDA__ || TEST_EXPLICIT_KERNEL_NAMES) -#endif - -#ifndef TEST_CHECK_COMPILATION_WITH_COMMA_OP_DELETED_ITERS -# define TEST_CHECK_COMPILATION_WITH_COMMA_OP_DELETED_ITERS 1 -#endif - -// Enable test when the TBB backend is available -#if !defined(ONEDPL_USE_TBB_BACKEND) || ONEDPL_USE_TBB_BACKEND -#define TEST_TBB_BACKEND_PRESENT 1 -#endif - -// Check for C++ standard and standard library for the use of ranges API -#if !defined(_ENABLE_RANGES_TESTING) -#define _TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY TEST_DPCPP_BACKEND_PRESENT -#if defined(_GLIBCXX_RELEASE) -# define _ENABLE_RANGES_TESTING (_TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY && _GLIBCXX_RELEASE >= 8 && __GLIBCXX__ >= 20180502) -#elif defined(_LIBCPP_VERSION) -# define _ENABLE_RANGES_TESTING (_TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY && _LIBCPP_VERSION >= 7000) -#else -# define _ENABLE_RANGES_TESTING (_TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY) -#endif -#endif //!defined(_ENABLE_RANGES_TESTING) - -#if (__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && __has_include() -# include -# define TEST_STD_FEATURE_MACROS_PRESENT 1 -#endif - -#if TEST_STD_FEATURE_MACROS_PRESENT -// Make sure _ENABLE_STD_RANGES_TESTING is always defined for the use at runtime, e.g. by TestUtils::done -// Clang 15 and older do not support range adaptors, see https://bugs.llvm.org/show_bug.cgi?id=44833 -# if __cpp_lib_ranges >= 201911L && !(__clang__ && __clang_major__ < 16) -# define _ENABLE_STD_RANGES_TESTING 1 -# else -# define _ENABLE_STD_RANGES_TESTING 0 -# endif -# define TEST_CPP20_SPAN_PRESENT (__cpp_lib_span >= 202002L) -#else -# define _ENABLE_STD_RANGES_TESTING 0 -# define TEST_CPP20_SPAN_PRESENT 0 -#endif // TEST_STD_FEATURE_MACROS_PRESENT - -#define TEST_HAS_NO_INT128 -#define _PSTL_TEST_COMPLEX_NON_FLOAT_AVAILABLE (_MSVC_STL_VERSION < 143) - -#define _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN (__GLIBCXX__ >= 7) - -#define _PSTL_GLIBCXX_TEST_COMPLEX_POW_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN -#define _PSTL_GLIBCXX_TEST_COMPLEX_DIV_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN -#define _PSTL_GLIBCXX_TEST_COMPLEX_MINUS_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN -#define _PSTL_GLIBCXX_TEST_COMPLEX_PLUS_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN -#define _PSTL_GLIBCXX_TEST_COMPLEX_TIMES_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN - -#define _PSTL_MSVC_LESS_THAN_CPP20_COMPLEX_CONSTEXPR_BROKEN (_MSC_VER && __cplusplus < 202002L && _MSVC_LANG < 202002L) - -#define _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER (__INTEL_LLVM_COMPILER <= _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER) - -#define _PSTL_ICC_TEST_COMPLEX_ASIN_MINUS_INF_NAN_BROKEN_SIGNBIT _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_COSH_MINUS_INF_MINUS_ZERO_BROKEN_SIGNBIT _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_COSH_MINUS_ZERO_MINUS_ZERO_BROKEN_SIGNBIT _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_POW_COMPLEX_COMPLEX_PASS_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_POW_COMPLEX_SCALAR_PASS_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_POW_SCALAR_COMPLEX_PASS_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_NORM_MINUS_INF_NAN_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_POLAR_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER -#define _PSTL_ICC_TEST_COMPLEX_EXP_BROKEN_TEST_EDGES (20240201 < __INTEL_LLVM_COMPILER && __INTEL_LLVM_COMPILER < 20250100) -#define _PSTL_ICC_TEST_COMPLEX_EXP_BROKEN_TEST_EDGES_LATEST (20240201 < __INTEL_LLVM_COMPILER && __INTEL_LLVM_COMPILER <= _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER) -#define _PSTL_TEST_COMPLEX_ACOS_BROKEN_IN_KERNEL (__SYCL_DEVICE_ONLY__ && __INTEL_LLVM_COMPILER < 20250100) -#define _PSTL_TEST_COMPLEX_EXP_BROKEN (__SYCL_DEVICE_ONLY__ && __INTEL_LLVM_COMPILER < 20250100) -#define _PSTL_TEST_COMPLEX_TANH_BROKEN_IN_KERNEL (__SYCL_DEVICE_ONLY__ && __INTEL_LLVM_COMPILER < 20250100) - - -#define _PSTL_ICC_TEST_COMPLEX_ISINF_BROKEN (_MSVC_STL_VERSION && __INTEL_LLVM_COMPILER) -#define _PSTL_ICC_TEST_COMPLEX_ISNAN_BROKEN (_MSVC_STL_VERSION && __INTEL_LLVM_COMPILER) - -#define _PSTL_TEST_COMPLEX_OP_BROKEN (_MSVC_STL_VERSION && _MSVC_STL_VERSION <= _PSTL_TEST_LATEST_MSVC_STL_VERSION) - -#define _PSTL_TEST_COMPLEX_ACOS_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_ACOSH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_ASINH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_ATANH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_COS_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_COSH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_LOG10_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_SIN_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_SINH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_TANH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN - -#define _PSTL_TEST_COMPLEX_OP_USING_DOUBLE (_MSVC_STL_VERSION && _MSVC_STL_VERSION <= _PSTL_TEST_LATEST_MSVC_STL_VERSION) -#define _PSTL_TEST_COMPLEX_OP_ACOS_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE -#define _PSTL_TEST_COMPLEX_OP_ACOSH_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE -#define _PSTL_TEST_COMPLEX_OP_ASIN_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE -#define _PSTL_TEST_COMPLEX_OP_ASINH_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE -#define _PSTL_TEST_COMPLEX_OP_LOG_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE -#define _PSTL_TEST_COMPLEX_OP_LOG10_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE -#define _PSTL_TEST_COMPLEX_OP_POW_SCALAR_COMPLEX_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE - -// oneAPI DPC++ compiler 2025.0.0 and earlier is unable to eliminate a "dead" function call to an undefined function -// within a sycl kernel which MSVC uses to allow comparisons with literal zero without warning -#define _PSTL_TEST_COMPARISON_BROKEN \ - ((__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && _MSVC_STL_VERSION >= 143 && _MSVC_STL_UPDATE >= 202303L && \ - __INTEL_LLVM_COMPILER > 0 && __INTEL_LLVM_COMPILER < 20250100) - -#define _PSTL_TEST_COMPLEX_TIMES_COMPLEX_BROKEN (_PSTL_TEST_COMPLEX_OP_BROKEN || _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER) -#define _PSTL_TEST_COMPLEX_DIV_COMPLEX_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN -#define _PSTL_TEST_COMPLEX_DIV_COMPLEX_BROKEN_IN_INTEL_LLVM_COMPILER _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER - -#define _PSTL_ICC_TEST_UNDERLYING_TYPE_BROKEN (_GLIBCXX_RELEASE && _GLIBCXX_RELEASE < 9) - -// Known limitation: -// Due to specifics of Microsoft* Visual C++, some standard floating-point math functions require device support for double precision. -#define _PSTL_ICC_TEST_COMPLEX_MSVC_MATH_DOUBLE_REQ _MSC_VER - -#define _PSTL_CLANG_TEST_COMPLEX_ACOS_IS_NAN_CASE_BROKEN __clang__ -#define _PSTL_CLANG_TEST_COMPLEX_ATAN_IS_CASE_BROKEN __clang__ -#define _PSTL_CLANG_TEST_COMPLEX_SIN_IS_CASE_BROKEN __clang__ - -#define TEST_DYNAMIC_SELECTION_AVAILABLE (TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER >= 20230000) - -// oneAPI DPC++ compiler in 2023.2 release build crashes during optimization of reduce_by_segment.pass.cpp -// with TBB backend. -#if !PSTL_USE_DEBUG && TEST_TBB_BACKEND_PRESENT && defined(__INTEL_LLVM_COMPILER) -# define _PSTL_ICPX_TEST_RED_BY_SEG_OPTIMIZER_CRASH ((__INTEL_LLVM_COMPILER >= 20230200) && (__INTEL_LLVM_COMPILER <= 20240100)) -#else -# define _PSTL_ICPX_TEST_RED_BY_SEG_OPTIMIZER_CRASH 0 -#endif - -// If the workaround macro for the 64-bit type bug is not defined by the user, then exclude 64-bit type testing -// in reduce_by_segment.pass.cpp. -// TODO: When a driver fix is provided to resolve this issue, consider altering this macro or checking the driver version at runtime -// of the underlying sycl::device to determine whether to include or exclude 64-bit type tests. -#if !PSTL_USE_DEBUG && defined(__INTEL_LLVM_COMPILER) -# define _PSTL_ICPX_TEST_RED_BY_SEG_BROKEN_64BIT_TYPES 1 -#endif - -// Group reduction produces wrong results with multiplication of 64-bit for certain driver versions -// TODO: When a driver fix is provided to resolve this issue, consider altering this macro or checking the driver version at runtime -// of the underlying sycl::device to determine whether to include or exclude 64-bit type tests. -#define _PSTL_GROUP_REDUCTION_MULT_INT64_BROKEN 1 - -// oneAPI DPC++ compiler 2022.2 an below show an internal compiler error during the backend code generation of -// minmax_element.pass.cpp affecting min_element, max_element, and minmax_element calls. - -#define _PSTL_ICPX_TEST_MINMAX_ELEMENT_PASS_BROKEN \ - (TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER > 0 && __INTEL_LLVM_COMPILER < 20220300) - -// oneAPI DPC++ compiler fails to compile the sum of an integer and an iterator to a usm-allocated std vector when -// building for an FPGA device. This prevents fpga compilation of usm-allocated std vector wrapped in zip, transform, -// and permutation iterators (as a map). -#if (TEST_DPCPP_BACKEND_PRESENT && defined(ONEDPL_FPGA_DEVICE) && defined(__INTEL_LLVM_COMPILER) && \ - __INTEL_LLVM_COMPILER < 20250100) -# define _PSTL_ICPX_FPGA_TEST_USM_VECTOR_ITERATOR_BROKEN 1 -#else -# define _PSTL_ICPX_FPGA_TEST_USM_VECTOR_ITERATOR_BROKEN 0 -#endif - -// A specific kernel compilation order causes incorrect results on Windows with the DPCPP backend. For now, we reorder -// the test while the issue is being reported to the compiler team. Once it is resolved, this macro can be removed -// or limited to older compiler versions. -#define _PSTL_RED_BY_SEG_WINDOWS_COMPILE_ORDER_BROKEN \ - (_MSC_VER && TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER < 20250100) - -// Intel(R) oneAPI DPC++/C++ compiler produces 'Unexpected kernel lambda size issue' error -#define _PSTL_LAMBDA_PTR_TO_MEMBER_WINDOWS_BROKEN \ - (_MSC_VER && TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER <= _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER) - -// To prevent the assertion from Microsoft STL implementation about the comparison of iterators from different containers -#define _PSTL_TEST_ITERATORS_POSSIBLY_EQUAL_BROKEN (_DEBUG && _MSC_VER) - -#if TEST_ONLY_HETERO_POLICIES && !TEST_DPCPP_BACKEND_PRESENT -# error "TEST_ONLY_HETERO_POLICIES is passed but device backend is not available" -#endif - -//There are issues with stable_sort for libcpp with iterators with a deleted comma operator, disable no_comma compile -// only tests. Also, since this adds significant amount of code compilation to the build, lets be more conservative -// about when we try to test this. Since debug build mode and unnamed lambda support dont change the code in any way -// which should interact with what we are testing for here, lets disable it for those cases for time / build space. -#if !defined(_LIBCPP_VERSION) && !PSTL_USE_DEBUG && (TEST_UNNAMED_LAMBDAS || !TEST_DPCPP_BACKEND_PRESENT) -# define TEST_NO_COMMA_ITERATORS 1 -#else -# define TEST_NO_COMMA_ITERATORS 0 -#endif - -// For icpx versions prior to 2024.1, we encounter compilation issues in device_copyable.pass tests for device copyable -// specializations of kernel submitters. It is a test only issue. -#if TEST_DPCPP_BACKEND_PRESENT && defined(__INTEL_LLVM_COMPILER) && __INTEL_LLVM_COMPILER < 20240100 -# define _PSTL_ICPX_DEVICE_COPYABLE_SUBMITTER_BROKEN 1 -#else -# define _PSTL_ICPX_DEVICE_COPYABLE_SUBMITTER_BROKEN 0 -#endif - -// There is a bug in the libc++ at the time of writing this comment with 21 being the latest major release -// 23 is set to avoid frequent bump-ups. -// See: https://github.com/llvm/llvm-project/blob/6096d35ea93c75f648a253a00775b4d74915c819/libcxx/include/__algorithm/ranges_set_union.h#L94 -// This line does not take into account that the iterator-based implementation may arbitrary call comp(a, b) or comp(b, a) -// TODO: report it or contribute. -#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 230000 -# define _PSTL_LIBCPP_RANGE_SET_BROKEN 1 -#else -# define _PSTL_LIBCPP_RANGE_SET_BROKEN 0 -#endif - -// Drop view throws exceptions in libstdc++ 10 -#define _PSTL_LIBSTDCXX_XPU_DROP_VIEW_BROKEN (_GLIBCXX_RELEASE == 10) - -// std::ranges::view concept requires default_initializable: -// 1. GNU libstdc++ (GCC) - prior to GCC 11.4 -// 2. LLVM libc++ - prior to LLVM 13.0 -// 3. Microsoft STL (MSVC) - prior to VS 2022 17.0 -#if defined(_GLIBCXX_RELEASE) && defined(__GLIBCXX__) -# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE \ - ((_GLIBCXX_RELEASE < 11) || (_GLIBCXX_RELEASE == 11 && __GLIBCXX__ < 20230528)) -#elif defined(_LIBCPP_VERSION) -# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE (_LIBCPP_VERSION < 13000) -#elif defined(_MSVC_STL_VERSION) && defined(_MSVC_STL_UPDATE) -# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE \ - (_MSVC_STL_VERSION < 143 || (_MSVC_STL_VERSION == 143 && _MSVC_STL_UPDATE < 202111)) -#else -# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE 0 -#endif - -#endif // _TEST_CONFIG_H +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +#ifndef _TEST_CONFIG_H +#define _TEST_CONFIG_H + +// Any include from standard library required to have correct state of _GLIBCXX_RELEASE +#if __has_include() +# include +#else +# include +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// *** When updating we must audit each usage to ensure that the issue still exists in the latest version *** + +// +// This section contains macros representing the "Latest" version of compilers, STL implementations, etc. for use in +// broken macros to represent the latest version of something which still has an ongoing issue. The intention is to +// update this section regularly to reflect the latest version. +// +// When such an issue is fixed, we must replace the usage of these "Latest" macros with the appropriate version number +// before updating to the newest version in this section. + +#define _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER 20260000 + +#define _PSTL_TEST_LATEST_MSVC_STL_VERSION 145 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#define _PSTL_TEST_STRING(X) _PSTL_TEST_STRING_AUX(oneapi/dpl/X) +#define _PSTL_TEST_STRING_AUX(X) #X +//to support the optional including: , , or , , +#define _PSTL_TEST_HEADER(HEADER_ID) _PSTL_TEST_STRING(HEADER_ID) + +#if defined(_MSC_VER) && defined(_DEBUG) +#define _SCL_SECURE_NO_WARNINGS //to prevent the compilation warning. Microsoft STL implementation has specific checking of an iterator range in DEBUG mode for the containers from the standard library. +#endif + +// ICC 18 (Windows) has encountered an unexpected problem on some tests +#define _PSTL_ICC_18_VC141_TEST_SIMD_LAMBDA_RELEASE_BROKEN \ + (!_DEBUG && __INTEL_COMPILER >= 1800 && __INTEL_COMPILER < 1900 && _MSC_VER == 1910) +// ICC 18 doesn't vectorize the loop +#define _PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN (!_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER == 1800) +// ICC 18 generates wrong result with omp simd early_exit +#define _PSTL_ICC_18_TEST_EARLY_EXIT_AVX_RELEASE_BROKEN \ + (!_DEBUG && __INTEL_COMPILER == 1800 && __AVX__ && !__AVX2__ && !__AVX512__) +// ICC 19 has encountered an unexpected problem: Segmentation violation signal raised +#define _PSTL_ICC_19_TEST_IS_PARTITIONED_RELEASE_BROKEN \ + (!PSTL_USE_DEBUG && (__linux__ || __APPLE__) && __INTEL_COMPILER == 1900) +// ICC 19 generates wrong result with UDS on Windows +#define _PSTL_ICC_19_TEST_SIMD_UDS_WINDOWS_RELEASE_BROKEN (__INTEL_COMPILER == 1900 && _MSC_VER && !_DEBUG) +// ICPC compiler generates wrong "openMP simd" code for a user defined scan operation(UDS) +#define _PSTL_ICC_TEST_SIMD_UDS_BROKEN \ + (__INTEL_COMPILER && __INTEL_COMPILER_BUILD_DATE < 20211123) +// ICC 18,19 generate wrong result +#define _PSTL_ICC_18_19_TEST_SIMD_MONOTONIC_WINDOWS_RELEASE_BROKEN \ + ((__INTEL_COMPILER == 1800 || __INTEL_COMPILER == 1900) && _MSC_VER && !_DEBUG) +// ICC 18,19 generate wrong result with for_loop_strided and reverse iterators +#define _PSTL_ICC_18_19_TEST_REVERSE_ITERATOR_WITH_STRIDE_BROKEN \ + (__i386__ && (__INTEL_COMPILER == 1800 || __INTEL_COMPILER == 1900)) +// VC14 uninitialized_fill with no policy has broken implementation +#define _PSTL_STD_UNINITIALIZED_FILL_BROKEN (_MSC_VER == 1900) +// GCC10 produces wrong answer calling exclusive_scan using vectorized polices +#define TEST_GCC10_EXCLUSIVE_SCAN_BROKEN (_GLIBCXX_RELEASE == 10) +// GCC7 std::get doesn't return const rvalue reference from const rvalue reference of tuple +#define _PSTL_TEST_GCC7_RVALUE_TUPLE_GET_BROKEN (_GLIBCXX_RELEASE > 0 && _GLIBCXX_RELEASE < 8) + +#define _PSTL_SYCL_TEST_USM 1 + +#define TEST_SYCL_HEADER_PRESENT (__has_include() || __has_include()) +#define TEST_SYCL_LANGUAGE_VERSION_PRESENT (SYCL_LANGUAGE_VERSION || CL_SYCL_LANGUAGE_VERSION) +#define TEST_SYCL_AVAILABLE (TEST_SYCL_HEADER_PRESENT && TEST_SYCL_LANGUAGE_VERSION_PRESENT) + +// If SYCL is available, and DPCPP backend is not explicitly turned off, enable its testing +#if TEST_SYCL_AVAILABLE && !defined(ONEDPL_USE_DPCPP_BACKEND) +# define TEST_DPCPP_BACKEND_PRESENT 1 +// If DPCPP backend was explicitly requested, enable its testing, even if SYCL availability has not been proven +// this can be used to force DPCPP backend testing for environments where SYCL_LANGUAGE_VERSION is not predefined +#elif ONEDPL_USE_DPCPP_BACKEND +# define TEST_DPCPP_BACKEND_PRESENT 1 +// Define to 0 in other cases since some tests may rely at the macro value at runtime +#else +# define TEST_DPCPP_BACKEND_PRESENT 0 +#endif + +#ifdef __SYCL_UNNAMED_LAMBDA__ +#define TEST_UNNAMED_LAMBDAS 1 +#else +#define TEST_UNNAMED_LAMBDAS 0 +#endif + +// The TEST_EXPLICIT_KERNEL_NAMES macro may be defined on CMake level in CMakeLists.txt +// so we should check here if it is defined or not +#ifndef TEST_EXPLICIT_KERNEL_NAMES +# if __SYCL_UNNAMED_LAMBDA__ +# define TEST_EXPLICIT_KERNEL_NAMES 0 +# else +# define TEST_EXPLICIT_KERNEL_NAMES 1 +# endif // __SYCL_UNNAMED_LAMBDA__ +#endif // !TEST_EXPLICIT_KERNEL_NAMES + +// Enables full scope of testing +#ifndef TEST_LONG_RUN +#define TEST_LONG_RUN 0 +#endif + +// Enable check compilation with different policy value category +#ifndef TEST_CHECK_COMPILATION_WITH_DIFF_POLICY_VAL_CATEGORY +# define TEST_CHECK_COMPILATION_WITH_DIFF_POLICY_VAL_CATEGORY (!__SYCL_UNNAMED_LAMBDA__ || TEST_EXPLICIT_KERNEL_NAMES) +#endif + +#ifndef TEST_CHECK_COMPILATION_WITH_COMMA_OP_DELETED_ITERS +# define TEST_CHECK_COMPILATION_WITH_COMMA_OP_DELETED_ITERS 1 +#endif + +// Enable test when the TBB backend is available +#if !defined(ONEDPL_USE_TBB_BACKEND) || ONEDPL_USE_TBB_BACKEND +#define TEST_TBB_BACKEND_PRESENT 1 +#endif + +// Check for C++ standard and standard library for the use of ranges API +#if !defined(_ENABLE_RANGES_TESTING) +#define _TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY TEST_DPCPP_BACKEND_PRESENT +#if defined(_GLIBCXX_RELEASE) +# define _ENABLE_RANGES_TESTING (_TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY && _GLIBCXX_RELEASE >= 8 && __GLIBCXX__ >= 20180502) +#elif defined(_LIBCPP_VERSION) +# define _ENABLE_RANGES_TESTING (_TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY && _LIBCPP_VERSION >= 7000) +#else +# define _ENABLE_RANGES_TESTING (_TEST_RANGES_FOR_CPP_17_DPCPP_BE_ONLY) +#endif +#endif //!defined(_ENABLE_RANGES_TESTING) + +#if (__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && __has_include() +# include +# define TEST_STD_FEATURE_MACROS_PRESENT 1 +#endif + +#if TEST_STD_FEATURE_MACROS_PRESENT +// Make sure _ENABLE_STD_RANGES_TESTING is always defined for the use at runtime, e.g. by TestUtils::done +// Clang 15 and older do not support range adaptors, see https://bugs.llvm.org/show_bug.cgi?id=44833 +# if __cpp_lib_ranges >= 201911L && !(__clang__ && __clang_major__ < 16) +# define _ENABLE_STD_RANGES_TESTING 1 +# else +# define _ENABLE_STD_RANGES_TESTING 0 +# endif +# define TEST_CPP20_SPAN_PRESENT (__cpp_lib_span >= 202002L) +#else +# define _ENABLE_STD_RANGES_TESTING 0 +# define TEST_CPP20_SPAN_PRESENT 0 +#endif // TEST_STD_FEATURE_MACROS_PRESENT + +#define TEST_HAS_NO_INT128 +#define _PSTL_TEST_COMPLEX_NON_FLOAT_AVAILABLE (_MSVC_STL_VERSION < 143) + +#define _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN (__GLIBCXX__ >= 7) + +#define _PSTL_GLIBCXX_TEST_COMPLEX_POW_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN +#define _PSTL_GLIBCXX_TEST_COMPLEX_DIV_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN +#define _PSTL_GLIBCXX_TEST_COMPLEX_MINUS_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN +#define _PSTL_GLIBCXX_TEST_COMPLEX_PLUS_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN +#define _PSTL_GLIBCXX_TEST_COMPLEX_TIMES_EQ_BROKEN _PSTL_GLIBCXX_TEST_COMPLEX_BROKEN + +#define _PSTL_MSVC_LESS_THAN_CPP20_COMPLEX_CONSTEXPR_BROKEN (_MSC_VER && __cplusplus < 202002L && _MSVC_LANG < 202002L) + +#define _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER (__INTEL_LLVM_COMPILER <= _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER) + +#define _PSTL_ICC_TEST_COMPLEX_ASIN_MINUS_INF_NAN_BROKEN_SIGNBIT _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_COSH_MINUS_INF_MINUS_ZERO_BROKEN_SIGNBIT _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_COSH_MINUS_ZERO_MINUS_ZERO_BROKEN_SIGNBIT _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_POW_COMPLEX_COMPLEX_PASS_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_POW_COMPLEX_SCALAR_PASS_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_POW_SCALAR_COMPLEX_PASS_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_NORM_MINUS_INF_NAN_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_POLAR_BROKEN_TEST_EDGES _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER +#define _PSTL_ICC_TEST_COMPLEX_EXP_BROKEN_TEST_EDGES (20240201 < __INTEL_LLVM_COMPILER && __INTEL_LLVM_COMPILER < 20250100) +#define _PSTL_ICC_TEST_COMPLEX_EXP_BROKEN_TEST_EDGES_LATEST (20240201 < __INTEL_LLVM_COMPILER && __INTEL_LLVM_COMPILER <= _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER) +#define _PSTL_TEST_COMPLEX_ACOS_BROKEN_IN_KERNEL (__SYCL_DEVICE_ONLY__ && __INTEL_LLVM_COMPILER < 20250100) +#define _PSTL_TEST_COMPLEX_EXP_BROKEN (__SYCL_DEVICE_ONLY__ && __INTEL_LLVM_COMPILER < 20250100) +#define _PSTL_TEST_COMPLEX_TANH_BROKEN_IN_KERNEL (__SYCL_DEVICE_ONLY__ && __INTEL_LLVM_COMPILER < 20250100) + + +#define _PSTL_ICC_TEST_COMPLEX_ISINF_BROKEN (_MSVC_STL_VERSION && __INTEL_LLVM_COMPILER) +#define _PSTL_ICC_TEST_COMPLEX_ISNAN_BROKEN (_MSVC_STL_VERSION && __INTEL_LLVM_COMPILER) + +#define _PSTL_TEST_COMPLEX_OP_BROKEN (_MSVC_STL_VERSION && _MSVC_STL_VERSION <= _PSTL_TEST_LATEST_MSVC_STL_VERSION) + +#define _PSTL_TEST_COMPLEX_ACOS_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_ACOSH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_ASINH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_ATANH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_COS_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_COSH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_LOG10_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_SIN_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_SINH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_TANH_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN + +#define _PSTL_TEST_COMPLEX_OP_USING_DOUBLE (_MSVC_STL_VERSION && _MSVC_STL_VERSION <= _PSTL_TEST_LATEST_MSVC_STL_VERSION) +#define _PSTL_TEST_COMPLEX_OP_ACOS_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE +#define _PSTL_TEST_COMPLEX_OP_ACOSH_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE +#define _PSTL_TEST_COMPLEX_OP_ASIN_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE +#define _PSTL_TEST_COMPLEX_OP_ASINH_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE +#define _PSTL_TEST_COMPLEX_OP_LOG_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE +#define _PSTL_TEST_COMPLEX_OP_LOG10_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE +#define _PSTL_TEST_COMPLEX_OP_POW_SCALAR_COMPLEX_USING_DOUBLE _PSTL_TEST_COMPLEX_OP_USING_DOUBLE + +// oneAPI DPC++ compiler 2025.0.0 and earlier is unable to eliminate a "dead" function call to an undefined function +// within a sycl kernel which MSVC uses to allow comparisons with literal zero without warning +#define _PSTL_TEST_COMPARISON_BROKEN \ + ((__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && _MSVC_STL_VERSION >= 143 && _MSVC_STL_UPDATE >= 202303L && \ + __INTEL_LLVM_COMPILER > 0 && __INTEL_LLVM_COMPILER < 20250100) + +#define _PSTL_TEST_COMPLEX_TIMES_COMPLEX_BROKEN (_PSTL_TEST_COMPLEX_OP_BROKEN || _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER) +#define _PSTL_TEST_COMPLEX_DIV_COMPLEX_BROKEN _PSTL_TEST_COMPLEX_OP_BROKEN +#define _PSTL_TEST_COMPLEX_DIV_COMPLEX_BROKEN_IN_INTEL_LLVM_COMPILER _PSTL_TEST_COMPLEX_OP_BROKEN_IN_INTEL_LLVM_COMPILER + +#define _PSTL_ICC_TEST_UNDERLYING_TYPE_BROKEN (_GLIBCXX_RELEASE && _GLIBCXX_RELEASE < 9) + +// Known limitation: +// Due to specifics of Microsoft* Visual C++, some standard floating-point math functions require device support for double precision. +#define _PSTL_ICC_TEST_COMPLEX_MSVC_MATH_DOUBLE_REQ _MSC_VER + +#define _PSTL_CLANG_TEST_COMPLEX_ACOS_IS_NAN_CASE_BROKEN __clang__ +#define _PSTL_CLANG_TEST_COMPLEX_ATAN_IS_CASE_BROKEN __clang__ +#define _PSTL_CLANG_TEST_COMPLEX_SIN_IS_CASE_BROKEN __clang__ + +#define TEST_DYNAMIC_SELECTION_AVAILABLE (TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER >= 20230000) + +// oneAPI DPC++ compiler in 2023.2 release build crashes during optimization of reduce_by_segment.pass.cpp +// with TBB backend. +#if !PSTL_USE_DEBUG && TEST_TBB_BACKEND_PRESENT && defined(__INTEL_LLVM_COMPILER) +# define _PSTL_ICPX_TEST_RED_BY_SEG_OPTIMIZER_CRASH ((__INTEL_LLVM_COMPILER >= 20230200) && (__INTEL_LLVM_COMPILER <= 20240100)) +#else +# define _PSTL_ICPX_TEST_RED_BY_SEG_OPTIMIZER_CRASH 0 +#endif + +// If the workaround macro for the 64-bit type bug is not defined by the user, then exclude 64-bit type testing +// in reduce_by_segment.pass.cpp. +// TODO: When a driver fix is provided to resolve this issue, consider altering this macro or checking the driver version at runtime +// of the underlying sycl::device to determine whether to include or exclude 64-bit type tests. +#if !PSTL_USE_DEBUG && defined(__INTEL_LLVM_COMPILER) +# define _PSTL_ICPX_TEST_RED_BY_SEG_BROKEN_64BIT_TYPES 1 +#endif + +// Group reduction produces wrong results with multiplication of 64-bit for certain driver versions +// TODO: When a driver fix is provided to resolve this issue, consider altering this macro or checking the driver version at runtime +// of the underlying sycl::device to determine whether to include or exclude 64-bit type tests. +#define _PSTL_GROUP_REDUCTION_MULT_INT64_BROKEN 1 + +// oneAPI DPC++ compiler 2022.2 an below show an internal compiler error during the backend code generation of +// minmax_element.pass.cpp affecting min_element, max_element, and minmax_element calls. + +#define _PSTL_ICPX_TEST_MINMAX_ELEMENT_PASS_BROKEN \ + (TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER > 0 && __INTEL_LLVM_COMPILER < 20220300) + +// oneAPI DPC++ compiler fails to compile the sum of an integer and an iterator to a usm-allocated std vector when +// building for an FPGA device. This prevents fpga compilation of usm-allocated std vector wrapped in zip, transform, +// and permutation iterators (as a map). +#if (TEST_DPCPP_BACKEND_PRESENT && defined(ONEDPL_FPGA_DEVICE) && defined(__INTEL_LLVM_COMPILER) && \ + __INTEL_LLVM_COMPILER < 20250100) +# define _PSTL_ICPX_FPGA_TEST_USM_VECTOR_ITERATOR_BROKEN 1 +#else +# define _PSTL_ICPX_FPGA_TEST_USM_VECTOR_ITERATOR_BROKEN 0 +#endif + +// A specific kernel compilation order causes incorrect results on Windows with the DPCPP backend. For now, we reorder +// the test while the issue is being reported to the compiler team. Once it is resolved, this macro can be removed +// or limited to older compiler versions. +#define _PSTL_RED_BY_SEG_WINDOWS_COMPILE_ORDER_BROKEN \ + (_MSC_VER && TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER < 20250100) + +// Intel(R) oneAPI DPC++/C++ compiler produces 'Unexpected kernel lambda size issue' error +#define _PSTL_LAMBDA_PTR_TO_MEMBER_WINDOWS_BROKEN \ + (_MSC_VER && TEST_DPCPP_BACKEND_PRESENT && __INTEL_LLVM_COMPILER <= _PSTL_TEST_LATEST_INTEL_LLVM_COMPILER) + +// To prevent the assertion from Microsoft STL implementation about the comparison of iterators from different containers +#define _PSTL_TEST_ITERATORS_POSSIBLY_EQUAL_BROKEN (_DEBUG && _MSC_VER) + +#if TEST_ONLY_HETERO_POLICIES && !TEST_DPCPP_BACKEND_PRESENT +# error "TEST_ONLY_HETERO_POLICIES is passed but device backend is not available" +#endif + +//There are issues with stable_sort for libcpp with iterators with a deleted comma operator, disable no_comma compile +// only tests. Also, since this adds significant amount of code compilation to the build, lets be more conservative +// about when we try to test this. Since debug build mode and unnamed lambda support dont change the code in any way +// which should interact with what we are testing for here, lets disable it for those cases for time / build space. +#if !defined(_LIBCPP_VERSION) && !PSTL_USE_DEBUG && (TEST_UNNAMED_LAMBDAS || !TEST_DPCPP_BACKEND_PRESENT) +# define TEST_NO_COMMA_ITERATORS 1 +#else +# define TEST_NO_COMMA_ITERATORS 0 +#endif + +// For icpx versions prior to 2024.1, we encounter compilation issues in device_copyable.pass tests for device copyable +// specializations of kernel submitters. It is a test only issue. +#if TEST_DPCPP_BACKEND_PRESENT && defined(__INTEL_LLVM_COMPILER) && __INTEL_LLVM_COMPILER < 20240100 +# define _PSTL_ICPX_DEVICE_COPYABLE_SUBMITTER_BROKEN 1 +#else +# define _PSTL_ICPX_DEVICE_COPYABLE_SUBMITTER_BROKEN 0 +#endif + +// There is a bug in the libc++ at the time of writing this comment with 21 being the latest major release +// 23 is set to avoid frequent bump-ups. +// See: https://github.com/llvm/llvm-project/blob/6096d35ea93c75f648a253a00775b4d74915c819/libcxx/include/__algorithm/ranges_set_union.h#L94 +// This line does not take into account that the iterator-based implementation may arbitrary call comp(a, b) or comp(b, a) +// TODO: report it or contribute. +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 230000 +# define _PSTL_LIBCPP_RANGE_SET_BROKEN 1 +#else +# define _PSTL_LIBCPP_RANGE_SET_BROKEN 0 +#endif + +// Drop view throws exceptions in libstdc++ 10 +#define _PSTL_LIBSTDCXX_XPU_DROP_VIEW_BROKEN (_GLIBCXX_RELEASE == 10) + +// std::ranges::view concept requires default_initializable (pre P2325R3): +// 1. GNU libstdc++ (GCC) - prior to GCC 11.4 +// 2. LLVM libc++ - prior to LLVM 13.0 +// 3. Microsoft STL (MSVC) - prior to VS 2022 17.0 +#if defined(_GLIBCXX_RELEASE) && defined(__GLIBCXX__) +# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE \ + ((_GLIBCXX_RELEASE < 11) || (_GLIBCXX_RELEASE == 11 && __GLIBCXX__ < 20230528)) +#elif defined(_LIBCPP_VERSION) +# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE (_LIBCPP_VERSION < 13000) +#elif defined(_MSVC_STL_VERSION) && defined(_MSVC_STL_UPDATE) +# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE \ + (_MSVC_STL_VERSION < 143 || (_MSVC_STL_VERSION == 143 && _MSVC_STL_UPDATE < 202111)) +#else +# define TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE 0 +#endif + +// P2325R3 also removed default_initializable from weakly_incrementable, which breaks +// std::input_iterator and std::output_iterator on the same pre-P2325R3 implementations. +#define _ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN TEST_STD_RANGES_VIEW_CONCEPT_REQUIRES_DEFAULT_INITIALIZABLE + +#endif // _TEST_CONFIG_H diff --git a/test/support/test_iterators_cpp17.h b/test/support/test_iterators_cpp17.h new file mode 100644 index 00000000000..a76e0bff557 --- /dev/null +++ b/test/support/test_iterators_cpp17.h @@ -0,0 +1,1686 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// This file incorporates work covered by the following copyright and permission +// notice: +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_TEST_ITERATORS_H +#define SUPPORT_TEST_ITERATORS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "double_move_tracker.h" +#include "test_macros.h" +#include "type_algorithms.h" + + +// This iterator meets C++20's Cpp17OutputIterator requirements, as described +// in Table 90 ([output.iterators]). +template +class cpp17_output_iterator +{ + It it_; + support::double_move_tracker tracker_; + + template friend class cpp17_output_iterator; +public: + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR explicit cpp17_output_iterator(It it) : it_(std::move(it)) {} + + template + TEST_CONSTEXPR cpp17_output_iterator(const cpp17_output_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 cpp17_output_iterator(cpp17_output_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + TEST_CONSTEXPR reference operator*() const {return *it_;} + + TEST_CONSTEXPR_CXX14 cpp17_output_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 cpp17_output_iterator operator++(int) {return cpp17_output_iterator(it_++);} + + friend TEST_CONSTEXPR It base(const cpp17_output_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 +template +cpp17_output_iterator(It) -> cpp17_output_iterator; +#endif + +#if TEST_STD_VER > 17 && !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +static_assert(std::output_iterator, int>); +#endif + +// This iterator meets C++20's Cpp17InputIterator requirements, as described +// in Table 89 ([input.iterators]). +template +class cpp17_input_iterator +{ + typedef std::iterator_traits Traits; + It it_; + support::double_move_tracker tracker_; + + template friend class cpp17_input_iterator; +public: + typedef std::input_iterator_tag iterator_category; + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; + typedef It pointer; + typedef typename Traits::reference reference; + + TEST_CONSTEXPR explicit cpp17_input_iterator(It it) : it_(it) {} + + template + TEST_CONSTEXPR cpp17_input_iterator(const cpp17_input_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 cpp17_input_iterator(cpp17_input_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + TEST_CONSTEXPR reference operator*() const {return *it_;} + + TEST_CONSTEXPR_CXX14 cpp17_input_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 cpp17_input_iterator operator++(int) {return cpp17_input_iterator(it_++);} + + friend TEST_CONSTEXPR bool operator==(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const cpp17_input_iterator& x, const cpp17_input_iterator& y) {return x.it_ != y.it_;} + + friend TEST_CONSTEXPR It base(const cpp17_input_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 +template +cpp17_input_iterator(It) -> cpp17_input_iterator; +#endif + +#if TEST_STD_VER > 17 && !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +static_assert(std::input_iterator>); +#endif + +template +class forward_iterator +{ + It it_; + support::double_move_tracker tracker_; + + template friend class forward_iterator; +public: + typedef std::forward_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR forward_iterator() : it_() {} + TEST_CONSTEXPR explicit forward_iterator(It it) : it_(it) {} + + template + TEST_CONSTEXPR forward_iterator(const forward_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 forward_iterator(forward_iterator&& other) + : it_(std::move(other.it_)), tracker_(std::move(other.tracker_)) { + other.it_ = U(); + } + + TEST_CONSTEXPR reference operator*() const {return *it_;} + + TEST_CONSTEXPR_CXX14 forward_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 forward_iterator operator++(int) {return forward_iterator(it_++);} + + friend TEST_CONSTEXPR bool operator==(const forward_iterator& x, const forward_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const forward_iterator& x, const forward_iterator& y) {return x.it_ != y.it_;} + + friend TEST_CONSTEXPR It base(const forward_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 +template +forward_iterator(It) -> forward_iterator; +#endif + +template +class bidirectional_iterator +{ + It it_; + support::double_move_tracker tracker_; + + template friend class bidirectional_iterator; +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR bidirectional_iterator() : it_() {} + TEST_CONSTEXPR explicit bidirectional_iterator(It it) : it_(it) {} + + template + TEST_CONSTEXPR bidirectional_iterator(const bidirectional_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 bidirectional_iterator(bidirectional_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + TEST_CONSTEXPR reference operator*() const {return *it_;} + + TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 bidirectional_iterator& operator--() {--it_; return *this;} + TEST_CONSTEXPR_CXX14 bidirectional_iterator operator++(int) {return bidirectional_iterator(it_++);} + TEST_CONSTEXPR_CXX14 bidirectional_iterator operator--(int) {return bidirectional_iterator(it_--);} + + friend TEST_CONSTEXPR bool operator==(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const bidirectional_iterator& x, const bidirectional_iterator& y) {return x.it_ != y.it_;} + + friend TEST_CONSTEXPR It base(const bidirectional_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 +template +bidirectional_iterator(It) -> bidirectional_iterator; +#endif + +template +class random_access_iterator +{ + It it_; + support::double_move_tracker tracker_; + + template friend class random_access_iterator; +public: + typedef std::random_access_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + + TEST_CONSTEXPR random_access_iterator() : it_() {} + TEST_CONSTEXPR explicit random_access_iterator(It it) : it_(it) {} + + template + TEST_CONSTEXPR random_access_iterator(const random_access_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + TEST_CONSTEXPR_CXX14 random_access_iterator(random_access_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;} + TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];} + + TEST_CONSTEXPR_CXX14 random_access_iterator& operator++() {++it_; return *this;} + TEST_CONSTEXPR_CXX14 random_access_iterator& operator--() {--it_; return *this;} + TEST_CONSTEXPR_CXX14 random_access_iterator operator++(int) {return random_access_iterator(it_++);} + TEST_CONSTEXPR_CXX14 random_access_iterator operator--(int) {return random_access_iterator(it_--);} + + TEST_CONSTEXPR_CXX14 random_access_iterator& operator+=(difference_type n) {it_ += n; return *this;} + TEST_CONSTEXPR_CXX14 random_access_iterator& operator-=(difference_type n) {it_ -= n; return *this;} + friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(random_access_iterator x, difference_type n) {x += n; return x;} + friend TEST_CONSTEXPR_CXX14 random_access_iterator operator+(difference_type n, random_access_iterator x) {x += n; return x;} + friend TEST_CONSTEXPR_CXX14 random_access_iterator operator-(random_access_iterator x, difference_type n) {x -= n; return x;} + friend TEST_CONSTEXPR difference_type operator-(random_access_iterator x, random_access_iterator y) {return x.it_ - y.it_;} + + friend TEST_CONSTEXPR bool operator==(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ == y.it_;} + friend TEST_CONSTEXPR bool operator!=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ != y.it_;} + friend TEST_CONSTEXPR bool operator< (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ < y.it_;} + friend TEST_CONSTEXPR bool operator<=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ <= y.it_;} + friend TEST_CONSTEXPR bool operator> (const random_access_iterator& x, const random_access_iterator& y) {return x.it_ > y.it_;} + friend TEST_CONSTEXPR bool operator>=(const random_access_iterator& x, const random_access_iterator& y) {return x.it_ >= y.it_;} + + friend TEST_CONSTEXPR It base(const random_access_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +#if TEST_STD_VER > 14 +template +random_access_iterator(It) -> random_access_iterator; +#endif + +#if TEST_STD_VER > 17 + +template +class cpp20_random_access_iterator { + It it_; + support::double_move_tracker tracker_; + + template + friend class cpp20_random_access_iterator; + +public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::random_access_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + + constexpr cpp20_random_access_iterator() : it_() {} + constexpr explicit cpp20_random_access_iterator(It it) : it_(it) {} + + template + constexpr cpp20_random_access_iterator(const cpp20_random_access_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template + constexpr cpp20_random_access_iterator(cpp20_random_access_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + constexpr decltype(auto) operator*() const { return *it_; } + constexpr decltype(auto) operator[](difference_type n) const { return it_[n]; } + + constexpr cpp20_random_access_iterator& operator++() { + ++it_; + return *this; + } + constexpr cpp20_random_access_iterator& operator--() { + --it_; + return *this; + } + constexpr cpp20_random_access_iterator operator++(int) { return cpp20_random_access_iterator(it_++); } + constexpr cpp20_random_access_iterator operator--(int) { return cpp20_random_access_iterator(it_--); } + + constexpr cpp20_random_access_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + constexpr cpp20_random_access_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + friend constexpr cpp20_random_access_iterator operator+(cpp20_random_access_iterator x, difference_type n) { + x += n; + return x; + } + friend constexpr cpp20_random_access_iterator operator+(difference_type n, cpp20_random_access_iterator x) { + x += n; + return x; + } + friend constexpr cpp20_random_access_iterator operator-(cpp20_random_access_iterator x, difference_type n) { + x -= n; + return x; + } + friend constexpr difference_type operator-(cpp20_random_access_iterator x, cpp20_random_access_iterator y) { + return x.it_ - y.it_; + } + + friend constexpr bool operator==(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ == y.it_; + } + friend constexpr bool operator!=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ != y.it_; + } + friend constexpr bool operator<(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ < y.it_; + } + friend constexpr bool operator<=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ <= y.it_; + } + friend constexpr bool operator>(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ > y.it_; + } + friend constexpr bool operator>=(const cpp20_random_access_iterator& x, const cpp20_random_access_iterator& y) { + return x.it_ >= y.it_; + } + + friend constexpr It base(const cpp20_random_access_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +template +cpp20_random_access_iterator(It) -> cpp20_random_access_iterator; + +static_assert(std::random_access_iterator>); + +template +class contiguous_iterator { + It it_; + support::double_move_tracker tracker_; + + template + friend class contiguous_iterator; + +public: + using iterator_category = std::contiguous_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + using element_type = value_type; + + constexpr It base() const { return it_; } + + constexpr contiguous_iterator() : it_() {} + constexpr explicit contiguous_iterator(It it) : it_(it) {} + + template + constexpr contiguous_iterator(const contiguous_iterator& u) : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + constexpr contiguous_iterator(contiguous_iterator&& u) : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + constexpr reference operator*() const { return *it_; } + constexpr pointer operator->() const { return it_; } + constexpr reference operator[](difference_type n) const { return it_[n]; } + + constexpr contiguous_iterator& operator++() { + ++it_; + return *this; + } + constexpr contiguous_iterator& operator--() { + --it_; + return *this; + } + constexpr contiguous_iterator operator++(int) { return contiguous_iterator(it_++); } + constexpr contiguous_iterator operator--(int) { return contiguous_iterator(it_--); } + + constexpr contiguous_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + constexpr contiguous_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + friend constexpr contiguous_iterator operator+(contiguous_iterator x, difference_type n) { + x += n; + return x; + } + friend constexpr contiguous_iterator operator+(difference_type n, contiguous_iterator x) { + x += n; + return x; + } + friend constexpr contiguous_iterator operator-(contiguous_iterator x, difference_type n) { + x -= n; + return x; + } + friend constexpr difference_type operator-(contiguous_iterator x, contiguous_iterator y) { return x.it_ - y.it_; } + + friend constexpr bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ == y.it_; + } + friend constexpr bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ != y.it_; + } + friend constexpr bool operator<(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ < y.it_; } + friend constexpr bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ <= y.it_; + } + friend constexpr bool operator>(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ > y.it_; } + friend constexpr bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) { + return x.it_ >= y.it_; + } + + // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=> + + friend constexpr It base(const contiguous_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +template +contiguous_iterator(It) -> contiguous_iterator; + +template +class three_way_contiguous_iterator +{ + static_assert(std::is_pointer_v, "Things probably break in this case"); + + It it_; + support::double_move_tracker tracker_; + + template friend class three_way_contiguous_iterator; +public: + typedef std::contiguous_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::remove_pointer::type element_type; + + constexpr It base() const {return it_;} + + constexpr three_way_contiguous_iterator() : it_() {} + constexpr explicit three_way_contiguous_iterator(It it) : it_(it) {} + + template + constexpr three_way_contiguous_iterator(const three_way_contiguous_iterator& u) + : it_(u.it_), tracker_(u.tracker_) {} + + template ::value>::type> + constexpr three_way_contiguous_iterator(three_way_contiguous_iterator&& u) + : it_(std::move(u.it_)), tracker_(std::move(u.tracker_)) { + u.it_ = U(); + } + + constexpr reference operator*() const {return *it_;} + constexpr pointer operator->() const {return it_;} + constexpr reference operator[](difference_type n) const {return it_[n];} + + constexpr three_way_contiguous_iterator& operator++() {++it_; return *this;} + constexpr three_way_contiguous_iterator& operator--() {--it_; return *this;} + constexpr three_way_contiguous_iterator operator++(int) {return three_way_contiguous_iterator(it_++);} + constexpr three_way_contiguous_iterator operator--(int) {return three_way_contiguous_iterator(it_--);} + + constexpr three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;} + constexpr three_way_contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;} + friend constexpr three_way_contiguous_iterator operator+(three_way_contiguous_iterator x, difference_type n) {x += n; return x;} + friend constexpr three_way_contiguous_iterator operator+(difference_type n, three_way_contiguous_iterator x) {x += n; return x;} + friend constexpr three_way_contiguous_iterator operator-(three_way_contiguous_iterator x, difference_type n) {x -= n; return x;} + friend constexpr difference_type operator-(three_way_contiguous_iterator x, three_way_contiguous_iterator y) {return x.it_ - y.it_;} + + friend constexpr auto operator<=>(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ <=> y.it_;} + friend constexpr bool operator==(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {return x.it_ == y.it_;} + + template + void operator,(T const &) = delete; +}; +template +three_way_contiguous_iterator(It) -> three_way_contiguous_iterator; +#endif // TEST_STD_VER > 17 + +template // ADL base() for everything else (including pointers) +TEST_CONSTEXPR Iter base(Iter i) { return i; } + +template +struct ThrowingIterator { + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const T value_type; + typedef const T * pointer; + typedef const T & reference; + + enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison }; + + TEST_CONSTEXPR ThrowingIterator() + : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {} + TEST_CONSTEXPR explicit ThrowingIterator(const T* first, const T* last, int index = 0, + ThrowingAction action = TADereference) + : begin_(first), end_(last), current_(first), action_(action), index_(index) {} + TEST_CONSTEXPR ThrowingIterator(const ThrowingIterator &rhs) + : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {} + + TEST_CONSTEXPR_CXX14 ThrowingIterator& operator=(const ThrowingIterator& rhs) { + if (action_ == TAAssignment && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator assignment"); +#else + assert(false); +#endif + } + begin_ = rhs.begin_; + end_ = rhs.end_; + current_ = rhs.current_; + action_ = rhs.action_; + index_ = rhs.index_; + return *this; + } + + TEST_CONSTEXPR_CXX14 reference operator*() const { + if (action_ == TADereference && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator dereference"); +#else + assert(false); +#endif + } + return *current_; + } + + TEST_CONSTEXPR_CXX14 ThrowingIterator& operator++() { + if (action_ == TAIncrement && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator increment"); +#else + assert(false); +#endif + } + ++current_; + return *this; + } + + TEST_CONSTEXPR_CXX14 ThrowingIterator operator++(int) { + ThrowingIterator temp = *this; + ++(*this); + return temp; + } + + TEST_CONSTEXPR_CXX14 ThrowingIterator& operator--() { + if (action_ == TADecrement && --index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator decrement"); +#else + assert(false); +#endif + } + --current_; + return *this; + } + + TEST_CONSTEXPR_CXX14 ThrowingIterator operator--(int) { + ThrowingIterator temp = *this; + --(*this); + return temp; + } + + TEST_CONSTEXPR_CXX14 friend bool operator==(const ThrowingIterator& a, const ThrowingIterator& b) { + if (a.action_ == TAComparison && --a.index_ < 0) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::runtime_error("throw from iterator comparison"); +#else + assert(false); +#endif + } + bool atEndL = a.current_ == a.end_; + bool atEndR = b.current_ == b.end_; + if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not. + if (atEndL) return true; // both are at the end (or empty) + return a.current_ == b.current_; + } + + TEST_CONSTEXPR friend bool operator!=(const ThrowingIterator& a, const ThrowingIterator& b) { + return !(a == b); + } + + template + void operator,(T2 const &) = delete; + +private: + const T* begin_; + const T* end_; + const T* current_; + ThrowingAction action_; + mutable int index_; +}; + +template +struct NonThrowingIterator { + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const T value_type; + typedef const T * pointer; + typedef const T & reference; + + NonThrowingIterator() + : begin_(nullptr), end_(nullptr), current_(nullptr) {} + explicit NonThrowingIterator(const T *first, const T *last) + : begin_(first), end_(last), current_(first) {} + NonThrowingIterator(const NonThrowingIterator& rhs) + : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {} + + NonThrowingIterator& operator=(const NonThrowingIterator& rhs) TEST_NOEXCEPT { + begin_ = rhs.begin_; + end_ = rhs.end_; + current_ = rhs.current_; + return *this; + } + + reference operator*() const TEST_NOEXCEPT { + return *current_; + } + + NonThrowingIterator& operator++() TEST_NOEXCEPT { + ++current_; + return *this; + } + + NonThrowingIterator operator++(int) TEST_NOEXCEPT { + NonThrowingIterator temp = *this; + ++(*this); + return temp; + } + + NonThrowingIterator & operator--() TEST_NOEXCEPT { + --current_; + return *this; + } + + NonThrowingIterator operator--(int) TEST_NOEXCEPT { + NonThrowingIterator temp = *this; + --(*this); + return temp; + } + + friend bool operator==(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { + bool atEndL = a.current_ == a.end_; + bool atEndR = b.current_ == b.end_; + if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not. + if (atEndL) return true; // both are at the end (or empty) + return a.current_ == b.current_; + } + + friend bool operator!=(const NonThrowingIterator& a, const NonThrowingIterator& b) TEST_NOEXCEPT { + return !(a == b); + } + + template + void operator,(T2 const &) = delete; + +private: + const T *begin_; + const T *end_; + const T *current_; +}; + +#if TEST_STD_VER > 17 + +template +class cpp20_input_iterator +{ + It it_; + support::double_move_tracker tracker_; + +public: + using value_type = std::iter_value_t; + using difference_type = std::iter_difference_t; + using iterator_concept = std::input_iterator_tag; + + constexpr explicit cpp20_input_iterator(It it) : it_(it) {} + cpp20_input_iterator(cpp20_input_iterator&&) = default; + cpp20_input_iterator& operator=(cpp20_input_iterator&&) = default; + constexpr decltype(auto) operator*() const { return *it_; } + constexpr cpp20_input_iterator& operator++() { ++it_; return *this; } + constexpr void operator++(int) { ++it_; } + + friend constexpr It base(const cpp20_input_iterator& i) { return i.it_; } + + template + void operator,(T const &) = delete; +}; +template +cpp20_input_iterator(It) -> cpp20_input_iterator; + +#if TEST_STD_VER > 17 && !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +static_assert(std::input_iterator>); +#endif + +template +struct iter_value_or_void { using type = void; }; + +template +struct iter_value_or_void { + using type = std::iter_value_t; +}; + +template +class cpp20_output_iterator { + It it_; + support::double_move_tracker tracker_; + +public: + using difference_type = std::iter_difference_t; + + constexpr explicit cpp20_output_iterator(It it) : it_(it) {} + cpp20_output_iterator(cpp20_output_iterator&&) = default; + cpp20_output_iterator& operator=(cpp20_output_iterator&&) = default; + + constexpr decltype(auto) operator*() const { return *it_; } + constexpr cpp20_output_iterator& operator++() { + ++it_; + return *this; + } + constexpr cpp20_output_iterator operator++(int) { return cpp20_output_iterator(it_++); } + + friend constexpr It base(const cpp20_output_iterator& i) { return i.it_; } + + template + void operator,(T const&) = delete; +}; +template +cpp20_output_iterator(It) -> cpp20_output_iterator; + +#if TEST_STD_VER > 17 && !_ONEDPL_CPP20_IN_OUT_ITERATOR_BROKEN +static_assert(std::output_iterator, int>); +#endif + +# if TEST_STD_VER >= 20 + +// An `input_iterator` that can be used in a `std::ranges::common_range` +template +struct common_input_iterator { + Base it_; + + using value_type = std::iter_value_t; + using difference_type = std::intptr_t; + using iterator_concept = std::input_iterator_tag; + + constexpr common_input_iterator() = default; + constexpr explicit common_input_iterator(Base it) : it_(it) {} + + constexpr common_input_iterator& operator++() { + ++it_; + return *this; + } + constexpr void operator++(int) { ++it_; } + + constexpr decltype(auto) operator*() const { return *it_; } + + friend constexpr bool operator==(common_input_iterator const&, common_input_iterator const&) = default; +}; + +# endif // TEST_STD_VER >= 20 + +struct IteratorOpCounts { + std::size_t increments = 0; ///< Number of times the iterator moved forward (++it, it++, it+=positive, it-=negative). + std::size_t decrements = 0; ///< Number of times the iterator moved backward (--it, it--, it-=positive, it+=negative). + std::size_t zero_moves = 0; ///< Number of times a call was made to move the iterator by 0 positions (it+=0, it-=0). + std::size_t equal_cmps = 0; ///< Total number of calls to op== or op!=. If compared against a sentinel object, that + /// sentinel object must call the `record_equality_comparison` function so that the + /// comparison is counted correctly. +}; + +// Iterator adaptor that records its operation counts in a IteratorOpCounts +template +class operation_counting_iterator { +public: + using value_type = typename iter_value_or_void::type; + using difference_type = std::iter_difference_t; + using iterator_concept = + std::conditional_t, std::contiguous_iterator_tag, + std::conditional_t, std::random_access_iterator_tag, + std::conditional_t, std::bidirectional_iterator_tag, + std::conditional_t, std::forward_iterator_tag, + std::conditional_t, std::input_iterator_tag, + /* else */ std::output_iterator_tag + >>>>>; + using iterator_category = iterator_concept; + + operation_counting_iterator() + requires std::default_initializable + = default; + + constexpr explicit operation_counting_iterator(It const& it, IteratorOpCounts* counts = nullptr) + : base_(base(it)), counts_(counts) {} + + constexpr operation_counting_iterator(const operation_counting_iterator& o) { *this = o; } + constexpr operation_counting_iterator(operation_counting_iterator&& o) { *this = o; } + + constexpr operation_counting_iterator& operator=(const operation_counting_iterator& o) = default; + constexpr operation_counting_iterator& operator=(operation_counting_iterator&& o) { return *this = o; } + + friend constexpr It base(operation_counting_iterator const& it) { return It(it.base_); } + + constexpr decltype(auto) operator*() const { return *It(base_); } + + constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; } + + constexpr operation_counting_iterator& operator++() { + It tmp(base_); + base_ = base(++tmp); + moved_by(1); + return *this; + } + + constexpr void operator++(int) { ++*this; } + + constexpr operation_counting_iterator operator++(int) + requires std::forward_iterator + { + auto temp = *this; + ++*this; + return temp; + } + + constexpr operation_counting_iterator& operator--() + requires std::bidirectional_iterator + { + It tmp(base_); + base_ = base(--tmp); + moved_by(-1); + return *this; + } + + constexpr operation_counting_iterator operator--(int) + requires std::bidirectional_iterator + { + auto temp = *this; + --*this; + return temp; + } + + constexpr operation_counting_iterator& operator+=(difference_type const n) + requires std::random_access_iterator + { + It tmp(base_); + base_ = base(tmp += n); + moved_by(n); + return *this; + } + + constexpr operation_counting_iterator& operator-=(difference_type const n) + requires std::random_access_iterator + { + It tmp(base_); + base_ = base(tmp -= n); + moved_by(-n); + return *this; + } + + friend constexpr operation_counting_iterator operator+(operation_counting_iterator it, difference_type n) + requires std::random_access_iterator + { + return it += n; + } + + friend constexpr operation_counting_iterator operator+(difference_type n, operation_counting_iterator it) + requires std::random_access_iterator + { + return it += n; + } + + friend constexpr operation_counting_iterator operator-(operation_counting_iterator it, difference_type n) + requires std::random_access_iterator + { + return it -= n; + } + + friend constexpr difference_type + operator-(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::sized_sentinel_for + { + return base(x) - base(y); + } + + constexpr void record_equality_comparison() const { + if (counts_ != nullptr) + ++counts_->equal_cmps; + } + + constexpr bool operator==(operation_counting_iterator const& other) const + requires std::sentinel_for + { + record_equality_comparison(); + return It(base_) == It(other.base_); + } + + friend constexpr bool operator<(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator + { + return It(x.base_) < It(y.base_); + } + + friend constexpr bool operator>(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator + { + return It(x.base_) > It(y.base_); + } + + friend constexpr bool operator<=(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator + { + return It(x.base_) <= It(y.base_); + } + + friend constexpr bool operator>=(operation_counting_iterator const& x, operation_counting_iterator const& y) + requires std::random_access_iterator + { + return It(x.base_) >= It(y.base_); + } + + template + void operator,(T const &) = delete; + +private: + constexpr void moved_by(difference_type n) { + if (counts_ == nullptr) + return; + if (n > 0) + ++counts_->increments; + else if (n < 0) + ++counts_->decrements; + else + ++counts_->zero_moves; + } + + decltype(base(std::declval())) base_; + IteratorOpCounts* counts_ = nullptr; +}; +template +operation_counting_iterator(It) -> operation_counting_iterator; + +#endif // TEST_STD_VER > 17 + +#if TEST_STD_VER > 17 +template +class sentinel_wrapper { +public: + explicit sentinel_wrapper() = default; + constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {} + constexpr bool operator==(const It& other) const { + // If supported, record statistics about the equality operator call + // inside `other`. + if constexpr (requires { other.record_equality_comparison(); }) { + other.record_equality_comparison(); + } + return base_ == base(other); + } + friend constexpr It base(const sentinel_wrapper& s) { return It(s.base_); } +private: + decltype(base(std::declval())) base_; +}; +template +sentinel_wrapper(It) -> sentinel_wrapper; + +template +class sized_sentinel { +public: + explicit sized_sentinel() = default; + constexpr explicit sized_sentinel(const It& it) : base_(base(it)) {} + constexpr bool operator==(const It& other) const { return base_ == base(other); } + friend constexpr auto operator-(const sized_sentinel& s, const It& i) { return s.base_ - base(i); } + friend constexpr auto operator-(const It& i, const sized_sentinel& s) { return base(i) - s.base_; } + friend constexpr It base(const sized_sentinel& s) { return It(s.base_); } +private: + decltype(base(std::declval())) base_; +}; +template +sized_sentinel(It) -> sized_sentinel; + +namespace adl { + +class Iterator { + public: + using value_type = int; + using reference = int&; + using difference_type = std::ptrdiff_t; + + private: + value_type* ptr_ = nullptr; + int* iter_moves_ = nullptr; + int* iter_swaps_ = nullptr; + + constexpr Iterator(int* p, int* iter_moves, int* iter_swaps) + : ptr_(p) + , iter_moves_(iter_moves) + , iter_swaps_(iter_swaps) {} + + public: + constexpr Iterator() = default; + static constexpr Iterator TrackMoves(int* p, int& iter_moves) { + return Iterator(p, &iter_moves, /*iter_swaps=*/nullptr); + } + static constexpr Iterator TrackSwaps(int& iter_swaps) { + return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps); + } + static constexpr Iterator TrackSwaps(int* p, int& iter_swaps) { + return Iterator(p, /*iter_moves=*/nullptr, &iter_swaps); + } + + constexpr int iter_moves() const { assert(iter_moves_); return *iter_moves_; } + constexpr int iter_swaps() const { assert(iter_swaps_); return *iter_swaps_; } + + constexpr value_type& operator*() const { return *ptr_; } + constexpr reference operator[](difference_type n) const { return ptr_[n]; } + + friend constexpr Iterator operator+(Iterator i, difference_type n) { + return Iterator(i.ptr_ + n, i.iter_moves_, i.iter_swaps_); + } + friend constexpr Iterator operator+(difference_type n, Iterator i) { + return i + n; + } + constexpr Iterator operator-(difference_type n) const { + return Iterator(ptr_ - n, iter_moves_, iter_swaps_); + } + constexpr difference_type operator-(Iterator rhs) const { + return ptr_ - rhs.ptr_; + } + constexpr Iterator& operator+=(difference_type n) { + ptr_ += n; + return *this; + } + constexpr Iterator& operator-=(difference_type n) { + ptr_ -= n; + return *this; + } + + constexpr Iterator& operator++() { ++ptr_; return *this; } + constexpr Iterator operator++(int) { + Iterator prev = *this; + ++ptr_; + return prev; + } + + constexpr Iterator& operator--() { --ptr_; return *this; } + constexpr Iterator operator--(int) { + Iterator prev = *this; + --ptr_; + return prev; + } + + constexpr friend void iter_swap(Iterator a, Iterator b) { + std::swap(a.ptr_, b.ptr_); + if (a.iter_swaps_) { + ++(*a.iter_swaps_); + } + } + + constexpr friend value_type&& iter_move(Iterator iter) { + if (iter.iter_moves_) { + ++(*iter.iter_moves_); + } + return std::move(*iter); + } + + constexpr friend bool operator==(const Iterator& lhs, const Iterator& rhs) { + return lhs.ptr_ == rhs.ptr_; + } + constexpr friend auto operator<=>(const Iterator& lhs, const Iterator& rhs) { + return lhs.ptr_ <=> rhs.ptr_; + } +}; + +} // namespace adl + +template +class rvalue_iterator { +public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::random_access_iterator_tag; + using difference_type = std::ptrdiff_t; + using reference = T&&; + using value_type = T; + + rvalue_iterator() = default; + constexpr rvalue_iterator(T* it) : it_(it) {} + + constexpr reference operator*() const { return std::move(*it_); } + + constexpr rvalue_iterator& operator++() { + ++it_; + return *this; + } + + constexpr rvalue_iterator operator++(int) { + auto tmp = *this; + ++it_; + return tmp; + } + + constexpr rvalue_iterator& operator--() { + --it_; + return *this; + } + + constexpr rvalue_iterator operator--(int) { + auto tmp = *this; + --it_; + return tmp; + } + + constexpr rvalue_iterator operator+(difference_type n) const { + auto tmp = *this; + tmp.it_ += n; + return tmp; + } + + constexpr friend rvalue_iterator operator+(difference_type n, rvalue_iterator iter) { + iter += n; + return iter; + } + + constexpr rvalue_iterator operator-(difference_type n) const { + auto tmp = *this; + tmp.it_ -= n; + return tmp; + } + + constexpr difference_type operator-(const rvalue_iterator& other) const { return it_ - other.it_; } + + constexpr rvalue_iterator& operator+=(difference_type n) { + it_ += n; + return *this; + } + + constexpr rvalue_iterator& operator-=(difference_type n) { + it_ -= n; + return *this; + } + + constexpr reference operator[](difference_type n) const { return std::move(it_[n]); } + + auto operator<=>(const rvalue_iterator&) const noexcept = default; + +private: + T* it_; +}; + +template +rvalue_iterator(T*) -> rvalue_iterator; + +static_assert(std::random_access_iterator>); + +// Proxy +// ====================================================================== +// Proxy that can wrap a value or a reference. It simulates C++23's tuple +// but simplified to just hold one argument. +// Note that unlike tuple, this class deliberately doesn't have special handling +// of swap to cause a compilation error if it's used in an algorithm that relies +// on plain swap instead of ranges::iter_swap. +// This class is useful for testing that if algorithms support proxy iterator +// properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of +// plain swap and std::move. +template +struct Proxy; + +template +inline constexpr bool IsProxy = false; + +template +inline constexpr bool IsProxy> = true; + +template +struct Proxy { + T data; + + constexpr T& getData() & { return data; } + + constexpr const T& getData() const& { return data; } + + constexpr T&& getData() && { return static_cast(data); } + + constexpr const T&& getData() const&& { return static_cast(data); } + + template + requires std::constructible_from + constexpr Proxy(U&& u) : data{std::forward(u)} {} + + // This constructor covers conversion from cvref of Proxy, including non-const/const versions of copy/move constructor + template + requires(IsProxy> && std::constructible_from().getData())>) + constexpr Proxy(Other&& other) : data{std::forward(other).getData()} {} + + template + requires(IsProxy> && std::assignable_from().getData())>) + constexpr Proxy& operator=(Other&& other) { + data = std::forward(other).getData(); + return *this; + } + + // const assignment required to make ProxyIterator model std::indirectly_writable + template + requires(IsProxy> && std::assignable_from().getData())>) + constexpr const Proxy& operator=(Other&& other) const { + data = std::forward(other).getData(); + return *this; + } + + // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence + // over the templated `operator=` above because it's a better match). + constexpr Proxy& operator=(const Proxy& rhs) { + data = rhs.data; + return *this; + } + + // no specialised swap function that takes const Proxy& and no specialised const member swap + // Calling swap(Proxy{}, Proxy{}) would fail (pass prvalues) + + // Compare operators are defined for the convenience of the tests + friend constexpr bool operator==(const Proxy&, const Proxy&) + requires (std::equality_comparable && !std::is_reference_v) + = default; + + // Helps compare e.g. `Proxy` and `Proxy`. Note that the default equality comparison operator is deleted + // when `T` is a reference type. + template + friend constexpr bool operator==(const Proxy& lhs, const Proxy& rhs) + requires std::equality_comparable_with, std::decay_t> { + return lhs.data == rhs.data; + } + + friend constexpr auto operator<=>(const Proxy&, const Proxy&) + requires (std::three_way_comparable && !std::is_reference_v) + = default; + + // Helps compare e.g. `Proxy` and `Proxy`. Note that the default 3-way comparison operator is deleted when + // `T` is a reference type. + template + friend constexpr auto operator<=>(const Proxy& lhs, const Proxy& rhs) + requires std::three_way_comparable_with, std::decay_t> { + return lhs.data <=> rhs.data; + } +}; + +// This is to make ProxyIterator model `std::indirectly_readable` +template class TQual, template class UQual> + requires requires { typename std::common_reference_t, UQual>; } +struct std::basic_common_reference, Proxy, TQual, UQual> { + using type = Proxy, UQual>>; +}; + +template + requires requires { typename std::common_type_t; } +struct std::common_type, Proxy> { + using type = Proxy>; +}; + +// ProxyIterator +// ====================================================================== +// It wraps `Base` iterator and when dereferenced it returns a Proxy +// It simulates C++23's zip_view::iterator but simplified to just wrap +// one base iterator. +// Note it forwards value_type, iter_move, iter_swap. e.g if the base +// iterator is int*, +// operator* -> Proxy +// iter_value_t -> Proxy +// iter_move -> Proxy +template +struct ProxyIteratorBase {}; + +template + requires std::derived_from< + typename std::iterator_traits::iterator_category, + std::input_iterator_tag> +struct ProxyIteratorBase { + using iterator_category = std::input_iterator_tag; +}; + +template +consteval auto get_iterator_concept() { + if constexpr (std::random_access_iterator) { + return std::random_access_iterator_tag{}; + } else if constexpr (std::bidirectional_iterator) { + return std::bidirectional_iterator_tag{}; + } else if constexpr (std::forward_iterator) { + return std::forward_iterator_tag{}; + } else { + return std::input_iterator_tag{}; + } +} + +template +struct ProxyIterator : ProxyIteratorBase { + Base base_; + + using iterator_concept = decltype(get_iterator_concept()); + using value_type = Proxy>; + using difference_type = std::iter_difference_t; + + ProxyIterator() + requires std::default_initializable + = default; + + constexpr ProxyIterator(Base base) : base_{std::move(base)} {} + + template + requires std::constructible_from + constexpr ProxyIterator(T&& t) : base_{std::forward(t)} {} + + friend constexpr decltype(auto) base(const ProxyIterator& p) { return base(p.base_); } + + // Specialization of iter_move + // If operator* returns Proxy, iter_move will return Proxy + // Note std::move(*it) returns Proxy&&, which is not what we want as + // it will likely result in a copy rather than a move + friend constexpr Proxy> iter_move(const ProxyIterator& p) noexcept { + return {std::ranges::iter_move(p.base_)}; + } + + // Specialization of iter_swap + // Note std::swap(*x, *y) would fail to compile as operator* returns prvalues + // and std::swap takes non-const lvalue references + friend constexpr void iter_swap(const ProxyIterator& x, const ProxyIterator& y) noexcept { + std::ranges::iter_swap(x.base_, y.base_); + } + + // to satisfy input_iterator + constexpr Proxy> operator*() const { return {*base_}; } + + constexpr ProxyIterator& operator++() { + ++base_; + return *this; + } + + constexpr void operator++(int) { ++*this; } + + friend constexpr bool operator==(const ProxyIterator& x, const ProxyIterator& y) + requires std::equality_comparable { + return x.base_ == y.base_; + } + + // to satisfy forward_iterator + constexpr ProxyIterator operator++(int) + requires std::forward_iterator { + auto tmp = *this; + ++*this; + return tmp; + } + + // to satisfy bidirectional_iterator + constexpr ProxyIterator& operator--() + requires std::bidirectional_iterator { + --base_; + return *this; + } + + constexpr ProxyIterator operator--(int) + requires std::bidirectional_iterator { + auto tmp = *this; + --*this; + return tmp; + } + + // to satisfy random_access_iterator + constexpr ProxyIterator& operator+=(difference_type n) + requires std::random_access_iterator { + base_ += n; + return *this; + } + + constexpr ProxyIterator& operator-=(difference_type n) + requires std::random_access_iterator { + base_ -= n; + return *this; + } + + constexpr Proxy> operator[](difference_type n) const + requires std::random_access_iterator { + return {base_[n]}; + } + + friend constexpr bool operator<(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ < y.base_; + } + + friend constexpr bool operator>(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ > y.base_; + } + + friend constexpr bool operator<=(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ <= y.base_; + } + + friend constexpr bool operator>=(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ >= y.base_; + } + + friend constexpr auto operator<=>(const ProxyIterator& x, const ProxyIterator& y) + requires(std::random_access_iterator && std::three_way_comparable) { + return x.base_ <=> y.base_; + } + + friend constexpr ProxyIterator operator+(const ProxyIterator& x, difference_type n) + requires std::random_access_iterator { + return ProxyIterator{x.base_ + n}; + } + + friend constexpr ProxyIterator operator+(difference_type n, const ProxyIterator& x) + requires std::random_access_iterator { + return ProxyIterator{n + x.base_}; + } + + friend constexpr ProxyIterator operator-(const ProxyIterator& x, difference_type n) + requires std::random_access_iterator { + return ProxyIterator{x.base_ - n}; + } + + friend constexpr difference_type operator-(const ProxyIterator& x, const ProxyIterator& y) + requires std::random_access_iterator { + return x.base_ - y.base_; + } +}; +template +ProxyIterator(Base) -> ProxyIterator; + +static_assert(std::indirectly_readable>); +static_assert(std::indirectly_writable, Proxy>); +static_assert(std::indirectly_writable, Proxy>); + +template +using Cpp20InputProxyIterator = ProxyIterator>; + +template +using ForwardProxyIterator = ProxyIterator>; + +template +using BidirectionalProxyIterator = ProxyIterator>; + +template +using RandomAccessProxyIterator = ProxyIterator>; + +template +using ContiguousProxyIterator = ProxyIterator>; + +template +struct ProxySentinel { + BaseSent base_; + + ProxySentinel() = default; + constexpr ProxySentinel(BaseSent base) : base_{std::move(base)} {} + + template + requires std::equality_comparable_with + friend constexpr bool operator==(const ProxyIterator& p, const ProxySentinel& sent) { + return p.base_ == sent.base_; + } +}; +template +ProxySentinel(BaseSent) -> ProxySentinel; + +template + requires std::ranges::view +struct ProxyRange { + Base base_; + + constexpr auto begin() { return ProxyIterator{std::ranges::begin(base_)}; } + + constexpr auto end() { return ProxySentinel{std::ranges::end(base_)}; } + + constexpr auto begin() const + requires std::ranges::input_range { + return ProxyIterator{std::ranges::begin(base_)}; + } + + constexpr auto end() const + requires std::ranges::input_range { + return ProxySentinel{std::ranges::end(base_)}; + } +}; + +template + requires std::ranges::viewable_range +ProxyRange(R&&) -> ProxyRange>; + +#endif // TEST_STD_VER > 17 + +#if TEST_STD_VER >= 17 + +namespace util { +template +class iterator_wrapper { + Iter iter_; + + using iter_traits = std::iterator_traits; + +public: + using iterator_category = typename iter_traits::iterator_category; + using value_type = typename iter_traits::value_type; + using difference_type = typename iter_traits::difference_type; + using pointer = typename iter_traits::pointer; + using reference = typename iter_traits::reference; + + constexpr iterator_wrapper() : iter_() {} + constexpr explicit iterator_wrapper(Iter iter) : iter_(iter) {} + + decltype(*iter_) operator*() { return *iter_; } + decltype(*iter_) operator*() const { return *iter_; } + + decltype(iter_[0]) operator[](difference_type v) const { + return iter_[v]; + } + + Derived& operator++() { + ++iter_; + return static_cast(*this); + } + + Derived operator++(int) { + auto tmp = static_cast(*this); + ++(*this); + return tmp; + } + + Derived& operator--() { + --iter_; + return static_cast(*this); + } + + Derived operator--(int) { + auto tmp = static_cast(*this); + --(*this); + return tmp; + } + + Derived& operator+=(difference_type i) { + iter_ += i; + return static_cast(*this); + } + + Derived& operator-=(difference_type i) { + iter_ -= i; + return static_cast(*this); + } + + friend decltype(iter_ - iter_) operator-(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { + return lhs.iter_ - rhs.iter_; + } + + friend Derived operator-(Derived iter, difference_type i) { + iter.iter_ -= i; + return iter; + } + + friend Derived operator+(Derived iter, difference_type i) { + iter.iter_ += i; + return iter; + } + + friend Derived operator+(difference_type i, Derived iter) { return iter + i; } + + friend bool operator==(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ == rhs.iter_; } + friend bool operator!=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ != rhs.iter_; } + + friend bool operator>(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ > rhs.iter_; } + friend bool operator<(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ < rhs.iter_; } + friend bool operator<=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ <= rhs.iter_; } + friend bool operator>=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ >= rhs.iter_; } +}; + +class iterator_error : std::runtime_error { +public: + iterator_error(const char* what) : std::runtime_error(what) {} +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +class throw_on_move_iterator : public iterator_wrapper, Iter> { + using base = iterator_wrapper, Iter>; + + int moves_until_throw_ = 0; + +public: + using difference_type = typename base::difference_type; + using value_type = typename base::value_type; + using iterator_category = typename base::iterator_category; + + throw_on_move_iterator() = default; + throw_on_move_iterator(Iter iter, int moves_until_throw) + : base(std::move(iter)), moves_until_throw_(moves_until_throw) {} + + throw_on_move_iterator(const throw_on_move_iterator& other) : base(other) {} + throw_on_move_iterator& operator=(const throw_on_move_iterator& other) { + static_cast(*this) = other; + return *this; + } + + throw_on_move_iterator(throw_on_move_iterator&& other) + : base(std::move(other)), moves_until_throw_(other.moves_until_throw_ - 1) { + if (moves_until_throw_ == -1) + throw iterator_error("throw_on_move_iterator"); + } + + throw_on_move_iterator& operator=(throw_on_move_iterator&& other) { + moves_until_throw_ = other.moves_until_throw_ - 1; + if (moves_until_throw_ == -1) + throw iterator_error("throw_on_move_iterator"); + return *this; + } +}; + +template +throw_on_move_iterator(Iter) -> throw_on_move_iterator; +#endif // TEST_HAS_NO_EXCEPTIONS +} // namespace util + +#endif // TEST_STD_VER >= 17 + +namespace types { +template +using random_access_iterator_list = + type_list= 20 + contiguous_iterator, +#endif + random_access_iterator >; + +template +using bidirectional_iterator_list = + concatenate_t, type_list > >; + +template +using forward_iterator_list = concatenate_t, type_list > >; + +template +using cpp17_input_iterator_list = concatenate_t, type_list > >; + +#if TEST_STD_VER >= 20 +template +using cpp20_input_iterator_list = + concatenate_t, type_list, cpp17_input_iterator>>; +#endif +} // namespace types + + +#endif // SUPPORT_TEST_ITERATORS_H diff --git a/test/support/test_macros.h b/test/support/test_macros.h index 0b325e087ba..b45a433a4ee 100644 --- a/test/support/test_macros.h +++ b/test/support/test_macros.h @@ -384,4 +384,36 @@ inline void DoNotOptimize(Tp const& value) { #define TEST_PREPARE_CALLABLE(std_algo_name) \ [](auto&&... __args) { return std_algo_name(std::forward(__args)...); } +#if TEST_STD_VER >= 14 +# define TEST_CONSTEXPR_CXX14 constexpr +#else +# define TEST_CONSTEXPR_CXX14 +#endif + +#if TEST_STD_VER >= 11 +# define TEST_ALIGNOF(...) alignof(__VA_ARGS__) +# define TEST_ALIGNAS(...) alignas(__VA_ARGS__) +# define TEST_CONSTEXPR constexpr +# define TEST_NOEXCEPT noexcept +# define TEST_NOEXCEPT_FALSE noexcept(false) +# define TEST_NOEXCEPT_COND(...) noexcept(__VA_ARGS__) +#else +# if defined(TEST_COMPILER_CLANG) +# define TEST_ALIGNOF(...) _Alignof(__VA_ARGS__) +# else +# define TEST_ALIGNOF(...) __alignof(__VA_ARGS__) +# endif +# define TEST_ALIGNAS(...) __attribute__((__aligned__(__VA_ARGS__))) +# define TEST_CONSTEXPR +# define TEST_NOEXCEPT throw() +# define TEST_NOEXCEPT_FALSE +# define TEST_NOEXCEPT_COND(...) +#endif + +#if TEST_STD_VER >= 17 +# define TEST_CONSTEXPR_CXX17 constexpr +#else +# define TEST_CONSTEXPR_CXX17 +#endif + #endif // _SUPPORT_TEST_MACROS_H diff --git a/test/support/test_range.h b/test/support/test_range.h new file mode 100644 index 00000000000..d034462bdf6 --- /dev/null +++ b/test/support/test_range.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LIBCXX_TEST_SUPPORT_TEST_RANGE_H +#define LIBCXX_TEST_SUPPORT_TEST_RANGE_H + +#include +#include +#include +#include +#include + +#include "test_iterators_cpp17.h" + +#if TEST_STD_VER < 20 +# error "test/support/test_range.h" can only be included in builds supporting ranges +#endif + +struct sentinel { + bool operator==(std::input_or_output_iterator auto const&) const; +}; + +template