-
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
Conversation
Signed-off-by: Dan Hoeflinger <[email protected]>
Signed-off-by: Dan Hoeflinger <[email protected]>
Signed-off-by: Dan Hoeflinger <[email protected]>
Signed-off-by: Dan Hoeflinger <[email protected]>
Signed-off-by: Dan Hoeflinger <[email protected]>
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.
LGTM.
template <typename _ExecutionPolicy, typename _RandomAccessIterator1, typename _Size, typename _RandomAccessIterator2, | ||
typename _ValueType> | ||
typename> //final unused template param support extension API in combination with overload below |
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):
The well-formedness and behavior of a call to an algorithm with an explicitly-specified template argument list is unspecified, except where explicitly stated otherwise.
[Note 3: Consequently, an implementation can declare an algorithm with different template parameters than those presented. — end note]
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.
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 comment
The 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:
I think it is better for force users to provide bounds which are convertible to the value_type of the input sequence, and do the conversion once when accepting the arguments rather than each time in the comparison operator.
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 comment
The 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 !std::is_convertible
instead, I think it should still work.
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.
Technically, I believe this works with !std::is_convertible_v
in place of !istd::is_same_v
in that all the cases which build and run before still build and run in the new version as well.
However, the unused and defaulted template parameter feels a little more hacky with this version. With the !std::is_same_v
version, we know that the only time the spec compliant signature is picked, the types are the same, so doing this conversion is a no-op. Alternately, with !std::is_convertible_v
, if someone explicitly lists out their parameter list, including a _ValueType
which is convertible but not the same as the input iterator value type to match the old signature, we would still pick the new spec compliant overload and do the conversion.
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:
-
type not convertible to input iterator value type
This is basically what we have here, but checking!std::is_convertible_v
-
Explicit template list
This makes the 4th template argument non-deducable, but has 5th and 6th template arguments to represent the types of the two boundary limit parameters
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 comment
The 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.
After discussion with @rarutyun and @MikeDvorskiy, I think we may have better options here (specification / implementation). I will provide links for the alternatives tonight or tomorrow. I sent and email with some details which you can look at in the mean time. |
Signed-off-by: Dan Hoeflinger <[email protected]>
Signed-off-by: Dan Hoeflinger <[email protected]>
…implementation Signed-off-by: Dan Hoeflinger <[email protected]>
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 claim the old APIs deprecated, so that their use causes warnings and encourages the change to the supported overload?
// This overload is provided to support an extension to the oneDPL specification to support the original implementation | ||
// of the histogram API, where if users explicitly-specify all template arguments, their arguments for bin boundary min | ||
// and max are convertible to the specified _ValueType, and the _ValueType is convertible to the value type of the | ||
// input iterator. |
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 to mention that _ValueType
is not deducible and so this overload can only be chosen if it's explicitly specified.
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, I should mention that specifically, I'll fix the comment.
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.
Fixed.
I'm OK with that. Does that have any implication on the oneDPL version numbering, etc.? |
The version is not impacted, as the API is still there. But it makes sense to check what needs to be done to claim something deprecated. Tagging @timmiesmith. |
Signed-off-by: Dan Hoeflinger <[email protected]>
Signed-off-by: Dan Hoeflinger <[email protected]>
Deprecations have to be announced 1 year before the API is removed, and it's encouraged to do it at the major oneAPI release. We need to add the warning macros to the APIs so the user does see the warnings at comepile time now, and then next year we can remove the APIs. 5c4840f is an example of the notice required. |
OK, I can add deprecation warnings here to the extension APIs. Thanks @timmiesmith. |
Signed-off-by: Dan Hoeflinger <[email protected]>
Deprecations have been added. Its added a clang-format suggestion which I very much disagree with. |
We determined that we want to go with #1800 instead. Converting to draft and removing from milestone. |
closing this in favor of #1800. |
This PR adjust the API overloads for histogram to create an API which complies to the current PR for the specification, while continuing to support the existing API as an extension.
It removes an unnecessary and unused default parameter for
ValueType
which was incorrectly added in the original PR. The new spec compliant API implements what was the intended signature originally motivated from this discussion.This change in overload / signature should intercept the normal usages of histogram which have matching types for the bound limits with the value type of the input iterators, and use the spec compliant signature.
For those using histogram that provide bound limits which do not match the value type of the input iterator, the legacy overload will still support this usage.
We should not stop supporting any existing working cases with this change, but we will add some additional supported invocations where the type of the boundaries do not match each other. If they are both implicitly convertible to the value type of the input iterator, they will be converted, and it should work (possibly with warnings).
We also remove the default for
ValueType
here for the legacy API without harm, as it can never be used in practice.Example in godbolt to play with: Godbolt example
Updated godbolt: https://godbolt.org/z/Pev1Ps8nY
(Version 2 from email)