std::ranges::search_n(3)
π std::ranges::search_n β C++ Standard Library vibes
okay bestie, welcome to the std::ranges::search_n(3) page, aka the C++ Standard Library's certified "find me a run of N identical things" queen π she's giving haystack-needle energy and honestly? iconic.
β¨ NAME β¨
std::ranges::search_n β literally just std::ranges::search_n, no notes π
β¨ Synopsis β¨
Defined in header <algorithm> π
Call signature
bestie there are FOUR of these bad boys and they're all doing the same job, just with different template drip. read carefully ok π
template< std::forward_iterator I, std::sentinel_for<I> S,
class T,
class Pred = ranges::equal_to, class Proj = std::identity >
requires std::indirectly_comparable<I, const T*, Pred, Proj>
constexpr ranges::subrange<I>
search_n( I first, S last, std::iter_difference_t<I> count,
const T& value, Pred pred = {}, Proj proj = {} );
(1) β since C++20, until C++26
template< std::forward_iterator I, std::sentinel_for<I> S,
class Pred = ranges::equal_to, class Proj = std::identity,
class T = std::projected_value_t<I, Proj> >
requires std::indirectly_comparable<I, const T*, Pred, Proj>
constexpr ranges::subrange<I>
search_n( I first, S last, std::iter_difference_t<I> count,
const T& value, Pred pred = {}, Proj proj = {} );
(1) β since C++26
template< ranges::forward_range R, class T,
class Pred = ranges::equal_to, class Proj = std::identity >
requires std::indirectly_comparable
<ranges::iterator_t<R>, const T*, Pred, Proj>
constexpr ranges::borrowed_subrange_t<R>
search_n( R&& r, ranges::range_difference_t<R> count,
const T& value, Pred pred = {}, Proj proj = {} );
(2) β since C++20, until C++26
template< ranges::forward_range R,
class Pred = ranges::equal_to, class Proj = std::identity,
class T = std::projected_value_t<ranges::iterator_t<R>, Proj> >
requires std::indirectly_comparable
<ranges::iterator_t<R>, const T*, Pred, Proj>
constexpr ranges::borrowed_subrange_t<R>
search_n( R&& r, ranges::range_difference_t<R> count,
const T& value, Pred pred = {}, Proj proj = {} );
(2) β since C++26
1) so basically it searches the range [first, last) for the first sequence of count elements whose projected values are each equal to the given value, according to the binary predicate pred. β¨
2) same as (1) but it uses r as the source range, as if using ranges::begin(r) as first and ranges::end(r) as last. π«
π¦ the niebloid moment π¦
The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
In practice, they may be implemented as function objects, or with special compiler extensions. no cap, that's just how it is π€·ββοΈ
β¨ Parameters β¨
first,lastβ the range of elements to examine (aka haystack π΄)rβ the range of elements to examine (aka haystack, again π΄)countβ the length of the sequence to search forvalueβ the value to search for (aka needle πͺ‘)predβ the binary predicate that compares the projected elements withvalueprojβ the projection to apply to the elements of the range to examine
β¨ Return value β¨
1) returns a std::ranges::subrange object that contains a pair of iterators in the range [first, last) that designate the found subsequence. π―
If no such subsequence is found, it returns std::ranges::subrange{last, last}. π
If count <= 0, it returns std::ranges::subrange{first, first}. π«Ά
2) same as (1) but the return type is ranges::borrowed_subrange_t<R>.
β¨ Complexity β¨
Linear: at most ranges::distance(first, last) applications of the predicate and the projection. honestly not bad, slay π
β¨ Notes β¨
An implementation can improve efficiency of the search in average if the iterators model std::random_access_iterator. π
feature-test macro table but make it cute
__cpp_lib_algorithm_default_value_typeβ value202403β std(C++26)β feature: List-initialization for algorithms
β¨ Possible implementation β¨
like, here's literally how someone could cook this up π
struct search_n_fn
{
template<std::forward_iterator I, std::sentinel_for<I> S,
class Pred = ranges::equal_to, class Proj = std::identity,
class T = std::projected_value_t<I, Proj>>
requires std::indirectly_comparable<I, const T*, Pred, Proj>
constexpr ranges::subrange<I>
operator()(I first, S last, std::iter_difference_t<I> count,
const T& value, Pred pred = {}, Proj proj = {}) const
{
if (count <= 0)
return {first, first};
for (; first != last; ++first)
if (std::invoke(pred, std::invoke(proj, *first), value))
{
I start = first;
std::iter_difference_t<I> n{1};
for (;;)
{
if (n++ == count)
return {start, std::next(first)}; // found
if (++first == last)
return {first, first}; // not found
if (!std::invoke(pred, std::invoke(proj, *first), value))
break; // not equ to value
}
}
return {first, first};
}
template<ranges::forward_range R,
class Pred = ranges::equal_to, class Proj = std::identity,
class T = std::projected_value_t<ranges::iterator_t<R>, Proj>>
requires std::indirectly_comparable<ranges::iterator_t<R>, const T*, Pred, Proj>
constexpr ranges::borrowed_subrange_t<R>
operator()(R&& r, ranges::range_difference_t<R> count,
const T& value, Pred pred = {}, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r),
std::move(count), value,
std::move(pred), std::move(proj));
}
};
inline constexpr search_n_fn search_n {};
β¨ Example β¨
// Run this code β go off bestie πββοΈπ¨
#include <algorithm>
#include <cassert>
#include <complex>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
namespace ranges = std::ranges;
static constexpr auto nums = {1, 2, 2, 3, 4, 1, 2, 2, 2, 1};
constexpr int count{3};
constexpr int value{2};
typedef int count_t, value_t;
constexpr auto result1 = ranges::search_n
(
nums.begin(), nums.end(), count, value
);
static_assert // found
(
result1.size() == count &&
std::distance(nums.begin(), result1.begin()) == 6 &&
std::distance(nums.begin(), result1.end()) == 9
);
constexpr auto result2 = ranges::search_n(nums, count, value);
static_assert // found
(
result2.size() == count &&
std::distance(nums.begin(), result2.begin()) == 6 &&
std::distance(nums.begin(), result2.end()) == 9
);
constexpr auto result3 = ranges::search_n(nums, count, value_t{5});
static_assert // not found
(
result3.size() == 0 &&
result3.begin() == result3.end() &&
result3.end() == nums.end()
);
constexpr auto result4 = ranges::search_n(nums, count_t{0}, value_t{1});
static_assert // not found
(
result4.size() == 0 &&
result4.begin() == result4.end() &&
result4.end() == nums.begin()
);
constexpr char symbol{'B'};
auto to_ascii = [](const int z) -> char { return 'A' + z - 1; };
auto is_equ = [](const char x, const char y) { return x == y; };
std::cout << "Find a sub-sequence " << std::string(count, symbol) << " in the ";
std::ranges::transform(nums, std::ostream_iterator<char>(std::cout, ""), to_ascii);
std::cout << '\n';
auto result5 = ranges::search_n(nums, count, symbol, is_equ, to_ascii);
if (not result5.empty())
std::cout << "Found at position "
<< ranges::distance(nums.begin(), result5.begin()) << '\n';
std::vector<std::complex<double>> nums2{{4, 2}, {4, 2}, {1, 3}};
#ifdef __cpp_lib_algorithm_default_value_type
auto it = ranges::search_n(nums2, 2, {4, 2});
#else
auto it = ranges::search_n(nums2, 2, std::complex<double>{4, 2});
#endif
assert(it.size() == 2);
}
Output
Find a sub-sequence BBB in the ABBCDABBBA
Found at position 6
β¨ See also β¨
ranges::adjacent_find(C++20) (niebloid) β finds the first two adjacent items that are equal (or satisfy a given predicate)ranges::find,ranges::find_if,ranges::find_if_not(C++20) (niebloid) β finds the first element satisfying specific criteriaranges::find_end(C++20) (niebloid) β finds the last sequence of elements in a certain rangeranges::find_first_of(C++20) (niebloid) β searches for any one of a set of elementsranges::includes(C++20) (niebloid) β returns true if one sequence is a subsequence of anotherranges::mismatch(C++20) (niebloid) β finds the first position where two ranges differranges::search(C++20) (niebloid) β searches for a range of elementssearch_n(function template) β searches a range for a number of consecutive copies of an element
π and that's the whole page bestie, you ate that. go find your subsequences. π β¨
sourced from http://cppreference.com and dated 2024.06.10 β this has been your std::ranges::search_n(3) moment, mwah π«Άπ
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms