std::priori...::push_range(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… NAME πŸ’…

std::priority_queue::push_range β€” ok so literally it's std::priority_queue::push_range, that's the whole name bestie, no cap ✨

So this is a page from the C++ Standard Library manuals, section 3, and the thing it's documenting is std::priori...::push_range (yes the title gets truncated, it's giving "my name is too long for the sidebar" 😭). Buckle up, because this one is genuinely iconic.


🌸 Synopsis 🌸

template< container-compatible-range<value_type> R >  (since C++23)
void push_range( R&& rg );

So this bad boy right here? Since C++23, periodt. πŸŽ€

What it does: it inserts a copy of each element of rg into the priority_queue, and it does it "as if by" one of these two paths β€” pick whichever applies:

  • c.append_range(std::forward<R>(rg)) if that is a valid expression β€” i.e. if the underlying container c has an appropriate append_range member function. Slay, it's got the dedicated method.
  • ranges::copy(rg, std::back_inserter(c)) otherwise. The fallback bestie, still does the job. 🫢

Then β€” and this is the important part β€” it restores the heap property as if by ranges::make_heap(c, comp). After the insertion, ranges::is_heap(c, comp) is true. Like, actually true. Verified. βœ…

And one more detail that matters: each iterator in the range rg is dereferenced exactly once. Once! Not twice. Not "eh, maybe a couple times". Once. πŸ’…


πŸ¦‹ Parameters πŸ¦‹

  • rg β€” a container compatible range, that is, an input_range whose elements are convertible to T. So like, it's gotta be a range, and the stuff inside it's gotta be able to become a T. That's the vibe check. ✨

πŸŽ€ Return value πŸŽ€

(none) β€” nothing, nada, zero, zilch. It returns void, she does the work and dips. πŸ™ˆ


πŸ”₯ Complexity πŸ”₯

The complexity of c.append_range plus the complexity of ranges::make_heap(c, comp). So like, add those two together, that's your answer, no shortcuts. 😭


⭐ Notes ⭐

There's a feature-test macro, and here's the deets:

  • __cpp_lib_containers_ranges β€” value 202202L β€” std (C++23) β€” feature: Ranges-aware construction and insertion

That's the one you #ifdef on if you wanna be all fancy and conditional about it. iykyk πŸ’œ


🌈 Example 🌈

Run this code
#include <algorithm>
#include <iostream>
#include <ranges>
#include <queue>

template<typename Adaptor>
requires (std::ranges::input_range<typename Adaptor::container_type>)
void println(auto, const Adaptor& adaptor)
{
    struct Container : Adaptor // gain access to protected Adaptor::Container c;
    {
        auto const& container() const { return this->c; }
    };

    for (auto const& elem : static_cast<const Container&>(adaptor).container())
        std::cout << elem << ' ';
    std::cout << '\n';
}

int main()
{
    std::priority_queue<int> adaptor;
    const auto rg = {1, 3, 2, 4};

#ifdef __cpp_lib_containers_ranges
    adaptor.push_range(rg);
#else
    std::ranges::for_each(rg, [&adaptor](auto e){ adaptor.push(e); });
#endif

    println("{}", adaptor);
}

Output:

4 3 2 1

Not the 1 3 2 4 you put in, bestie β€” it's a priority queue, she reordered, that's literally her whole thing. πŸ’€ The #ifdef fallback is there because if your compiler doesn't have the ranges-aware containers, you just push in a loop. Same energy, more keystrokes. 🧚


πŸ‘‘ See also πŸ‘‘

  • push β€” inserts element and sorts the underlying container (public member function). The O.G. one-element-at-a-time queen. 🌸

ok that's the whole page, you ate that πŸ’…βœ¨

Source / version / date, for the record: this came from http://cppreference.com, dated 2024.06.10, and the page is std::priori...::push_range(3) β€” love that for us, go forth and push_range responsibly, mwah πŸ«ΆπŸŽ€

πŸ“¦ where this page comes from