-
Notifications
You must be signed in to change notification settings - Fork 114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[oneDPL][ranges] + zip_view implementation for C++20 #1877
base: main
Are you sure you want to change the base?
Conversation
9342293
to
91cf6b0
Compare
603daed
to
80ef9c5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me leave just a couple of minor comments. I am going to look at the whole PR during this week.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about testing the following properties of zip_view/zip?
- begin/end (they should also probably be checked if they are iterators)
- cbegin/cend
- front/back
- size
- empty
- operator bool
- construction:
- ranges::zip(...)/ranges::zip_view(...)
- empty view (views::zip())
- another view (*move construction is not checked)
- another zip_view
- ranges::zip(...) is a customization point object
I assume that the functionality must match what is required from c++ standard looking at the description. That's why I suggest testing all these properties. Let me know if the implementation is expected to be more relaxed (and how if it is).
Update. I see that the PR integrates the whole LLVM test suite now. The table is not relevant now
The description says:
According to SYCL 2020, |
The advantage here of using oneDPL's tuple is that it is trivially copyable (for trivially copyable types) which means that any class or structure which uses oneDPL's tuple can be implicitly device copyable rather than requiring a specialization of sycl::is_device_copyable (because of the tuple). The advantage is not just to avoid extra code here but also to not impose requirements on users to provide these specializations for types which are composed of a zip_view as well. There can be downsides to using oneDPLs tuple in that it may not be as fully featured as |
Actually, before C++23 standard library there is a problem with |
f1c08a6
to
74d52be
Compare
regarding > * cbegin + cend
|
78abd7f
to
fdf3e9b
Compare
if (x.current_ < y.current_) | ||
return -1; | ||
else if (x.current_ == y.current_) | ||
return 0; | ||
return 1; //x.current > y.current_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why cannot we use x.current <=> y.current
? Spaceship operator is undefined for some of our internal iterator types or it is undefined for internal tuple?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, spaceship operator is undefined for x.current_
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When adding comparison between internal tuples, we looked at adding spaceship and it was deemed not worth the effort at the time. We could use this as motivation for adding it, but it would require a bit of work. We would need to trigger it off of __cpp_lib_three_way_comparison >= 201907L
, and in that case replace the existing comparison operators with the spaceship, to time it properly with std::tuple <=> operator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thought was that it wasn't worth the maintenance because we would need to implement both to support our full support matrix, and it would be only helpful for those explicitly calling <=>
on the internal tuple (which is what we might want to do here as I understand it).
|
||
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) | ||
assert(std::get<0>(zip_view_sort[i]) == max_n - 1 - i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our testing framework is not adapted for assert
: it defines NDEBUG during release test builds. We should either avoid that definition, or do not rely on assert
in the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- In spite of that we are using
assert
in our tests more then 10 files... It seems an issue should be created. - I know that a better way to use our own macro like
EXPECT_TRUE
f.e.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I will create it.
- That sounds good. Could you do it? I see that there is still one
assert
in the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I will create it.
Done: #1945.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- done.
And I suggest offline discussion aboutassert
/EXPECT_TRUE
/NDEBUG
std::vector<int> vec1(max_n); | ||
std::vector<int> vec2(max_n/2); | ||
|
||
auto zip_view = dpl_ranges::zip(vec1, vec2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should zip also be checked for availability in oneapi::dpl::views
namespace?
zip_view is based on view_iterface, and the later does not have cbegin/cend in c++20. That means our c++20 zip_view will not have cbegin/cend, and we are not going to provide them. Is that correct understanding? |
#ifndef _ONEDPL_ZIP_VIEW_IMPL_H | ||
#define _ONEDPL_ZIP_VIEW_IMPL_H | ||
|
||
#if _ONEDPL_CPP20_RANGES_PRESENT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not we think about having oneapi::dpl::zip_view
as part of namespace std::ranges
prior to C++23?
It will allow the user to have portable code for each version of the standard. Otherwise, we will need to think about aligning oneapi::dpl::zip_view
with the C++23 and later as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean a kind of name injection into std::ranges
prior to C++23? Good question.
On one hand - it is useful when a user is going to modify his code forward to C++23.
On the other hand, having std::ranges::zip_view
(in result of name oneapi::dpl::zip_view
injection), enforces us to be fully compliance with standard zip_view
C++23. At least, the proposed zip_view implementation works only with random access views, for example. And we don't need more for oneDPL needs.
I would suggest rather to have an alias oneapi::dpl::zip_view
, which is our own implementation class prior to C++23 and which is std::ranges::zip_view
for C++23 and higher.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of having the alias to std::ranges::zip_view
in oneDPL for C++23 and higher. It perfectly fits the idea of having everything that should work in the offloaded code in oneapi::dpl
namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can consider such an alias, but for me that would mean that our implementation of zip_view
should support (almost) all of what the standard requires. And since zip_view
is based on the standard tuple, which in C++20 has some limitations for our needs, I am not sure to which extent the compliance with the standard is feasible.
Also there still will be a question whether it should be a specified feature or an extension.
0e35be1
to
5f43b52
Compare
…or (from declare_iterator_category)
…&& _ONEDPL_GCC_VERSION >= 120100
… "1) Default constructor. Value-initializes all elements, if any"
4a6a1f5
to
dce5f5e
Compare
include/oneapi/dpl/pstl/tuple_impl.h
Outdated
oneapi::dpl::__internal::__copy_assignable_holder<T1> holder{}; | ||
tuple<T...> next{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose to add comment why {}
are required since it is not trivial.
template <typename U1, typename... U> | ||
tuple& | ||
operator=(const tuple<U1, U...>& other) const | ||
{ | ||
holder.value = other.holder.value; | ||
next = other.next; | ||
return *this; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense when we assign constant tuple objects of non-constant references:
https://godbolt.org/z/TP8Gzhvxb (Failing with C++20, but works in C++23)
@@ -0,0 +1,151 @@ | |||
//===----------------------------------------------------------------------===// | |||
// | |||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we include Intel Copyright as well?
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these annotations are not required for our test system, I guess it can be removed from all tests
template <typename _R> | ||
concept __simple_view_concept = | ||
std::ranges::view<_R> && std::ranges::range<const _R> && std::same_as<std::ranges::iterator_t<_R>, | ||
std::ranges::iterator_t<const _R>> && std::same_as<std::ranges::sentinel_t<_R>, std::ranges::sentinel_t<const _R>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This concept is unused by this test. Why it is needed?
} | ||
|
||
private: | ||
constexpr explicit iterator(current_type __t): current_(std::move(__t)) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constexpr explicit iterator(current_type __t): current_(std::move(__t)) {} | |
constexpr explicit iterator(current_type __t) : current_(std::move(__t)) {} |
|
||
public: | ||
zip_view() = default; | ||
constexpr explicit zip_view(Views... views) : views_(std::move(views)...) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we apply code uglification everywhere for private APIs and arguments?
using return_tuple_type = reference_type; | ||
return return_tuple_type(std::forward<decltype(__args)>(__args)...); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using return_tuple_type = reference_type; | |
return return_tuple_type(std::forward<decltype(__args)>(__args)...); | |
return reference_type(std::forward<decltype(__args)>(__args)...); |
operator==(const iterator& x, const iterator& y) requires( | ||
std::equality_comparable<std::ranges::iterator_t<__maybe_const<Const, Views>>>&&...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
operator==(const iterator& x, const iterator& y) requires( | |
std::equality_comparable<std::ranges::iterator_t<__maybe_const<Const, Views>>>&&...) | |
operator==(const iterator& x, const iterator& y) | |
requires(std::equality_comparable<std::ranges::iterator_t<__maybe_const<Const, Views>>>&&...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just formatting? or?
operator-(const iterator& x, const iterator& y) requires | ||
(std::sized_sentinel_for<std::ranges::iterator_t<__maybe_const<Const, Views>>, std::ranges::iterator_t<__maybe_const<Const, Views>>> && ...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
operator-(const iterator& x, const iterator& y) requires | |
(std::sized_sentinel_for<std::ranges::iterator_t<__maybe_const<Const, Views>>, std::ranges::iterator_t<__maybe_const<Const, Views>>> && ...) | |
operator-(const iterator& x, const iterator& y) | |
requires(std::sized_sentinel_for<std::ranges::iterator_t<__maybe_const<Const, Views>>, | |
std::ranges::iterator_t<__maybe_const<Const, Views>>> && ...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just formatting? or?
… forward iterators" This reverts commit 6ff5b7a.
3cc0ea8
to
8c17b90
Compare
8c17b90
to
c2156af
Compare
[oneDPL][ranges] + zip_view implementation for C++20. The implementation and test.