std::experi...es::search_n(3)

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

πŸ’… std::experi...es::search_n(3) πŸ’…

Okay bestie, so this one lives in the C++ Standard Library β€” the manual page calls it std::experi...es::search_n(3) (yes the name is literally truncated with dots, that's not me being lazy, that's the actual title, iykyk). Grab a snack, we're looking for runs of identical stuff. πŸ“


✨ NAME ✨

std::experimental::ranges::search_n β€” and that's it, that's the whole name section. It's giving minimal. It says std::experimental::ranges::search_n and then repeats std::experimental::ranges::search_n. Iconic of it tbh.


🌸 SYNOPSIS 🌸

It's Defined in header <experimental/ranges/algorithm> β€” that's the header, don't forget it, she's important. πŸ’–

template< ForwardIterator I, Sentinel<I> S, class T,
          class Pred = ranges::equal_to<>, class Proj = ranges::identity >
    requires IndirectlyComparable<I, const T*, Pred, Proj>
(1) (ranges TS)
I search_n( I first, S last, ranges::difference_type_t<I> count,
            const T& value, Pred pred = Pred{}, Proj proj = Proj{} );

template< ForwardRange R, class T, class Pred = ranges::equal_to<>,
          class Proj = ranges::identity >
    requires IndirectlyComparable<ranges::iterator_t<R>, const T*, Pred, Proj>
(2) (ranges TS)
ranges::safe_iterator_t<R> search_n( R&& r,
            ranges::difference_type_t<ranges::iterator_t<R>> count,
            const T& value, Pred pred = Pred{}, Proj proj = Proj{} );

So overload (1) and overload (2), both tagged (ranges TS). Both are requires IndirectlyComparable<...> so the compiler does a vibe check before it even lets you in. 🫢

  • (1) Searches the range [first, last) for the first sequence of count elements whose projected values are each equal to the given value, checked according to the predicate pred. Basically: find me count matching besties in a row, no cap.
  • (2) Same as (1), but it takes r as the source range β€” like it's using ranges::begin(r) as first and ranges::end(r) as last. Convenience queen. πŸ‘‘

πŸŽ€ PARAMETERS πŸŽ€

  • first, last β€” the range of elements to examine πŸ‘€
  • r β€” the range of elements to examine (the shortcut version, same deal)
  • count β€” the length of the sequence to search for. how many in a row we're hunting, fr fr
  • value β€” the value to search for ✨
  • pred β€” the predicate that compares the projected elements with value
  • proj β€” the projection to apply to the elements

πŸ¦‹ RETURN VALUE πŸ¦‹

An iterator to the beginning of the found sequence in the range [first, last). Literally points at the first one of your little matched squad. 🫢

If no such sequence is found, you get an iterator that compares equal to last. So it's not a "no" like a crash, it's a "no" like points at the end and shrugs. 😭


🌈 COMPLEXITY 🌈

At most last - first applications of the predicate and the projection. Not more, not extra. She's efficient. Slay. πŸ’…


πŸ‘‘ POSSIBLE IMPLEMENTATION πŸ‘‘

Okay this is the fun part, look at how simple she is:

template<ForwardIterator I, Sentinel<I> S, class T,
         class Pred = ranges::equal_to<>, class Proj = ranges::identity>
    requires IndirectlyComparable<I, const T*, Pred, Proj>
I search_n(I first, S last, ranges::difference_type_t<I> count,
           const T& value, Pred pred = Pred{}, Proj proj = Proj{})
{
    for (; first != last; ++first)
    {
        if (!ranges::invoke(pred, ranges::invoke(proj, *first), value))
            continue;

        I candidate = first;
        ranges::difference_type_t<I> cur_count = 0;

        while (true)
        {
            ++cur_count;
            if (cur_count == count)
                // success
                return candidate;

            ++first;
            if (first == last)
                // exhausted the list
                return first;

            if (!ranges::invoke(pred, ranges::invoke(proj, *first), value))
                // too few in a row
                break;
        }
    }
    return first;
}

The way this works: hit a match β†’ remember it as candidate β†’ keep counting β†’ if cur_count == count you win, success, return the candidate. If you run out of range, exhausted the list, return first. If the streak breaks, too few in a row, break out and keep scanning. Main character algorithm energy, honestly. πŸ”₯


⭐ EXAMPLE ⭐

This section is incomplete. Reason: no example

I know. I know. 😭 The example section is empty. It's giving "I'll do it later" and then never doing it. It's fine. We're fine. We have the possible implementation, we can cope. 🧚


πŸ’œ SEE ALSO πŸ’œ

  • search_n β€” searches a range for a number of consecutive copies of an element (function template). yes that's the same name, yes this page is literally about it, the See Also section is a little self-obsessed, we love that for her πŸ’…
  • find_end β€” finds the last sequence of elements in a certain range (function template)
  • find β€” finds the first element satisfying specific criteria
  • find_if β€” (function template)
  • find_if_not β€” (function template)
  • search β€” searches for a range of elements (function template)

πŸ› CATEGORY πŸ›

  • Todo no example

There it is again. The todo. The unfinished business. The "no example" haunting this entire page. πŸ’€


Bestie that's the whole page!! βœ¨πŸ’– Huge thanks to http://cppreference.com for hosting the lore, this copy is from the 2024.06.10 edition, and the header and footer of this manual page said exactly std::experi...es::search_n(3) up top and the same plus that date down below β€” so now you know the whole story. Go find your count matching elements in a row, you've got this. πŸŒˆπŸ«ΆπŸŽ€

πŸ“¦ where this page comes from