Skip to content

Incorrect implementation of struct __equal_fn::operator() if one of ranges is not sized_range #2421

@SergeyKopienko

Description

@SergeyKopienko

We have the next code here

:

struct __equal_fn
{
    template<typename _ExecutionPolicy, std::ranges::random_access_range _R1, std::ranges::random_access_range _R2,
             typename _Pred = std::ranges::equal_to, typename _Proj1 = std::identity, typename _Proj2 = std::identity>
    requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<_ExecutionPolicy>>
           && (std::ranges::sized_range<_R1> || std::ranges::sized_range<_R2>)
           && std::indirectly_comparable<std::ranges::iterator_t<_R1>, std::ranges::iterator_t<_R2>, _Pred, _Proj1,
           _Proj2>
    bool
    operator()(_ExecutionPolicy&& __exec, _R1&& __r1, _R2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {},
               _Proj2 __proj2 = {}) const
    {
        if constexpr(!std::ranges::sized_range<_R1> || !std::ranges::sized_range<_R2>)
            return false;
        else
        {
            const auto __dispatch_tag = oneapi::dpl::__ranges::__select_backend(__exec);
            return oneapi::dpl::__internal::__ranges::__pattern_equal(__dispatch_tag,
                std::forward<_ExecutionPolicy>(__exec), std::forward<_R1>(__r1), std::forward<_R2>(__r2), __pred,
                __proj1, __proj2);
        }
    }
}; //__equal_fn

This code should correspond the specification at https://github.com/uxlfoundation/oneAPI-spec/blob/main/source/elements/oneDPL/source/parallel_api/parallel_range_api.rst :

_The following differences to the standard serial C++ range algorithms apply:

List initialization of value parameters is enabled, as in the working draft of the next C++ standard edition (C++26).
Parallel range algorithms cannot be used in constant expressions.
The oneDPL execution policy parameter is added.
Output data sequences are defined as ranges, not iterators.
Both input and output ranges must support random access.
As a rule, both input and output ranges must be sized.
Exceptions are binary transform, equal, and mismatch, where at least one of the input ranges must be sized, and if a range is not sized it is supposed to be infinite. [Note: An example of an infinite range is std::views::repeat with no bound. -- end note]_

But looking at condition

if constexpr(!std::ranges::sized_range<_R1> || !std::ranges::sized_range<_R2>)

I believe it's not correct condition.
Justification: the definition of what is std::ranges::sized_range : "specifies that a range knows its size in constant time"

So this mean that we able to check equality of two ranges ever in the case if one of them is not sized.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions