2222#include < utility> // std::declval
2323#include < iterator> // std::iterator_traits
2424#include < type_traits> // std::decay_t, std::remove_cv_t, std::remove_reference_t, std::invoke_result_t, ...
25+ #include < cassert> // assert
2526
2627#if _ONEDPL_CPP20_RANGES_PRESENT
2728# include < ranges> // std::ranges::sized_range, std::ranges::range_size_t
@@ -34,6 +35,107 @@ namespace oneapi
3435{
3536namespace dpl
3637{
38+ namespace __ranges
39+ {
40+ #if _ONEDPL_CPP20_RANGES_PRESENT
41+ template <typename _Range>
42+ auto
43+ __begin (_Range&& __rng) -> decltype(std::ranges::begin(std::forward<_Range>(__rng)))
44+ {
45+ return std::ranges::begin (std::forward<_Range>(__rng));
46+ }
47+ #else
48+ template <typename _Range>
49+ auto
50+ __begin (_Range&& __rng) -> decltype(__rng.begin())
51+ {
52+ return __rng.begin ();
53+ }
54+ #endif
55+
56+ #if _ONEDPL_CPP20_RANGES_PRESENT
57+ template <typename _Range>
58+ auto
59+ __end (_Range&& __rng) -> decltype(std::ranges::end(std::forward<_Range>(__rng)))
60+ {
61+ return std::ranges::end (std::forward<_Range>(__rng));
62+ }
63+ #else
64+ template <typename _Range>
65+ auto
66+ __end (_Range&& __rng) -> decltype(__rng.end())
67+ {
68+ return __rng.end ();
69+ }
70+ #endif
71+
72+ #if _ONEDPL_CPP20_RANGES_PRESENT
73+ template <typename _Range>
74+ auto
75+ __size (_Range&& __rng) -> decltype(std::ranges::size(std::forward<_Range>(__rng)))
76+ {
77+ return std::ranges::size (std::forward<_Range>(__rng));
78+ }
79+ #else
80+ template <typename _R, typename = void >
81+ struct __has_size : std::false_type
82+ {
83+ };
84+
85+ template <typename _R>
86+ struct __has_size <_R, std::void_t <decltype (std::declval<_R>().size())>> : std::true_type
87+ {
88+ };
89+
90+ template <typename _Range>
91+ std::enable_if_t <__has_size<_Range>::value, decltype (std::declval<_Range>().size())>
92+ __size (_Range&& __rng)
93+ {
94+ return __rng.size ();
95+ }
96+
97+ template <typename _Range>
98+ std::enable_if_t <!__has_size<_Range>::value, decltype (__end(std::declval<_Range>()) - __begin(std::declval<_Range>()))>
99+ __size (_Range&& __rng)
100+ {
101+ return __end (__rng) - __begin (__rng);
102+ }
103+ #endif
104+
105+ #if _ONEDPL_CPP20_RANGES_PRESENT
106+ template <typename _Range>
107+ bool
108+ __empty (_Range&& __rng)
109+ {
110+ return std::ranges::empty (__rng);
111+ }
112+ #else
113+ template <typename _R, typename = void >
114+ struct __has_empty : std::false_type
115+ {
116+ };
117+
118+ template <typename _R>
119+ struct __has_empty <_R, std::void_t <decltype (std::declval<_R>().empty())>> : std::true_type
120+ {
121+ };
122+
123+ template <typename _Range>
124+ std::enable_if_t <__has_empty<_Range>::value, bool >
125+ __empty (_Range&& __rng)
126+ {
127+ return __rng.empty ();
128+ }
129+
130+ template <typename _Range>
131+ std::enable_if_t <!__has_empty<_Range>::value, bool >
132+ __empty (_Range&& __rng)
133+ {
134+ return __size (__rng) == 0 ;
135+ }
136+ #endif
137+
138+ } // namespace __ranges
37139
38140namespace __internal
39141{
@@ -44,8 +146,8 @@ get_value_type(int) -> typename ::std::decay_t<_R>::value_type;
44146
45147template <typename _R>
46148auto
47- get_value_type (long ) ->
48- typename :: std::iterator_traits<::std:: decay_t < decltype (:: std::declval<_R&>().begin( ))>>::value_type;
149+ get_value_type (long ) -> typename std::iterator_traits<
150+ std::decay_t < decltype (oneapi::dpl::__ranges::__begin( std::declval<_R&>()))>>::value_type;
49151
50152template <typename _It>
51153auto
@@ -87,21 +189,28 @@ using __range_size_t = typename __range_size<_R>::type;
87189
88190template <typename _R>
89191auto
90- __check_size (int ) -> decltype (std::declval<_R&>().size( ));
192+ __check_size (int ) -> decltype(__get_buffer_size( std::declval<_R&>()));
91193
92194template <typename _R>
93195auto
94- __check_size (long ) -> decltype (std::declval<_R&>().get_count( ));
196+ __check_size (long ) -> decltype(oneapi::dpl::__ranges::__size( std::declval<_R&>()));
95197
96- #if _ONEDPL_CPP20_RANGES_PRESENT
97- template <typename _R>
198+ template <typename _It>
98199auto
99- __check_size (long long ) -> decltype(std::ranges::size(std::declval<_R&>()));
100- #endif // _ONEDPL_CPP20_RANGES_PRESENT
200+ __check_size (long long ) -> typename std::iterator_traits<_It>::difference_type;
101201
102- template <typename _It >
202+ template <typename _R >
103203auto
104- __check_size (...) -> typename std::iterator_traits<_It>::difference_type;
204+ __check_size (...)
205+ {
206+ // static_assert should always fail when this overload is chosen, so its condition must depend on
207+ // the template parameter and evaluate to false
208+ static_assert (
209+ std::is_same_v<_R, void >,
210+ " error: unable to determine the size of the range; the range must provide a 'get_count()' or 'size()' member, "
211+ " or otherwise support size determination (e.g., via std::ranges::size or by supporting begin/end for distance "
212+ " calculation)" );
213+ }
105214
106215template <typename _R>
107216using __difference_t = std::make_signed_t <decltype (__check_size<_R>(0 ))>;
@@ -121,70 +230,6 @@ using projected_value_t = std::remove_cvref_t<std::invoke_result_t<Proj&, std::i
121230namespace __ranges
122231{
123232
124- #if _ONEDPL_CPP20_RANGES_PRESENT
125- template <typename _Range>
126- bool
127- __empty (_Range&& __rng)
128- {
129- return std::ranges::empty (__rng);
130- }
131- #else
132- template <typename _R, typename = void >
133- struct __has_empty : std::false_type
134- {
135- };
136-
137- template <typename _R>
138- struct __has_empty <_R, std::void_t <decltype (std::declval<_R>().empty())>> : std::true_type
139- {
140- };
141-
142- template <typename _Range>
143- bool
144- __empty (_Range&& __rng)
145- {
146- if constexpr (__has_empty<_Range>::value)
147- return __rng.empty ();
148- else
149- return __rng.begin () == __rng.end ();
150- }
151- #endif
152-
153- template <typename _R, typename = void >
154- struct __has_size : std::false_type
155- {
156- };
157-
158- template <typename _R>
159- struct __has_size <_R, std::void_t <decltype (std::declval<_R>().size())>> : std::true_type
160- {
161- };
162-
163- template <typename _Range>
164- std::enable_if_t <__has_size<_Range>::value, decltype (std::declval<_Range>().size())>
165- __size (_Range&& __rng)
166- {
167- return __rng.size ();
168- }
169-
170- #if _ONEDPL_CPP20_RANGES_PRESENT
171- template <typename _Range>
172- std::enable_if_t <!__has_size<_Range>::value,
173- decltype (std::ranges::distance(std::declval<_Range>().begin(), std::declval<_Range>().end()))>
174- __size(_Range&& __rng)
175- {
176- return std::ranges::distance (__rng.begin (), __rng.end ());
177- }
178- #else
179- template <typename _Range>
180- std::enable_if_t <!__has_size<_Range>::value,
181- decltype (std::distance(std::declval<_Range>().begin(), std::declval<_Range>().end()))>
182- __size(_Range&& __rng)
183- {
184- return std::distance (__rng.begin (), __rng.end ());
185- }
186- #endif
187-
188233template <typename ... _Rng>
189234using __common_size_t = std::common_type_t <std::make_unsigned_t <decltype (__size(std::declval<_Rng>()))>...>;
190235
@@ -725,58 +770,62 @@ struct __has_subscription_op<_R, std::void_t<decltype(std::declval<_R>().operato
725770{
726771};
727772
728- template <typename _Source, typename _Base = std::decay_t <_Source>>
729- struct __subscription_impl_view_simple : _Base
773+ template <typename _Range, typename = std::enable_if_t <__has_subscription_op<_Range>::value>>
774+ _Range&&
775+ __get_subscription_view (_Range&& __rng)
730776{
731- static_assert (
732- !__has_subscription_op<_Base>::value,
733- " The usage of __subscription_impl_view_simple prohibited if std::decay_t<_Source>::operator[] implemented " );
777+ // If the range supports operator[], return it as is
778+ return std::forward<_Range>(__rng);
779+ }
734780
735- using value_type = oneapi::dpl::__internal::__value_t <_Base>;
736- using index_type = oneapi::dpl::__internal::__difference_t <_Base>;
781+ #if _ONEDPL_CPP20_RANGES_PRESENT
782+ template <std::ranges::view _View>
783+ requires std::ranges::random_access_range<_View>
784+ struct __subscription_impl_view_simple : std::ranges::view_interface<__subscription_impl_view_simple<_View>>
785+ {
786+ static_assert (!__has_subscription_op<_View>::value,
787+ " The usage of __subscription_impl_view_simple prohibited if _View::operator[] implemented" );
788+
789+ _View __base;
737790
738- // Define default constructors
739- __subscription_impl_view_simple (const __subscription_impl_view_simple&) = default ;
740- __subscription_impl_view_simple (__subscription_impl_view_simple&&) = default ;
791+ constexpr explicit __subscription_impl_view_simple (_View __view) : __base(std::move(__view)) {}
741792
742- // Define custom constructor to forward arguments to the base class
743- template <typename ... _Args>
744- __subscription_impl_view_simple (_Args&&... __args) : _Base(std::forward<_Args>(__args)...)
793+ constexpr auto
794+ begin () const
745795 {
796+ return __begin (__base);
746797 }
747798
748- // Define default operator=
749- __subscription_impl_view_simple&
750- operator =( const __subscription_impl_view_simple&) = default ;
751- __subscription_impl_view_simple&
752- operator =(__subscription_impl_view_simple&&) = default ;
799+ constexpr auto
800+ end () const
801+ {
802+ return __end (__base);
803+ }
753804
754- decltype ( auto )
755- operator [](index_type __i)
805+ constexpr auto
806+ size () const
756807 {
757- return * std::next ( _Base::begin (), __i );
808+ return __size (__base );
758809 }
759810
760- decltype ( auto )
761- operator [](index_type __i ) const
811+ constexpr _View
812+ base ( ) const
762813 {
763- return * std::next ( _Base::begin (), __i) ;
814+ return __base ;
764815 }
765816};
766817
767- template <typename _Range>
768- decltype (auto )
769- __get_subscription_view (_Range&& __rng)
818+ template <typename _View, typename _ViewInstance = std::remove_cvref_t <_View>>
819+ requires (!__has_subscription_op<_ViewInstance>::value) && std::ranges::view<_ViewInstance> &&
820+ std::ranges::random_access_range<_ViewInstance>
821+ auto
822+ __get_subscription_view(_View&& __view)
770823{
771- if constexpr (__has_subscription_op<_Range>::value)
772- {
773- return std::forward<_Range>(__rng);
774- }
775- else
776- {
777- return __subscription_impl_view_simple<_Range>(std::forward<_Range>(__rng));
778- }
824+ // If the view doesn't support operator[], wrap it with __subscription_impl_view_simple
825+ // to provide operator[] access and extend lifetime if necessary (for temporary ranges).
826+ return __subscription_impl_view_simple<_ViewInstance>(__view);
779827}
828+ #endif // _ONEDPL_CPP20_RANGES_PRESENT
780829
781830} // namespace __ranges
782831} // namespace dpl
0 commit comments