-
Notifications
You must be signed in to change notification settings - Fork 628
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
[REQUEST] Provide C++20 range API for iteration #1771
Comments
Unfortunately openvdb is stuck with C++17 (for now) because it is tied to the vfx platform Cheers,KenOn Feb 28, 2024, at 1:53 PM, Ben FrantzDale ***@***.***> wrote:
Is your feature request related to a problem? Please describe.
The current OpenVDB iterator API is non-standard and uses testing the truthiness of an iterator to see if it reaches the end of the range. This means that standard algorithms don't work with OpenVDB iterators.
In C++20's ranges library, they use sentinels to expend that traditional definition of iterators to cover things just like this. OpenVDB would just need to provide a sentinel type like
//! C++20-style end sentinel for an OpenVDB iterator, which is falsey at the end of its range.
template <typename VdbIter>
struct EndSentinel {
[[nodiscard]] friend constexpr bool operator==(EndSentinel, const VdbIter& it) { return !static_cast<bool>(it); }
};
then we could use std::ranges::subrange to create a std::rangs-compatible view of things like node.beginValueOn(). That would let us do for (auto& v : node.valuesOn()) { or std::ranges::count_if(node.valuesAll(), isInteresting).
Describe the solution you'd like
Provide an end-sentinel that tests the iterator for falsiness.
Provide a function to turn an OpenVDB iterator into a std::ranges::subrange from the iterator to the end of range.
Optionally: Provide an adaptor that views a range as its iterators rather than values, so we can do things like
auto bboxes = std::ranges::to<std::vector>(
viewOfIterators(node.valuesAll())
| std::views::transform([](const auto& it) { return it.getBoundingBox(); })
);
Possibly it makes more sense for 3 to be the default behavior, so the iterators iterate over "values" that have a .getBoundingBox() and .getValue() member function.
Describe alternatives you've considered
I've implemented this as free functions in my codebase and found it much easier to work with: Places we were doing raw loops could easily become algorithms, like
for (auto it = node.beginValueOn(); it; ++it) {
if (pred(it)) {
return true;
}
}
return false;
became
return std::ranges::any_of(viewOfIterators(viewValueOn(node)), pred);
and with this suggestion, it could even be
return std::ranges::any_of(node.valuesOn(), pred);
Additional context
The iterator–sentinel pair notion isn't supported by the classic STL algorithms, so this is most useful with C++20, which is the same version that provides std::ranges::subrange.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
This isn't strictly true. We can support C++20 primitives as long as they are ifdef'ed. It will however complicate our CI, though we do already have some basic C++20 CI. I don't see why we couldn't support this suggestion. |
For what it’s worth, a simple approximation of |
The biggest question in my mind is if we move toward a more-standard ranges-like world, would it make sense to iterate over values or over proxy objects that provide the "extra" stuff that OpenVDB iterators provide, or iterate over a range of iterators (which is a little weird feeling, although it works and in some ways is clearer (less magical) than iterating over proxy objects). |
Is your feature request related to a problem? Please describe.
The current OpenVDB iterator API is non-standard and uses testing the truthiness of an iterator to see if it reaches the end of the range. This means that standard algorithms don't work with OpenVDB iterators.
In C++20's ranges library, they use sentinels to expend that traditional definition of iterators to cover things just like this. OpenVDB would just need to provide a sentinel type like
then we could use
std::ranges::subrange
to create astd::rangs
-compatible view of things likenode.beginValueOn()
. That would let us dofor (auto& v : node.valuesOn()) {
orstd::ranges::count_if(node.valuesAll(), isInteresting)
.Describe the solution you'd like
std::ranges::subrange
from the iterator to the end of range.Possibly it makes more sense for 3 to be the default behavior, so the iterators iterate over "values" that have a
.getBoundingBox()
and.getValue()
member function.Describe alternatives you've considered
I've implemented this as free functions in my codebase and found it much easier to work with: Places we were doing raw loops could easily become algorithms, like
became
return std::ranges::any_of(viewOfIterators(viewValueOn(node)), pred);
and with this suggestion, it could even be
return std::ranges::any_of(node.valuesOn(), pred);
Additional context
The iterator–sentinel pair notion isn't supported by the classic STL algorithms, so this is most useful with C++20, which is the same version that provides
std::ranges::subrange
.The text was updated successfully, but these errors were encountered: