std::ranges::search_n
Defined in header <algorithm>
|
||
Call signature |
||
template< std::forward_iterator I, std::sentinel_for<I> S, class T, class Pred = ranges::equal_to, class Proj = std::identity > |
(1) | (since C++20) |
template< ranges::forward_range R, class T, class Pred = ranges::equal_to, class Proj = std::identity > |
(2) | (since C++20) |
[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
.r
as the source range, as if using ranges::begin(r) as first
and ranges::end(r) as last
.The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists may not be specified when calling any of them.
- None of them is visible to argument-dependent lookup.
- When one of them is found by normal unqualified lookup for the name to the left of the function-call operator, it inhibits argument-dependent lookup.
In practice, they may be implemented as function objects, or with special compiler extensions.
Parameters
first, last | - | the range of elements to examine (aka haystack) |
r | - | the range of elements to examine (aka haystack) |
count | - | the length of the sequence to search for |
value | - | the value to search for (aka needle) |
pred | - | the binary predicate that compares the projected elements with value
|
proj | - | the projection to apply to the elements of the range to examine |
Return value
[first, last)
that designate the found subsequence.
If no such subsequence is found, returns std::ranges::subrange{last, last}.
If count <= 0, returns std::ranges::subrange{first, first}.Complexity
Linear: at most ranges::distance(first, last) applications of the predicate and the projection.
Notes
An implementation can improve efficiency of the search in average if the iterators model std::random_access_iterator.
Possible implementation
struct search_n_fn { 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> 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 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> 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
#include <algorithm> #include <iomanip> #include <iostream> #include <string> int main() { static constexpr auto nums = {1, 2, 2, 3, 4, 1, 2, 2, 2, 1}; constexpr int count{ 3 }; constexpr int value{ 2 }; constexpr auto result1 = std::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 = std::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 = std::ranges::search_n(nums, count, /* value */ 5); static_assert( // not found result3.size() == 0 && result3.begin() == result3.end() && result3.end() == nums.end() ); constexpr auto result4 = std::ranges::search_n(nums, /* count */ 0, /* value */ 1); static_assert( // not found result4.size() == 0 && result4.begin() == result4.end() && result4.end() == nums.begin() ); constexpr char symbol{'B'}; std::cout << std::boolalpha << "Find a sub-sequence: " << std::quoted(std::string(count, symbol)) << '\n'; auto result5 = std::ranges::search_n(nums, count, symbol, [](const char x, const char y) { // binary predicate const bool o{ x == y }; std::cout << "bin_op(" << x << ", " << y << ") == " << o << "\n"; return o; }, [](const int z) { return 'A' + z - 1; } // projects nums -> ASCII ); std::cout << "Found: " << !result5.empty() << '\n'; }
Output:
Find a sub-sequence: "BBB" bin_op(A, B) == false bin_op(B, B) == true bin_op(B, B) == true bin_op(C, B) == false bin_op(D, B) == false bin_op(A, B) == false bin_op(B, B) == true bin_op(B, B) == true bin_op(B, B) == true Found: true
See also
(C++20) |
finds the first two adjacent items that are equal (or satisfy a given predicate) (niebloid) |
(C++20)(C++20)(C++20) |
finds the first element satisfying specific criteria (niebloid) |
(C++20) |
finds the last sequence of elements in a certain range (niebloid) |
(C++20) |
searches for any one of a set of elements (niebloid) |
(C++20) |
returns true if one sequence is a subsequence of another (niebloid) |
(C++20) |
finds the first position where two ranges differ (niebloid) |
(C++20) |
searches for a range of elements (niebloid) |
searches a range for a number of consecutive copies of an element (function template) |