This proposal introduces versions of the overload of the algorithm, which takes a searcher object instead of an iterator pair and (optionally) a predicate.
It was originally introduced for more performant specialized searching.
As customary in Ranges algorithms, this proposal also proposes Range-ified versions of the existing standard searchers, along with a concept for better capturing the semantic requirements of standard searchers.
1. Revision History
1.1. R0 (2026-05 pre-Brno mailing)
-
Initial revision.
2. Background
is a very old standard algorithm, dating back to the inclusion of the original STL in 1994. The most basic shape of the algorithm takes two pairs of iterators representing haystack and needle, and returns the beginning position of the first occurrence of the needle sequence in the haystack sequence (or returns the end iterator of haystack if no occurrences are found). Optionally, the algorithm also takes a binary predicate to overwrite the equality comparison operation. The algorithm also has a variant that searches for copies of the same element instead of a provided needle range.
Several improvements and extensions have been applied to after its inclusion in the C++ standard. In the C++17 cycle, the introduction of parallel algorithms brings overloads to ; in the C++20 cycle alone, the merging of Ranges TS ([P0896R4]) into the standard brings with it the variant, which enables iterator-sentinel and ranges argument passing style instead of the traditional iterator pair style to the algorithm. Meanwhile, [P0202R3] also added the specifier to both variants of the algorithm, finally leading to its present form.
However, all of these modifications apply uniformly to most algorithms in the header; this proposal instead focuses on one specific enhancement that only applies to : the overload of the algorithm introduced by [N3905] (originally to Library Fundamentals TS v1, later merged into C++17). The original motivation for the inclusion of searchers was to allow more performant specialized search algorithms that precompute various statistics from the pattern to increase performance, as ’s normal overloads in general can only achieve a time complexity of using naive methods (where and are the length of the haystack and needle sequences, respectively). For instance, the standard implements the Boyer-Moore String Search Algorithm, which can achieve a worst-case running time of instead (requires some variation on the original 1977 version of the algorithm). In practice, using standard searchers often introduces significant speedup compared to normal invocations, at the cost of a larger memory footprint and longer initialization times on first invocation due to the need for precomputations.
Unfortunately, perhaps due to its late entrance to the standard, the overload is never included in either Boost.Ranges or range-v3, and as a result, the current Ranges library never included a overload with arguments. Given that nearly every other overload in the header has a corresponding version, and works ([P1813R0], [P3732R2]) have been underway to Range-ify the remaining algorithms too, it seems increasingly likely that the omission of this overload is an unintentional mistake.
This proposal thus proposes fixing this omission by introducing an overload for that accepts a algorithm instead of a second range. Furthermore, the C++23 algorithm introduced by [P2302R4] was specified as a convenience wrapper for , thus a overload is introduced for that algorithm too for API consistency.
3. Motivation
Current inconsistency in the API forces users to exit the Ranges world to use searchers and resort to using traditional STL algorithms instead, which is undesirable.
A before/after comparison of the feature is shown below:
// In C++26 std :: string haystack = "a quick brown fox jumps over the lazy dog" ; std :: string needle = "jump" ; std :: search ( haystack . begin (), haystack . end (), needle . begin (), needle . end ()); // OK std :: ranges :: search ( haystack , needle ); // OK, clear improvements to std::search std :: search ( haystack . begin (), haystack . end (), needle . begin (), needle . end (), []( auto a , auto b ) { return tolower ( a ) == b ; }); // OK std :: ranges :: search ( haystack , needle , []( auto a , auto b ) { return tolower ( a ) == b ; }); // OK std :: ranges :: search ( haystack , needle , {}, []( auto a ) { return tolower ( a ); }); // OK, better std :: search ( std :: execution :: par_unseq , haystack . begin (), haystack . end (), needle . begin (), needle . end ()); // OK std :: ranges :: search ( std :: execution :: par_unseq , haystack , needle ); // OK since C++26 std :: boyer_moore_searcher searcher ( needle . begin (), needle . end ()); std :: search ( haystack . begin (), haystack . end (), searcher ); // OK std :: ranges :: search ( haystack , needle , searcher ); // Error! // After this proposal: std :: ranges :: boyer_moore_searcher searcher ( needle ); std :: ranges :: search ( haystack , needle , searcher ); // Proposed OK
Since most Ranges algorithms use concepts to constrain their arguments instead of using template parameter names as an implicit named requirement, this proposal also follows this custom and introduces a concept for searchers that constraints their API, instead of relying on named requirements.
4. Design
4.1. What Is Being Proposed?
-
The following additional overloads for
andstd :: ranges :: search :std :: ranges :: contains_subrange
template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr auto ranges :: search ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr auto ranges :: search ( R && r , const Searcher & searcher , Proj proj = {}); template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr bool ranges :: contains_subrange ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr bool ranges :: contains_subrange ( R && r , const Searcher & searcher , Proj proj = {});
-
Concept
that captures the standard searcher requirementsstd :: searchable -
,std :: ranges :: default_searcher ,std :: ranges :: boyer_moore_searcher std :: ranges :: boyer_moore_horspool_searcher
4.2. Range-Based Searchers
The simplest version of a standard searcher is realized in , which acts as a thin wrapper around to make it follow the searcher API. The API for looks like this:
template < class ForwardIterator1 , class BinaryPredicate = equal_to <>> class default_searcher { public : constexpr default_searcher ( ForwardIterator1 pat_first , ForwardIterator1 pat_last , BinaryPredicate pred = BinaryPredicate ()); template < class ForwardIterator2 > constexpr pair < ForwardIterator2 , ForwardIterator2 > operator ()( ForwardIterator2 first , ForwardIterator2 last ) const ; };
There are several peculiarities in this API that make it unsuitable for the Ranges library, thus prompting this proposal to propose new versions of the standard searchers, similarly to the relation between and . For instance, all standard searchers' returns a pair of iterators after [P0253R1] identified that the end position of the needle inside the haystack is frequently useful for algorithms that are based on searchers. The Ranges library introduced directly for this purpose, and thus, that should be used as the return type instead.
The proposed API for looks like this:
template < forward_range R , copy_constructible Pred = ranges :: equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity > class ranges :: default_searcher { public : constexpr default_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {}); template < typename R2 > requires std :: same_as < std :: remove_reference_t < R2 > , R > constexpr explicit default_searcher ( R2 && r ); template < typename R2 > requires std :: same_as < std :: remove_reference_t < R2 > , R > constexpr default_searcher ( R2 && r , Pred pred , Proj proj = {}); template < forward_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > constexpr subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const ; template < forward_range R2 , class Proj2 = identity > requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > constexpr borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const ; }; template < std :: ranges :: forward_range R , std :: copy_constructible Pred = std :: ranges :: equal_to , std :: indirectly_regular_unary_invocable < std :: ranges :: iterator_t < R >> Proj = std :: identity > default_searcher ( R && , Pred = {}, Proj = {}) -> default_searcher < std :: remove_reference_t < R > , Pred , Proj > ;
Essentially, the API for is a Range-ified version of , with the intention that (which calls ) is always equivalent to . It is for this reason that the concepts on have its arguments flipped.
The API for adds a type argument as the last template argument (that defaults to ), and adds a argument to the constructor. Apart from these changes, their API is identical to the default searchers (except requiring random-access iterators and ranges instead of forward ones). The argument is changed from the second argument to the last because of its default argument dependency on the projection. It is expected that most users will utilize CTAD to construct these searchers (i.e. ), so the positions of template argument are not that important anyways.
One thing to be noted here is that the proposed searchers have a lifetime dependency on the underlying ranges; the standard searchers will store the iterators from the provided range, and thus is only valid for use while the provided range is alive (or if it is a borrowed range). The author initially considered requiring to remove this safety hazard, but ultimately decided that allowing thing like is much more important, as most searchers are used directly after construction anyways. The proposed searchers also have to store a copy of the predicate and projection, so these should ideally be cheap to copy.
4.3. Building A Searchers Concept
The concept itself does not fully capture the API proposed for the Range versions of searchers; this is because the proposed concept is iterator-based, so the Range constructor and Range-based are not a required part of the searchers interface to reduce requirements on user-provided searcher types. However, range-accepting overloads of will still call the searcher’s range-accepting if it is available, and fall back to iterator versions of otherwise. This design enables optimization opportunities when the searcher can meaningfully treat a range different from its begin/end iterators.
The proposed specification for the concept is as follows:
template < class Searcher , class I , class S , class P = identity > concept searchable = copyable < Searcher > && // C++17 searchers require Cpp17CopyConstructible and Cpp17CopyAssignable already invocable < Searcher , I , S , P > && ranges :: forward_range < invoke_result_t < Searcher , I , S , P >>
Note that we deliberately use here since most implementations of non-trivial searchers are stateful.
4.4. constexpr And Return Type
It is worth noting that are not marked as currently, so the versions also do not support compile-time evaluation. on the other hand did support .
The return type for the new overloads of is specified as (i.e., copy the return type of the searcher’s ). It is possible to require convertible to here too, but the author thinks that this is an unnecessary limitation. The searcher’s return type is constrained to be a forward range by the concept .
4.5. Header Choice
The existing standard searchers live in , and all overloads of the algorithm live in .
This proposal proposes that the new overloads of and both still go into , which is consistent with other overloads of the two algorithms. The versions of the three existing standard searchers should also still go into , following the precedent of . The concept will go into , similar to other and concepts.
4.6. Feature-Test Macro Changes
Currently, both and use the same feature-test macro , and does not have a corresponding macro (its -edness is tracked by ). Also, does not have its own feature-test macro, and the author thinks that bumping for this seems a bit too huge.
This proposal ultimately decided to propose the following changes to feature-test macros:
-
A new FTM
for all Range versions of searchers__cpp_lib_ranges_searcher -
Do not bump the existing
; the author thinks that macro is more appropriate for direct functional changes to the searcher. This proposal also does not make any changes to the existing__cpp_lib_boyer_moore_searcher anywaystd :: boyer_moore_ [ horspool_ ] searcher -
A new FTM
for__cpp_lib_ranges_search (should track all overloads)std :: ranges :: search -
Bump the existing
FTM for__cpp_lib_ranges_contains (this FTM is also used byranges :: contains_subrange too)ranges :: contains
Of course, the author is happy to split the FTMs further (such as separate FTMs for each Range searcher) if LEWG requests.
4.7. Freestanding
After the adoption of [P2976R1] in C++26, the majority of (including all overloads of and ) are marked as freestanding. This proposal does not change anything in that regard, so the newly proposed overloads are also available in freestanding.
The searchers have a somewhat different status. is deliberately left out of freestanding by [P1642R11] as their common implementations rely on dynamic allocation, so their range versions are also not marked freestanding. is marked freestanding as it is just a thin wrapper around anyway. The concept is marked freestanding to maintain consistency with other parts of .
All feature-test macros added by this paper are marked freestanding, and all modified FTMs are already freestanding after the adoption of [P2198R7] and [LWG4286]. No existing features are moved to freestanding, so the freestanding-related FTMs are not changed.
4.8. Alternatives Considered
A possible less invasive change is to reuse the existing searchers, but only update with the new overloads. In that path, the concept will probably accept only an iterator type and test for .
However, such a change will not support range-based construction and , not support projections on needles, and also not adapt to the new C++20 range/iterator model. The author thinks that requiring the user to write is strictly worse than introducing Range-ified versions of the searchers.
It has also been considered briefly to add a default argument to the argument of the algorithms; however, using here is meaningless, and other searchers all have different tradeoffs, so it seems unwise for the standard to specify one as the default choice.
4.9. Future Extensions
4.9.1. Parallel Overloads
After C++26 adopted [P3179R9], most of the algorithms in the namespace gained a parallel overload that accepts an execution policy as the first argument. Since searchers are born to increase the performance of searching, it seems natural to also add parallel overload to them to further increase efficiency.
However, most existing specialized algorithms are designed for sequential usage. Paralleled versions of the Boyer-Moore algorithm are certainly possible, but seem to require non-trivial handling of edge cases, such as when the pattern crosses the slicing boundaries. Given that C++17’s parallel STL library deliberately did not add an execution policy overload to the searcher version of , this proposal also does not add an execution policy overload to or .
A future parallel extension probably requires some kind of coordination between the algorithm and the searcher, so both the constructor and of the searcher probably should accept an execution policy argument (which also requires a new version of the concept ). However, such extensions are outside the scope of this proposal.
4.9.2. Searcher Overloads In More Algorithms
Currently, searchers are only accepted and used in . This proposal does a slight extension in this regard to make accept searchers too.
In the future, it can be envisioned that more algorithms can take advantage of searchers. For instance, may also accept a searcher that is constructed from and , and family may also benefit from more performant algorithms that search for single elements. However, such extensions are outside the scope of this proposal.
4.9.3. More Searchers
Finally, there are various attempts to add more searchers to the standard library, providing users with searchers that satisfy more tradeoff decisions. Popular choices include the famous Knuth-Morris-Pratt String-Searching Algorithm and Crochemore-Perrin Search Algorithm ([P0638R0]). Similar to Range algorithms, future extensions to searchers probably should only add types to (in particular from [P0638R0] can use instead). Though the author will not oppose adding versions too.
5. Implementation Experience
The author implemented this proposal in beman.range_searcher as part of the Beman Project. The implementation basically copies libc++'s searcher implementation and modify them to accommodate the new API. All modifications are straightforward, and no significant obstacles are observed.
6. Questions To Resolve
6.1. Questions for SG9
-
Should the searchers be templated on range types or iterator/sentinel types?
6.2. Questions for LEWG
-
does specify that the searchers don’t need to satisfy Cpp17CopyConstructible; do we want to relax thestd :: search requirement incopyable ?searchable -
Should searchers'
be SFINAE-friendly (i.e., put the same value type requirements in theoperator () clause)?requires
7. Wording
The wording below is based on [N5032].
7.1. 17.3.2 Header < version > synopsis [version.syn]
In this clause’s synopsis, make the following modification, substituting by the date of adoption. All inserted new macro definition should be in places that respects the current alphabetical order of the synopsis.
#define __cpp_lib_ranges_contains 20XXYYL 202207L // freestanding, also in <algorithm> // [...] #define __cpp_lib_ranges_search 20XXYYL // freestanding, also in <algorithm> #define __cpp_lib_ranges_searcher 20XXYYL // freestanding, also in <functional>
7.2. 22.10.2 Header < functional > synopsis [functional.syn]
Modify the synopsis as follows:
// [...] namespace std { // [...] // [func.search], searchers // [...] template < class RandomAccessIterator , class Hash = hash < typename iterator_traits < RandomAccessIterator >:: value_type > , class BinaryPredicate = equal_to <>> class boyer_moore_horspool_searcher ; namespace ranges { template < forward_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity > class default_searcher ; // freestanding template < random_access_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> class boyer_moore_searcher ; template < random_access_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> class boyer_moore_horspool_searcher ; } // [...] }
Editor’s Note: Insert the following subclause at the end of 22.10.18 Searchers [func.search]
7.3. 22.10.18.5 Range-based searchers [func.range.search]
7.3.1. 22.10.18.5.1 Class template default_searcher [func.range.search.default]
namespace std :: ranges { template < forward_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity > class default_searcher { public : constexpr default_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {}); template < typename R2 > requires same_as < remove_reference_t < R2 > , R > constexpr explicit default_searcher ( R2 && r ); template < typename R2 > requires same_as < remove_reference_t < R2 > , R > constexpr default_searcher ( R2 && r , Pred pred , Proj proj = {}); template < forward_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > constexpr subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > ; template < forward_range R2 , class Proj2 = identity > constexpr borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > ; private : [[ no_unique_address ]] std :: ranges :: iterator_t < R > pat_first_ ; // exposition only [[ no_unique_address ]] std :: ranges :: sentinel_t < R > pat_last_ ; // exposition only [[ no_unique_address ]] Pred pred_ ; // exposition only [[ no_unique_address ]] Proj proj_ ; // exposition only } template < forward_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity > default_searcher ( R && , Pred = {}, Proj = {}) -> default_searcher < remove_reference_t < R > , Pred , Proj > }
constexpr default_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {});
-
Effects: Constructs a
object, initializingdefault_searcher withpat_first_ ,pat_first withpat_last_ ,pat_last withpred_ , andmove ( pred ) withproj_ .move ( proj ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > .sentinel_t < R >
template < typename R2 > requires same_as < remove_reference_t < R2 > , R > constexpr explicit default_searcher ( R2 && r );
-
Effects: Constructs a
object, initializingdefault_searcher withpat_first_ andranges :: begin ( r ) withpat_last_ .ranges :: end ( r ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > .sentinel_t < R >
template < typename R2 > requires same_as < remove_reference_t < R2 > , R > constexpr default_searcher ( R2 && r , Pred pred , Proj proj = {});
-
Effects: Constructs a
object, initializingdefault_searcher withpat_first_ ,ranges :: begin ( r ) withpat_last_ ,ranges :: end ( r ) withpred_ , andmove ( pred ) withproj_ .move ( proj ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > .sentinel_t < R >
template < forward_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > constexpr subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > ;
-
Effects: Equivalent to:
return ranges :: search ( first , last , pat_first_ , pat_last_ , pred_ , move ( proj2 ), proj_ );
template < forward_range R2 , class Proj2 = identity > constexpr borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > ;
-
Effects: Equivalent to:
return ranges :: search ( ranges :: begin ( r2 ), ranges :: end ( r2 ), pat_first_ , pat_last_ , pred_ , move ( proj2 ), proj_ );
7.3.2. 22.10.18.5.2 Class template boyer_moore_searcher [func.range.search.bm]
namespace std :: ranges { template < random_access_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> class boyer_moore_searcher { public : boyer_moore_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {}, Hash hf = {}); template < typename R2 > requires same_as < remove_reference_t < R2 > , R > explicit boyer_moore_searcher ( R2 && r ); template < typename R2 > requires same_as < remove_reference_t < R2 > , R > boyer_moore_searcher ( R2 && r , Pred pred , Proj proj = {}, Hash hf = {}); template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > ; template < random_access_range R2 , class Proj2 = identity > borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > ; private : [[ no_unique_address ]] std :: ranges :: iterator_t < R > pat_first_ ; // exposition only [[ no_unique_address ]] std :: ranges :: sentinel_t < R > pat_last_ ; // exposition only [[ no_unique_address ]] Pred pred_ ; // exposition only [[ no_unique_address ]] Proj proj_ ; // exposition only [[ no_unique_address ]] Hash hash_ ; // exposition only } template < random_access_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> boyer_moore_searcher ( R && , Pred = {}, Proj = {}, Hash = {}) -> boyer_moore_searcher < remove_reference_t < R > , Pred , Proj , Hash > ; }
boyer_moore_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {}, Hash hf = {});
-
Preconditions: Let
beV . For any two valuesrange_value_t < R > andA of typeB , ifV , thenpred ( invoke ( proj , A ), invoke ( proj , B )) == trueishf ( invoke ( proj , A )) == hf ( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_searcher withpat_first_ ,pat_first withpat_last_ ,pat_last withpred_ ,move ( pred ) withproj_ , andmove ( proj ) withhash_ .move ( hf ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > , or by the default constructor, copy constructor, or the copy assignment operator of the value type ofsentinel_t < R > , orR ofoperator () orPred . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
template < typename R2 > requires same_as < remove_reference_t < R2 > , R > explicit boyer_moore_searcher ( R2 && r );
-
Preconditions: Let
beV . For any two valuesrange_value_t < R > andA of typeB , ifV , thenPred {}( invoke ( proj , A ), invoke ( proj , B )) == trueisHash {}( invoke ( proj , A )) == Hash {}( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_searcher withpat_first_ andranges :: begin ( r ) withpat_last_ .ranges :: end ( r ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > , or by the default constructor, copy constructor, or the copy assignment operator of the value type ofsentinel_t < R > , orR ofoperator () orPred . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
template < typename R2 > requires same_as < remove_reference_t < R2 > , R > boyer_moore_searcher ( R2 && r , Pred pred , Proj proj = {}, Hash hf = {});
-
Preconditions: Let
beV . For any two valuesrange_value_t < R > andA of typeB , ifV , thenpred ( invoke ( proj , A ), invoke ( proj , B )) == trueishf ( invoke ( proj , A )) == hf ( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_searcher withpat_first_ ,ranges :: begin ( r ) withpat_last_ ,ranges :: end ( r ) withpred_ ,move ( pred ) withproj_ , andmove ( proj ) withhash_ .move ( hf ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > , or by the default constructor, copy constructor, or the copy assignment operator of the value type ofsentinel_t < R > , orR ofoperator () orPred . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > ;
-
Mandates:
isis_same_v < remove_cvref_t < projected_value_t < iterator_t < R > , Proj >> , remove_cvref_t < projected_value_t < I2 , Proj2 >>> true. -
Effects: Finds a subsequence of equal values in a sequence.
-
Returns:
, wheresubrange ( i , j ) andi is a pair of iterators such thatj
-
is the first iterator in the rangei such that for every non-negative integer[ first , last - ( pat_last_ - pat_first_ )) less thann the following condition holds:pat_last_ - pat_first_ , andpred_ ( invoke ( proj2 , * ( i + n )), invoke ( proj_ , * ( pat_first_ + n ))) != false -
.j == ranges :: next ( i , ranges :: distance ( pat_first_ , pat_last_ ))
Returns if is empty, otherwise returns if no such iterator is found.
-
Complexity: At most
applications of the predicate, and at most( last - first ) * ( pat_last_ - pat_first_ ) applications of either projection.( last - first ) * ( pat_last_ - pat_first_ + 1 )
template < random_access_range R2 , class Proj2 = identity > borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > ;
-
Effects: Equivalent to:
return operator ()( ranges :: begin ( r2 ), ranges :: end ( r2 ), move ( proj2 ));
7.3.3. 22.10.18.5.3 Class template boyer_moore_horspool_searcher [func.range.search.bmh]
namespace std :: ranges { template < random_access_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> class boyer_moore_horspool_searcher { public : boyer_moore_horspool_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {}, Hash hf = {}); template < typename R2 > requires same_as < remove_reference_t < R2 > , R > explicit boyer_moore_horspool_searcher ( R2 && r ); template < typename R2 > requires same_as < remove_reference_t < R2 > , R > boyer_moore_horspool_searcher ( R2 && r , Pred pred , Proj proj = {}, Hash hf = {}); template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > ; template < random_access_range R2 , class Proj2 = identity > borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > ; private : [[ no_unique_address ]] std :: ranges :: iterator_t < R > pat_first_ ; // exposition only [[ no_unique_address ]] std :: ranges :: sentinel_t < R > pat_last_ ; // exposition only [[ no_unique_address ]] Pred pred_ ; // exposition only [[ no_unique_address ]] Proj proj_ ; // exposition only [[ no_unique_address ]] Hash hash_ ; // exposition only } template < random_access_range R , copy_constructible Pred = equal_to , indirectly_regular_unary_invocable < iterator_t < R >> Proj = identity , class Hash = hash < projected_value_t < iterator_t < R > , Proj >>> requires semiregular < range_value_t < R >> boyer_moore_horspool_searcher ( R && , Pred = {}, Proj = {}, Hash = {}) -> boyer_moore_horspool_searcher < remove_reference_t < R > , Pred , Proj , Hash > ; }
boyer_moore_horspool_searcher ( iterator_t < R > pat_first , sentinel_t < R > pat_last , Pred pred = {}, Proj proj = {}, Hash hf = {});
-
Preconditions: Let
beV . For any two valuesrange_value_t < R > andA of typeB , ifV , thenpred ( invoke ( proj , A ), invoke ( proj , B )) == trueishf ( invoke ( proj , A )) == hf ( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_horspool_searcher withpat_first_ ,pat_first withpat_last_ ,pat_last withpred_ ,move ( pred ) withproj_ , andmove ( proj ) withhash_ .move ( hf ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > , or by the default constructor, copy constructor, or the copy assignment operator of the value type ofsentinel_t < R > , orR ofoperator () orPred . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
template < typename R2 > requires same_as < remove_reference_t < R2 > , R > explicit boyer_moore_horspool_searcher ( R2 && r );
-
Preconditions: Let
beV . For any two valuesrange_value_t < R > andA of typeB , ifV , thenPred {}( invoke ( proj , A ), invoke ( proj , B )) == trueisHash {}( invoke ( proj , A )) == Hash {}( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_horspool_searcher withpat_first_ andranges :: begin ( r ) withpat_last_ .ranges :: end ( r ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > , or by the default constructor, copy constructor, or the copy assignment operator of the value type ofsentinel_t < R > , orR ofoperator () orPred . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
template < typename R2 > requires same_as < remove_reference_t < R2 > , R > boyer_moore_horspool_searcher ( R2 && r , Pred pred , Proj proj = {}, Hash hf = {});
-
Preconditions: Let
beV . For any two valuesrange_value_t < R > andA of typeB , ifV , thenpred ( invoke ( proj , A ), invoke ( proj , B )) == trueishf ( invoke ( proj , A )) == hf ( invoke ( proj , B )) true. -
Effects: Constructs a
object, initializingboyer_moore_horspool_searcher withpat_first_ ,ranges :: begin ( r ) withpat_last_ ,ranges :: end ( r ) withpred_ ,move ( pred ) withproj_ , andmove ( proj ) withhash_ .move ( hf ) -
Throws: Any exception thrown by the copy constructor of
oriterator_t < R > , or by the default constructor, copy constructor, or the copy assignment operator of the value type ofsentinel_t < R > , orR ofoperator () orPred . May throwHash if additional memory needed for internal data structures cannot be allocated.bad_alloc
template < random_access_iterator I2 , sentinel_for < I2 > S2 , class Proj2 = identity > subrange < I2 > operator ()( I2 first , S2 last , Proj2 proj2 = {}) const requires indirectly_comparable < I2 , iterator_t < R > , Pred , Proj2 , Proj > ;
-
Mandates:
isis_same_v < remove_cvref_t < projected_value_t < iterator_t < R > , Proj >> , remove_cvref_t < projected_value_t < I2 , Proj2 >>> true. -
Effects: Finds a subsequence of equal values in a sequence.
-
Returns:
, wheresubrange ( i , j ) andi is a pair of iterators such thatj
-
is the first iterator in the rangei such that for every non-negative integer[ first , last - ( pat_last_ - pat_first_ )) less thann the following condition holds:pat_last_ - pat_first_ , andpred_ ( invoke ( proj2 , * ( i + n )), invoke ( proj_ , * ( pat_first_ + n ))) != false -
.j == ranges :: next ( i , ranges :: distance ( pat_first_ , pat_last_ ))
Returns if is empty, otherwise returns if no such iterator is found.
-
Complexity: At most
applications of the predicate, and at most( last - first ) * ( pat_last_ - pat_first_ ) applications of either projection.( last - first ) * ( pat_last_ - pat_first_ + 1 )
template < random_access_range R2 , class Proj2 = identity > borrowed_subrange_t < R2 > operator ()( R2 && r2 , Proj2 proj2 = {}) const requires indirectly_comparable < iterator_t < R2 > , iterator_t < R > , Pred , Proj2 , Proj > ;
-
Effects: Equivalent to:
return operator ()( ranges :: begin ( r2 ), ranges :: end ( r2 ), move ( proj2 ));
7.4. 24.2 Header < iterator > synopsis [iterator.synopsis]
Modify the synopsis as follows:
// [...] namespace std { // [...] // [alg.req.ind.cmp], concept indirectly_comparable template < class I1 , class I2 , class R , class P1 = identity , class P2 = identity > concept indirectly_comparable = see below ; // freestanding // [alg.req.searchable], concept searchable template < class Searcher , class I , class S , class P = identity > concept searchable = see below ; // freestanding // [alg.req.permutable], concept permutable template < class I > concept permutable = see below ; // freestanding // [...] }
Editor’s Note: Insert the following subclause between 24.3.7.5 Concept [alg.req.ind.cmp] and 24.3.7.6 Concept [alg.req.permutable]
7.5. 24.3.7.� Concept searchable [alg.req.searchable]
-
The
concept specifies the requirements of algorithms that interact with searchers (22.10.18 [func.search]) to search for a sequence in another sequence.searchable
template < class Searcher , class I , class S , class P = identity > concept searchable = copyable < Searcher > && invocable < Searcher , I , S , P > && ranges :: forward_range < invoke_result_t < Searcher , I , S , P >>
7.6. 26.4 Header < algorithm > synopsis [algorithm.syn]
Modify the synopsis as follows:
// [...] namespace std { // [...] // [alg.contains], contains namespace ranges { // [...] template < execution - policy Ep , sized - random - access - range R1 , sized - random - access - range R2 , class Pred = ranges :: equal_to , class Proj1 = identity , class Proj2 = identity > requires indirectly_comparable < iterator_t < R1 > , iterator_t < R2 > , Pred , Proj1 , Proj2 > bool contains_subrange ( Ep && exec , R1 && r1 , R2 && r2 , Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr bool contains_subrange ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr bool contains_subrange ( R && r , const Searcher & searcher , Proj proj = {}); } // [...] // [alg.search], search // [...] template < class ForwardIterator , class Searcher > constexpr ForwardIterator search ( ForwardIterator first , ForwardIterator last , const Searcher & searcher ); namespace ranges { template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr auto search ( I first , S last , const Searcher & searcher , Proj proj = {}); template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr auto search ( R && r , const Searcher & searcher , Proj proj = {}); } // [...] }
7.7. 26.6.4 Contains [alg.contains]
Add to the end of this clause:
template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr bool ranges :: contains_subrange ( I first , S last , const Searcher & searcher , Proj proj = {});
-
Returns:
! ranges :: empty ( ranges :: search ( first , last , searcher , move ( proj )))
template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr bool ranges :: contains_subrange ( R && r , const Searcher & searcher , Proj proj = {});
-
Returns:
! ranges :: empty ( ranges :: search ( forward < R > ( r ), searcher , move ( proj )))
7.8. 26.6.15 Search [alg.search]
Add to the end of this clause:
template < forward_iterator I , sentinel_for < I > S , class Searcher , class Proj = identity > requires searchable < Searcher , I , S , Proj > constexpr auto ranges :: search ( I first , S last , const Searcher & searcher , Proj proj = {});
-
Effects: Equivalent to:
return searcher ( first , last , move ( proj ));
template < forward_range R , class Searcher , class Proj = identity > requires searchable < Searcher , iterator_t < R > , sentinel_t < R > , Proj > constexpr auto ranges :: search ( R && r , const Searcher & searcher , Proj proj = {});
-
Effects: Equivalent to:
-
if that expression is well-formed.return searcher ( forward < R > ( r ), move ( proj )) -
Otherwise,
.return searcher ( ranges :: begin ( r ), ranges :: end ( r ), move ( proj ));