Skip to content
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

RFC for zip_view implementation, for oneDPL C++20 #1931

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
09bd199
[oneDPL][rfc][zip_view] + draft
MikeDvorskiy Nov 4, 2024
b56c860
Update README.md
MikeDvorskiy Nov 27, 2024
761ecb7
Update README.md
MikeDvorskiy Nov 29, 2024
7ef15f4
Update README.md
MikeDvorskiy Nov 29, 2024
e792b5b
Update README.md
MikeDvorskiy Nov 29, 2024
786d5c5
Update README.md
MikeDvorskiy Nov 29, 2024
171e5fe
Update README.md
MikeDvorskiy Nov 29, 2024
f9a2e45
[oneDPL][rfc][ranges][zip_view] + Implementation design proposal
MikeDvorskiy Dec 2, 2024
4a701fc
+ spelling fix
MikeDvorskiy Dec 3, 2024
cc3eac4
+ spelling fix
MikeDvorskiy Dec 3, 2024
52acfac
+Implementation proposal
MikeDvorskiy Dec 4, 2024
526a603
Delete rfcs/experimental/zip_view/README.md
MikeDvorskiy Dec 4, 2024
518aee0
Update README.md
MikeDvorskiy Dec 4, 2024
234dbdb
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
c20ef9f
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
aec760b
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
9ab570b
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
300e13c
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
f51297e
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
4cade93
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
7b882fb
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
2e9c98d
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 17, 2024
214dcde
Update rfcs/proposed/zip_view/README.md
MikeDvorskiy Dec 18, 2024
1f7b132
Update README.md
MikeDvorskiy Dec 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions rfcs/proposed/zip_view/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# zip_view Support for the oneDPL Range APIs with C++20

## Introduction
`std::ranges::zip_view` is a powerful utility that enables developers to combine two or more ranges into a single view,
where each element is represented as a tuple containing corresponding elements from each input range.

## Motivations
`std::ranges::zip_view` is a convenient way to combine multiple ranges into a single view, where each element of
the resulting range is a tuple containing one element from each of the input ranges. This can be particularly
useful for iterating over multiple collections in parallel. `std::ranges::zip_view` was introduced in C++23,
but many developers are still using C++20 standard. So, oneDPL introduces `oneapi::dpl::ranges::zip_view`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this feature going to be experimental? If yes, I guess the namespace should be oneapi::dpl::experimental::ranges::zip_view.

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding to experimental namespace here. I don't know... It depends on RFC process. This document is a proposal in the product or to be productized - that's a goal. So, experimental word looks weird.

Talking about the next stage of our doing with zip_view, yes we would like to have it in the experimental namespace first.

Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you expect the feature to be productized fast, similarly to the C++20 range support. Hence, having experimental namespace will impair user experience due to the changes it involves.

Does it make sense to treat it as an extension straight away with "supported" as the next stage? Do you feel confident regarding the current design?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding here was that we were shooting for full product status for the ranges MVP APIs including zip_view after the experience of the existing experimental ranges APIs. We already have an experimental zip_view that has been around for some time now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, indeed, thanks for reminding about oneapi::dpl::experimental::ranges::zip_view. Then, "supported" stage looks better than "experimental" as the next target.

Talking about the next stage of our doing with zip_view, yes we would like to have it in the experimental namespace first.

Could you elaborate why you prefer "experimental" stage?

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, there is an internal utility - oneapi::dpl::__ranges::zip_view in using everywhere in the internal oneDPL implementation with C++17 support.
Also oneapi::dpl::__ranges::zip_view is injected into oneapi::dpl::experimental::ranges namespace.
oneapi::dpl::experimental::ranges::zip_view is used in 4 places in oneDPL impl... and probably in a user'code, because it is a public name.

So, I would propose 1) for _ONEDPL_CPP20_RANGES_PRESENT mode to have the proposed new zip_view in the oneapi::dpl::experimental::ranges namespace and 2) injection of existing oneapi::dpl::__ranges::zip_view into oneapi::dpl::experimental::ranges otherwise (in case of C++17).

1a) the "old" oneapi::dpl::__ranges::zip_view has public "tuple()" method... and it used in the following context:
std::get<0>(__in_rng.tuple()), Actually, it is not correct. Should be an oneDPL internal analog of std::views::elements<0>(__in_rng) IMHO.

@akukanov , @danhoeflinger , @dmitriy-sobolev what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory, we have license to change "experimental" things, as you suggest (in C++20 in this case).

What we need to be careful of is that the existing zip_view has been stable for a long time, and I think used in non-experimental production code internally. I think we need to confirm and be sure that we are not introducing breaking changes into non-experimental code, and that any breaking changes to the experimental zip_view with C++20 enabled are well described and kept to a minimum.

As far as the RFC is concerned, we need to make it clear here the plan for how it will coexist with what already exists (basically what you describe above).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the existing zip_view has been stable for a long time

The existing zip_view doesn't work with C++ standard ranges. That's why we need new one for _ONEDPL_CPP20_RANGES_PRESENT mode.

Copy link
Contributor

@danhoeflinger danhoeflinger Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that makes sense. My reason for stating its stability is not to argue that a new version isn't needed, but merely to say that users may have more of an expectation to treat the existing implementation as a "supported" feature rather than an "experimental" feature, because we have basically treated it as such.
Therefore, changes may take them by surprise. We are not doing anything wrong by changing it, as it is experimental, we just need to be aware that it may affect users.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I would propose 1) for _ONEDPL_CPP20_RANGES_PRESENT mode to have the proposed new zip_view in the oneapi::dpl::experimental::ranges namespace and 2) injection of existing oneapi::dpl::__ranges::zip_view into oneapi::dpl::experimental::ranges otherwise (in case of C++17).

If the experimental algos based on non-standard views are available for C++20, this can still be a breaking change I am afraid.

We can go with e.g. oneapi::dpl::ranges::zip_view_experimental, I guess. It's ugly and does not follow the convention, but the intent is clear.

with the same API and functionality as `std::ranges::zip_view`.
Comment on lines +10 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking more of zip_view, I now wonder if we should add it to the specification or rather should provide it as a library extension.

If the goal is only to close the gap between C++20 and C++23, while the standard C++23 zip_view is well usable with oneDPL, including with device policies - then maybe it is not worth adding our zip_view variation to the specification. Perhaps especially so if it cannot be used as a substitution for the standard zip_view in all scenarios (that means, if developers cannot always use the oneDPL variation and may need to choose between that and the standard one).


### Key Requirements
akukanov marked this conversation as resolved.
Show resolved Hide resolved
`oneapi::dpl::ranges::zip_view` should be:
- compilable with C++20 version (minimum)
dmitriy-sobolev marked this conversation as resolved.
Show resolved Hide resolved
- API-compliant with `std::ranges::zip_view`
- random accessible view; the "underlying" views also should be random accessible
dmitriy-sobolev marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how cppreference describes the category for std::ranges::zip_view:

zip_view always models input_range, and models forward_range, bidirectional_range, random_access_range, or sized_range if all adapted view types model the corresponding concept.

Do we want the same adaptive behavior, or do we want to require all the base ranges to be random access ranges?

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding our intention was to provide zip_view like adaptor (for C++20), which "works (is pipeable)" with C++20 ranges/views and can be passed into oneDPL algorithms, because existing experimental::zip_view "doesn't work (is not pipeable)" with C++20 ranges/views.

As far as https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3179r2.html tells that only random access ranges are accepted for range based oneDPL algorithm, I think we want to support zip_view only for random_access_range - to require all the base ranges to be random access ranges.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so there is no intent to make it adaptable to different range categories and usable more widely. It needs to be clear in the documentation & specification.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we should also think of implications. If our zip_view cannot be used with ranges that are not random access, could it make developers hesitant to use it, possibly impacting oneDPL usage?

- in case of a device usage: a device copyable view if the all "underlying" views are device copyable views

`oneapi::dpl::ranges::zip_view::iterator` should be:
- value-swappable (https://en.cppreference.com/w/cpp/named_req/ValueSwappable)
- implicitly convertible to `oneapi::dpl::zip_iterator`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have in mind some reasonable use cases for this conversion? Because if we do not, maybe we should not add extra complexity and extra risks with the implicit conversion.

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned above, I have in my mind at least one practically-viable example:
A user has some function like void foo(oneapi::dpl::zip_iterator b, oneapi::dpl::zip_iterator e) and has some ranges combined into one zip_view and is going to call foo with zip_view.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to think that functions usually take generic iterators rather than specific ones. And as we know, implicit conversions may affect SFINAE, overload resolution sets, etc.

Maybe it is sufficient for the iterator traits to match, including their value and reference types? That makes sense and seems less risky to me. We can consider conversion (implicit or explicit) later, based on real demand and implementation complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, explicitly conversion is "safer"...
I don't mind to consider such conversion support "on demand".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another compatibility/conversion question is with regard to the C++23 zip_view. If our view cannot always be used in place of the standard one, perhaps we should consider how developers would switch between the two.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the standard zip_view C++23 might be not device copyable f.e.? And how developers can use our view instead of?

Copy link
Contributor

@akukanov akukanov Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I meant if our view is not going to support all requirements/use cases of the standard (e.g. not going to work with bidirectional etc. views), then developers cannot use it all the time. So it makes sense to think if there could be cases to transit from one zip view to another.

- able to be used with the non-range algorithms

### Implementation proposal
- `oneapi::dpl::ranges::zip_view` is designed as a C++ class which represents a range adaptor (see C++ Range Library).
This class encapsulates a tuple-like type to keep a combination of two or more ranges.
- The implementation provides all necessary operators to satisfy 'random accessible view' requirement.
- To ensure device copyability, `oneapi::dpl::__internal::tuple` is proposed as a tuple-like type for underlying elements.
- To provide a value-swappable requirement `oneapi::dpl::__internal::tuple` is proposed as a dereferenced value for
`oneapi::dpl::ranges::zip_view::iterator` due to `std::tuple` not satisfying the value-swappable requirement in C++20.
- Usage of C++ concepts is desirable to write type requirements for types, methods and members of the class.
- C++20 is minimum supported version for the class. It allows using modern C++ features such as concepts and others.

### Test coverage

- `oneapi::dpl::ranges::zip_view` is tested itself, base functionality.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What amount of testing would be necessary to ensure the API compliance with std::ranges::zip_view, stated as a requirement?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think to have at least one call of each method of oneapi::dpl::ranges::zip_view with result checking is quite enough.
As an additional test coverage we may consider to take LLVM tests for std::ranges::zip_view, if it is technically possible by C++23/C++20 reasons.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking about "the API compliance with std::ranges::zip_view". I mean the public methods and types are equivalent at least for underlying random sized ranges: ones are callable and result the same. And also pipeable feature is supported.

- should be tested with at least one oneDPL range based algorithm.
- should be tested with at least one oneDPL iterator based algorithm.
Loading