Date: Sat, 22 Feb 2025 13:45:01 -0500
Relevant reading:
https://quuxplusone.github.io/blog/2023/10/01/quick-custom-iterator/
The STL is "missing" a lot of custom iterator adaptors:
- emplace_iterator
- emplace_back_iterator
- emplace_front_iterator
- push_iterator
- pop_iterator
But they can all be written in just a few lines by hand (especially, for
output iterators, by using the trick detailed above), so I think it's fine
that they don't exist in the STL.
Here's your `pop_off` example in C++23: https://godbolt.org/z/3dPEqhn47
template<class Q>
struct PopIterator {
using difference_type = int;
using value_type = typename Q::value_type;
explicit PopIterator(Q& q) : q_(&q) {}
PopIterator& operator++() { q_->pop(); return *this; }
PopIterator operator++(int) { auto copy = *this; ++*this; return copy; }
decltype(auto) operator*() const { return q_->top(); }
bool operator==(std::default_sentinel_t) const { return q_->empty(); }
Q *q_;
};
template<class R>
auto pop_off(R&& rg) {
return stdr::subrange(PopIterator(rg), std::default_sentinel);
}
template<stdr::input_range R1, stdr::input_range R2>
bool is_permutation(R1&& r1, R2&& r2) {
return stdr::equal(
pop_off(r1 | stdr::to<std::priority_queue>()),
pop_off(r2 | stdr::to<std::priority_queue>())
);
}
–Arthur
On Sat, Feb 22, 2025 at 1:25 PM Ell via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> This could be occasionally nice to have, especially if it worked with
> other adaptors as well. Some random examples:
>
> Finding the area of the largest rectangle under a histogram [1] can be
> solved with a monotonic stack. Before pushing a new element, the
> discarded elements could be processed as a range:
>
> template <stdr::input_range R>
> auto max_rect_area (R&& r) {
> using idx_t = stdr::range_difference_t<R>;
> using height_t = stdr::range_value_t<R>;
> using area_t = decltype (idx_t () * height_t ());
>
> struct bar {
> idx_t idx;
> height_t height;
> };
>
> std::stack<bar> stk;
> area_t result {};
>
> for (auto [idx, height] : stdv::concat (r, stdv::single (0)) |
> stdv::enumerate)
> {
> std::tie (idx, result) = stdr::fold_left (
> pop_off (stk) | // <-- popping adaptor
> stdv::take_while ([=] (bar b) {
> return b.height >= height;
> }),
>
> std::pair (idx, result),
>
> [=] (auto p, bar b) {
> return std::pair (
> b.idx,
> std::max (p.second, (idx - b.idx) * b.height)
> );
> }
> );
>
> stk.emplace (idx, height);
> }
>
> return result;
> }
>
> Finding minimal paths in a graph using BFS:
>
> std::queue<...> q;
>
> q.push (seed);
>
> for (std::size_t path_length = 0; ! q.empty (); ++path_length) {
> /* all current elements in the queue are path_length away
> * from seed
> */
> for (auto& node : pop_off (q) | stdv::take (q.size ())) {
> // process node, possibly pushing new elements
> }
> }
>
> Using priority_queue as a lazily-sorted range:
>
> template <stdr::input_range R1, stdr::input_range R2>
> bool is_permutation (R1&& r1, R2&& r2) {
> return stdr::equal (
> pop_off (
> stdr::to<std::priority_queue> (std::forward<R1> (r1))
> ),
> pop_off (
> stdr::to<std::priority_queue> (std::forward<R2> (r2))
> )
> );
> }
>
> [1] https://leetcode.com/problems/largest-rectangle-in-histogram/
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
https://quuxplusone.github.io/blog/2023/10/01/quick-custom-iterator/
The STL is "missing" a lot of custom iterator adaptors:
- emplace_iterator
- emplace_back_iterator
- emplace_front_iterator
- push_iterator
- pop_iterator
But they can all be written in just a few lines by hand (especially, for
output iterators, by using the trick detailed above), so I think it's fine
that they don't exist in the STL.
Here's your `pop_off` example in C++23: https://godbolt.org/z/3dPEqhn47
template<class Q>
struct PopIterator {
using difference_type = int;
using value_type = typename Q::value_type;
explicit PopIterator(Q& q) : q_(&q) {}
PopIterator& operator++() { q_->pop(); return *this; }
PopIterator operator++(int) { auto copy = *this; ++*this; return copy; }
decltype(auto) operator*() const { return q_->top(); }
bool operator==(std::default_sentinel_t) const { return q_->empty(); }
Q *q_;
};
template<class R>
auto pop_off(R&& rg) {
return stdr::subrange(PopIterator(rg), std::default_sentinel);
}
template<stdr::input_range R1, stdr::input_range R2>
bool is_permutation(R1&& r1, R2&& r2) {
return stdr::equal(
pop_off(r1 | stdr::to<std::priority_queue>()),
pop_off(r2 | stdr::to<std::priority_queue>())
);
}
–Arthur
On Sat, Feb 22, 2025 at 1:25 PM Ell via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> This could be occasionally nice to have, especially if it worked with
> other adaptors as well. Some random examples:
>
> Finding the area of the largest rectangle under a histogram [1] can be
> solved with a monotonic stack. Before pushing a new element, the
> discarded elements could be processed as a range:
>
> template <stdr::input_range R>
> auto max_rect_area (R&& r) {
> using idx_t = stdr::range_difference_t<R>;
> using height_t = stdr::range_value_t<R>;
> using area_t = decltype (idx_t () * height_t ());
>
> struct bar {
> idx_t idx;
> height_t height;
> };
>
> std::stack<bar> stk;
> area_t result {};
>
> for (auto [idx, height] : stdv::concat (r, stdv::single (0)) |
> stdv::enumerate)
> {
> std::tie (idx, result) = stdr::fold_left (
> pop_off (stk) | // <-- popping adaptor
> stdv::take_while ([=] (bar b) {
> return b.height >= height;
> }),
>
> std::pair (idx, result),
>
> [=] (auto p, bar b) {
> return std::pair (
> b.idx,
> std::max (p.second, (idx - b.idx) * b.height)
> );
> }
> );
>
> stk.emplace (idx, height);
> }
>
> return result;
> }
>
> Finding minimal paths in a graph using BFS:
>
> std::queue<...> q;
>
> q.push (seed);
>
> for (std::size_t path_length = 0; ! q.empty (); ++path_length) {
> /* all current elements in the queue are path_length away
> * from seed
> */
> for (auto& node : pop_off (q) | stdv::take (q.size ())) {
> // process node, possibly pushing new elements
> }
> }
>
> Using priority_queue as a lazily-sorted range:
>
> template <stdr::input_range R1, stdr::input_range R2>
> bool is_permutation (R1&& r1, R2&& r2) {
> return stdr::equal (
> pop_off (
> stdr::to<std::priority_queue> (std::forward<R1> (r1))
> ),
> pop_off (
> stdr::to<std::priority_queue> (std::forward<R2> (r2))
> )
> );
> }
>
> [1] https://leetcode.com/problems/largest-rectangle-in-histogram/
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2025-02-22 18:45:15