-
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
Add spec compliant histogram API while supporting legacy extension API #1793
Changes from 5 commits
c549d52
c40b3fe
ba9ece8
a7dab72
d707788
fcfaf59
1cdfc3f
c3f87d3
127f2cb
ce768f5
8e329b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,8 +47,32 @@ __pattern_histogram(_Tag, _ExecutionPolicy&& exec, _RandomAccessIterator1 __firs | |
} // namespace __internal | ||
|
||
template <typename _ExecutionPolicy, typename _RandomAccessIterator1, typename _Size, typename _RandomAccessIterator2, | ||
typename _ValueType> | ||
typename> //final unused template param support extension API in combination with overload below | ||
oneapi::dpl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _RandomAccessIterator2> | ||
histogram(_ExecutionPolicy&& exec, _RandomAccessIterator1 first, _RandomAccessIterator1 last, _Size num_bins, | ||
typename std::iterator_traits<_RandomAccessIterator1>::value_type first_bin_min_val, | ||
typename std::iterator_traits<_RandomAccessIterator1>::value_type last_bin_max_val, | ||
_RandomAccessIterator2 histogram_first) | ||
{ | ||
using _BoundaryType = typename std::iterator_traits<_RandomAccessIterator1>::value_type; | ||
const auto __dispatch_tag = oneapi::dpl::__internal::__select_backend(exec, first, histogram_first); | ||
|
||
oneapi::dpl::__internal::__pattern_histogram( | ||
__dispatch_tag, std::forward<_ExecutionPolicy>(exec), first, last, num_bins, | ||
oneapi::dpl::__internal::__evenly_divided_binhash<_BoundaryType>(first_bin_min_val, last_bin_max_val, num_bins), | ||
histogram_first); | ||
return histogram_first + num_bins; | ||
} | ||
|
||
// This overload is provided to support an extension to the oneDPL specification to support the original implementation | ||
// of the histogram API, where the boundary type _ValueType could differ from the value type of the input iterator, | ||
// and required `<`, `<=`, `+`, `-`, and `/` to be defined between _ValueType and | ||
// std::iterator_traits<_RandomAccessIterator1>::value_type rather than enforcing they were the same type or convertible | ||
template <typename _ExecutionPolicy, typename _RandomAccessIterator1, typename _Size, typename _RandomAccessIterator2, | ||
typename _ValueType> | ||
std::enable_if_t<oneapi::dpl::execution::is_execution_policy_v<std::decay_t<_ExecutionPolicy>> && | ||
!std::is_same_v<_ValueType, typename std::iterator_traits<_RandomAccessIterator1>::value_type>, | ||
_RandomAccessIterator2> | ||
histogram(_ExecutionPolicy&& exec, _RandomAccessIterator1 first, _RandomAccessIterator1 last, _Size num_bins, | ||
_ValueType first_bin_min_val, _ValueType last_bin_max_val, _RandomAccessIterator2 histogram_first) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if keeping the old variant of the function available sort of defeats the purpose of adding the new one, as Dan wrote in a comment to the specification PR:
If this overload is kept under the condition of type not being the same as the iterator value type, it will be selected even for the cases where we would want to have the conversion done only once. If the condition is changed to that of type not being convertible, will the code even work for such types? Or should the condition be for types that are not implicitly convertible to the desired one, while still explicitly convertible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need to experiment here a little to see if there is a better check. I think if we check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically, I believe this works with However, the unused and defaulted template parameter feels a little more hacky with this version. With the I have an improved version in a sandbox godbolt which adds a (sigh) 4th overload, but manages to remove the hacky unused and defaulted template parameter from the spec compliant signature. This version breaks up the extension overloads into two signatures:
I'll get an commit in to update this PR with what it would look like tomorrow, its better, but I think I still prefer 1a or 1b. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the code to implement the improved logic for supporting the extension API cases, and added tests to check these overloads specifically. |
||
{ | ||
|
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 do not see why this extra template parameter is needed. As far as I know, it is fine to have function template overloads with different numbers of template parameters.
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 combination with the other overload, this unused defaulted template parameters covers the case where a user specified all template parameters explicitly, and the specified type matches the input iterator value type.
histogram<Policy, int*, std::size_t, uint32_t*, int>(policy, first, last, num_bins, bin_min, bin_max, histogram_first);
The other overload would exclude it because of the matching type.
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 C++20, the standard has a clause in [algorithms.requirements] similar to this (taken from the current draft):
I believe this was added due to range algorithms, which are usually implemented in a way that they cannot be called with explicit template arguments. The restriction however, as I read it, is not limited to range algorithms.
Since we are adding parallel range algorithms both to the library and the spec as well, we will need a similar clause, and maybe it makes sense to apply to all algorithms.
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.
Very interesting, I wasn't aware of that.