// bslstl_defaultsearcher.h -*-C++-*- #ifndef INCLUDED_BSLSTL_DEFAULTSEARCHER #define INCLUDED_BSLSTL_DEFAULTSEARCHER #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide an STL-compliant 'default_searcher' class. // //@CLASSES: // bsl::default_searcher: class template to search via the "naive" algorithm // bslstl::DefaultSearcher: class template to search via the "naive" algorithm // //@CANONICAL_HEADER: bsl_functional.h // //@SEE_ALSO: bslstl_boyermoorehorspoolsearcher // //@DESCRIPTION: This component defines two class templates, // 'bsl::default_searcher' and 'bslstl::DefaultSearcher'. Both are compliant // with section '[func.search.default]' of the C++ Standard (C++17 and later). // // 'bsl::default_searcher' is strictly limited to the Standard and is provided // for clients for whom standard compliance is a priority. // 'bslstl::DefaultSearcher' provides several additional accessors that are not // mentioned in the Standard. // // Except where there is a relevant difference, both are described below as if // they were one. // // This class template has two parameters: // //: 'FORWARD_ITR_NEEDLE': //: The iterator type that defines on construction the range of values to be //: sought (the "needle"), and //: //: 'EQUAL': //: an optional parameter that defines the class used to compare those //: values. // // The class also provides a functor-style interface that accepts two iterators // that define the range of values to be searched (the "haystack"). Once // constructed the searcher object can be re-used to search multiple haystacks // (for the same needle). // // The iterators defining the haystack need not be of the same type as those // that define the needle. Moreover, the search method of the searcher can be // overloaded for an arbitrary different haystack iterators (subject to // {Iterator Requirements}). // ///Algorithm ///--------- // The 'bslstl::DefaultSearcher' class uses the classic, "naive" algorithm. // The needle is sought at the beginning of the haystack and, if not found // there, the start position in the haystack is incremented. That is repeated // until the needle is found in the haystack or the end of the haystack is // encountered. The time complexity is 'O(M * N)', where 'M' is the length of // the needle and 'N' is the length of the haystack. // // There are more sophisticated algorithms available; however, those typically // require creating and retaining metadata derived from the needle and/or // haystack. If the needle is short and the haystack of moderate length, the // naive algorithm may be faster than generating that metadata, especially if // the search is one-time and the metadata cost cannot be amortized. // // Another advantage of the "default" searcher is that it accepts (relatively // simple) *ForwardIterator*s whereas more sophisticated algorithms typically // require (more fully-featured) *RandomIterator*s. // ///Iterator Requirements ///--------------------- // The two independent iterator types associated with this class -- one // defining the needle, the other defining the haystack -- must meet the // requirements of *ForwardIterator*. // // Additionally: //: o These iterators can be constant. //: o When dereferenced, they must both refer to the same value type. // // Either of the iterator types are allowed to throw exceptions. // // Iterators defining needles are required to remain valid as long as the // searcher object might be used. // ///Comparator Requirements ///----------------------- // The comparator class must meet the requirements of *BinaryPredicate*: //: o The class defines an 'operator()' method, which, given an //: *ForwardIterator*, 'iterator', may be invoked as //: 'operator()(*iterator, *iterator)'. //: o The return value must be contextually convertible to 'bool'. //: o The supplied iterators can be constant. //: o The class must be copyable. // // The comparator class is allowed to throw exceptions. // ///Optimizations for 'bslstl::DefaultSearcher' ///------------------------------------------- // For certain template arguments this implementation improves performance by // utilizing low-level operations. The requirements to do so are: //: o Both supplied iterators are pointers. //: o The default equality comparison is allowed to default (to //: 'bsl::equal_to<value_type>'). //: o The 'value_type' is bitwise-equality-comparable. // // Users supplying their own data types are advised to set the // 'bslmf::IsBitwiseEqualityComparable' trait when applicable so that // 'bslstl::DefaultSearcher' knows that the last optimization condition listed // above is met. See {'bslmf_isbitwiseequalitycomparable'}. // ///Usage ///----- // In this section we show the intended usage of this component. // ///Example 1: Basic Usage /// - - - - - - - - - - - // The problem of searching a sequence of characters for a particular // sub-sequence arises in many applications. For example, one might need to // know if some document contains a particular word of interest. For example, // suppose we would like to know the first occurrence of the word "United" in // the Declaration of Independence (of the United States): // // First, we obtain the text of document and word of interest as sequences of // 'char' values. //.. // const char document[] = // " IN CONGRESS, July 4, 1776.\n" // 28 // "\n" // 1 // " The unanimous Declaration of the thirteen united States of America,\n" // //----^----|----^----|----^----|----^----|---- // 44 // // // -- // // // 73rd character // // // "\n" // // ... // " declare, That these United Colonies are, and of Right ought to be\n" // // ... // "Honor."; // // const char *word = "United"; //.. // Then, we create a 'bsl::default_searcher' object (a functor) using the given // 'word': //.. // bsl::default_searcher<const char*> searchForUnited( // word, // word + bsl::strlen(word)); //.. // Notice that no equality comparison functor was specified so // 'searchForUnited' will use 'bsl::equal_to<char>' by default. // // Now, we invoke our functor, specifying the range of the document to be // searched: //.. // bsl::pair<const char *, const char *> result = searchForUnited( // document, // document // + sizeof document); // bsl::size_t offset = result.first - document; // // assert(120 == offset); // assert(static_cast<bsl::size_t>(result.second - result.first) // == bsl::strlen(word)); //.. // Finally, we notice that the search correctly ignored the appearance of the // word "united" (all lower case) in the second sentence. // // {'bslstl_boyermoorehorspoolsearcher'|Example 1} shows how the same problem // is addressed using 'bsl::boyer_moore_horspool_searcher'. // ///Example 2: Defining a Comparator /// - - - - - - - - - - - - - - - - // As seen in {Example 1} above, the default equality comparison functor is // case sensitive. If one needs case *in*-sensitive searches, a non-default // equality comparison class must be specified. // // First, define (at file scope if using a pre-C++11 compiler) an equality // comparison class that provides the required functor interface: //.. // struct MyCaseInsensitiveCharComparator { // bool operator()(const char& a, const char& b) const { // return bsl::tolower(a) == bsl::tolower(b); // } // }; //.. // Then, define a new 'bsl::default_searcher' type and create a searcher object // to search for 'word': //.. // bsl::default_searcher<const char *, // struct MyCaseInsensitiveCharComparator> // searchForUnitedInsensitive( // word, // word + bsl::strlen(word)); //.. // Note that the new searcher object will used a default constructed // 'MyCaseInsensitiveCharComparator' class. If an equality comparison object // requires state supplied on construction, such an object be explicitly // created and supplied as the final constructor argument. // // Now, we invoke our new functor, specifying that the same document searched // in {Example 1}: //.. // bsl::pair<const char *, const char *> resultInsensitive = // searchForUnitedInsensitive( // document, // document // + sizeof document); // // bsl::size_t offsetInsensitive = resultInsensitive.first - document; // // assert( 72 == offsetInsensitive); // assert(static_cast<bsl::size_t>(resultInsensitive.second // - resultInsensitive.first) // == bsl::strlen(word)); //.. // Finally, we find the next occurrence of 'word' by *reusing* the same // searcher object, this time instructing it to begin its search just after the // previous occurrence of 'word' was found: //.. // resultInsensitive = searchForUnitedInsensitive(resultInsensitive.second, // document + sizeof document); // // offsetInsensitive = resultInsensitive.first - document; // // assert(120 == offsetInsensitive); // assert(static_cast<bsl::size_t>(resultInsensitive.second // - resultInsensitive.first) // == bsl::strlen(word)); //.. // {'bslstl_boyermoorehorspoolsearcher'|Example 2} shows how the same problem // is addressed using 'bsl::boyer_moore_horspool_searcher'. // ///Example 3: Non-'char' Searches /// - - - - - - - - - - - - - - - // The "default" searcher class template is not constrained to searching for // 'char' values. Searches can be done on other types (see {Iterator // Requirements}). Moreover the container of the sequence being sought (the // "needle") need not the same as the sequence being searched (the "haystack"). // // Suppose one has data from an instrument that reports 'float' values and that // inserts the sequence '{ FLT_MAX, FLT_MIN, FLT_MAX }' as a marker for the // start and end of a test run. We can assume the probably of the instrument // reporting this sequence as readings is negligible and that data reported // outside of the test runs is random noise. Here is how we can search for the // first test run data in the data sequence. // // First, we create a representation of the sequence that denotes the limit of // a test run. //.. // const float markerSequence[] = { FLT_MAX , FLT_MIN , FLT_MAX }; // const bsl::size_t markerSequenceLength = sizeof markerSequence // / sizeof *markerSequence; //.. // Next, we obtain the data to be searched. (In this example, we will use // simulated data.) //.. // bsl::list<float> data; // Container provides bidirectional iterators. // doTestRun(&data); //.. // Then, we define and create our searcher object: //.. // bsl::default_searcher<const float *> searchForMarker(markerSequence, // markerSequence // + markerSequenceLength); //.. // Notice that no equality comparator was specified so 'searchForMarker' will // use 'bsl::equal_to<float>' by default. // // Now, we invoke our searcher on the instrument data. //.. // typedef bsl::list<float>::const_iterator DataConstItr; // // const bsl::pair<DataConstItr, DataConstItr> notFound(data.cend(), // data.cend()); // // bsl::pair<DataConstItr, DataConstItr> markerPosition = searchForMarker( // data.cbegin(), // data.cend()); // // assert(notFound != markerPosition); // // DataConstItr startOfTestRun = markerPosition.second; //.. // Finally, we locate the marker of the end of the first test run and pass the // location of the first test run data to some other function for processing. //.. // markerPosition = searchForMarker(markerPosition.second, data.cend()); // // assert(notFound != markerPosition); // // DataConstItr endOfTestRun = markerPosition.first; // // processTestRun(startOfTestRun, endOfTestRun); //.. // // {'bslstl_boyermoorehorspoolsearcher'|Example 3} shows how the same problem // is addressed using 'bsl::boyer_moore_horspool_searcher'. Notice that other // example uses 'data' from a container that provides random access iterators; // whereas here, bidirectional iterators are used (and forward iterators would // have sufficed). #include <bslscm_version.h> #include <bslstl_equalto.h> #include <bslstl_iterator.h> #include <bslstl_pair.h> #include <bslmf_assert.h> #include <bslmf_enableif.h> #include <bslmf_issame.h> #include <bsls_assert.h> #include <bsls_keyword.h> // for 'BSLS_KEYWORD_CONSTEXPR' #include <bsls_libraryfeatures.h> #include <bsls_performancehint.h> #include <cstring> // for 'std::memcmp' #include <utility> // for 'std::make_pair' namespace BloombergLP { namespace bslstl { // ===================== // class DefaultSearcher // ===================== template <class FORWARD_ITR_NEEDLE, class EQUAL = bsl::equal_to< typename bsl::iterator_traits<FORWARD_ITR_NEEDLE>::value_type> > class DefaultSearcher { // This class template defines functors that can search for the sequence of // 'value_type' values defined on construction (i.e., the "needle") in // sequences of 'value_type' values (i.e., "haystacks") passed to the // functor's 'operator()'. // PRIVATE TYPES typedef typename bsl::iterator_traits<FORWARD_ITR_NEEDLE>::value_type value_type; // the type of the values that can be obtained by dereferencing a // 'FORWARD_ITR_NEEDLE' iterator typedef typename bsl::iterator_traits<FORWARD_ITR_NEEDLE>:: iterator_category IteratorCategory; // DATA FORWARD_ITR_NEEDLE d_needleFirst; FORWARD_ITR_NEEDLE d_needleLast; EQUAL d_equal; public: // CREATORS DefaultSearcher(FORWARD_ITR_NEEDLE needleFirst, FORWARD_ITR_NEEDLE needleLast, EQUAL equal = EQUAL()); // Create a 'DefaultSearcher' object that can search for the sequence // of 'value_type' values found in the specified range // '[needleFirst, needleLast)'. Optionally supply an 'equal' functor // for use by 'operator()'. The behavior is undefined unless // 'needleFirst' can be advanced to equal 'needleLast'. //! DefaultSearcher(const DefaultSearcher& original) = default; // Create a 'DefaultSearcher' object that has the same state as the // specified 'original' object. //! DefaultSearcher(DefaultSearcher&& original) = default; // Create a 'DefaultSeacher' object having the same state as the // specified 'original' object. The 'original' object is left in an // unspecified (valid) state. //! ~DefaultSearcher() = default; // Destroy this 'DefaultSearcher' object. // MANIPULATORS //! DefaultSearcher& operator=(const DefaultSearcher& rhs) = default; // Assign to this object the state of the specified 'rhs' object, and // return a non-'const' reference to this object. //! DefaultSearcher& operator=(DefaultSearcher&& rhs) = default; // Assign to this object the state of the specified 'rhs' had and // return a non-'const' reference to this object. The 'original' // object is left in an unspecified (valid) state. // ACCESSORS template<class FORWARD_ITR_HAYSTACK> bsl::pair<FORWARD_ITR_HAYSTACK, FORWARD_ITR_HAYSTACK> operator()( FORWARD_ITR_HAYSTACK haystackFirst, FORWARD_ITR_HAYSTACK haystackLast) const; // Search the specified range '[haystackFirst, haystackLast)' for the // first sequence of 'value_type' values specified on construction. // Return the range where those values are found, or the range // '[haystackLast, haystackLast)' if that sequence is not found. The // search is performed using a "naive" algorithm that has time // complexity of: //.. // bsl::distance(needleFirst(), needleLast()) // * bsl::distance(haystackFirst, haystackLast); //.. // Values of the "needle" sequence and the "haystack" sequence are // compared using the equality comparison functor specified on // construction. The behavior is undefined unless 'haystackFirst' can // be advanced to equal 'haystackLast' and the iterators used to // construct this object, 'needleFirst()' and 'needleLast()', are still // valid. Note that if the "needle" sequence is empty, the range // '[haystackFirst, haystackFirst)' is returned. Also note that if the // "needle" sequence is longer than the "haystack" sequence -- thus, // impossible for the "needle" to be found in the "haystack" -- the // range '[haystackLast, haystackLast)' is returned. // Non-Standard Accessors FORWARD_ITR_NEEDLE needleFirst() const; // Return an iterator referring to the first element of the sequence of // 'value_type' values that can be sought by this searcher object. FORWARD_ITR_NEEDLE needleLast() const; // Return an iterator referring to one past the last element of the // sequence of 'value_type' values that can be sought by this searcher // object. EQUAL equal() const; // Return the functor used by this searcher object to compare // 'value_type' values. }; // =================================== // struct DefaultSearcher_CanOptimize // =================================== template <class FORWARD_ITR_NEEDLE, class EQUAL, class FORWARD_ITR_HAYSTACK> struct DefaultSearcher_CanOptimize { // This component-private meta-function 'struct' provides a member // enumerator 'value' that is 'true' if all of the specified // 'FORWARD_ITR_NEEDLE,' 'EQUAL,' and 'FORWARD_ITR_HAYSTACK' meet the // criteria for an optimization of the default searcher, and has the value // 'false' otherwise. enum { value = ( bsl::is_pointer<FORWARD_ITR_NEEDLE>::value && bsl::is_pointer<FORWARD_ITR_HAYSTACK>::value && bsl::is_same<EQUAL, // 'EQUAL' does 'value_type::operator==' bsl::equal_to< typename bsl::iterator_traits<FORWARD_ITR_NEEDLE>::value_type > >::value && bslmf::IsBitwiseEqualityComparable< typename bsl::iterator_traits<FORWARD_ITR_NEEDLE>::value_type >::value && bslmf::IsBitwiseEqualityComparable< typename bsl::iterator_traits<FORWARD_ITR_HAYSTACK>::value_type >::value ) }; }; // =============================== // struct DefaultSearcher_ImpUtil // =============================== struct DefaultSearcher_ImpUtil { // This component-private utility 'struct' provides two mutually exclusive // overloads of the 'doSearch' method -- i.e., just one of the two methods // is enabled at any time. Enablement is decided by the // 'DefaultSearcher_CanOptimize' meta-function. // TYPES template <class FORWARD_ITR_NEEDLE, class EQUAL, class FORWARD_ITR_HAYSTACK> static typename bsl::enable_if< DefaultSearcher_CanOptimize<FORWARD_ITR_NEEDLE, EQUAL, FORWARD_ITR_HAYSTACK>::value , bsl::pair<FORWARD_ITR_HAYSTACK, FORWARD_ITR_HAYSTACK> >::type doSearch(const FORWARD_ITR_HAYSTACK& haystackFirst, const FORWARD_ITR_HAYSTACK& haystackLast, const FORWARD_ITR_NEEDLE& needleFirst, const FORWARD_ITR_NEEDLE& needleLast, const EQUAL& equal); template <class FORWARD_ITR_NEEDLE, class EQUAL, class FORWARD_ITR_HAYSTACK> static typename bsl::enable_if<!DefaultSearcher_CanOptimize<FORWARD_ITR_NEEDLE, EQUAL, FORWARD_ITR_HAYSTACK>::value , bsl::pair<FORWARD_ITR_HAYSTACK, FORWARD_ITR_HAYSTACK> >::type doSearch(const FORWARD_ITR_HAYSTACK& haystackFirst, const FORWARD_ITR_HAYSTACK& haystackLast, const FORWARD_ITR_NEEDLE& needleFirst, const FORWARD_ITR_NEEDLE& needleLast, const EQUAL& equal); // Search the specified "haystack" sequence of 'value_type' values, // '[haystackFirst, hastackLast)', for the specified "needle" sequence // of 'value_type' values, '[needleFirst, needleLast)' where the // 'value_type' values are compared using the specified 'equal' // functor. Return the range where the sought sequence of values are // found, or the range '[haystackLast, haystackLast)' if that sequence // is not found. The search is performed using a "naive" algorithm // that has time complexity of: //.. // bsl::distance(needleFirst(), needleLast()) // * bsl::distance(haystackFirst, haystackLast); //.. // Values of the "needle" sequence and the "haystack" sequences are // compared using the equality comparison functor specified on // construction except, possibly, if the 'DefaultSearcher_CanOptimize' // metafunction indicates that the template parameters are eligible for // optimization. The optimized overload is enabled when needle and // haystack can be validly compared using 'std::memcmp', a // low-level function that is often highly optimized for its platform. // The behavior is undefined unless 'haystackFirst' can be advanced to // equal 'haystackLast'. Note that if the "needle" sequence is empty, // the range '[haystackFirst, haystackFirst)' is returned. Also note // that if the "needle" sequence is longer than the "haystack" sequence // -- thus, impossible for the "needle" to be found in the "haystack" // -- the range '[haystackLast, haystackLast)' is returned. }; } // close package namespace } // close enterprise namespace #ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_FUNCTORS namespace bsl { // ====================== // class default_searcher // ====================== template<class ForwardIterator1, class BinaryPredicate = equal_to< typename bsl::iterator_traits<ForwardIterator1>::value_type> > class default_searcher { // This class template defines functors that can search for the sequence of // 'value_type' values defined on construction in sequences of 'value_type' // values passed to the functor's 'operator()'. //DATA BloombergLP::bslstl::DefaultSearcher<ForwardIterator1, BinaryPredicate> d_imp; public: // CREATORS BSLS_KEYWORD_CONSTEXPR default_searcher(ForwardIterator1 pat_first, ForwardIterator1 pat_last, BinaryPredicate pred = BinaryPredicate()); // Create a 'default_searcher' object that can search for the sequence // of 'value_type' values found in the specified range // '[pat_first, pat_last)'. Optionally supply a 'pred' functor for use // by 'operator()'. See {Comparator Requirements}. The behavior is // undefined unless 'pat_first' can be advanced to equal 'pat_last'. //! default_searcher(const default_searcher& original) = default; // Create a 'default_searcher' object having same state as the // specified 'original' object. //! default_searcher(BloombergLP::bslmf::MovableRef<default_searcher> //! original) = default; // Create a 'default_searcher' object having same state as the // specified 'original' object. by moving (in constant time) the state // of 'original' to the new searcher. The 'original' object is left in // an unspecified (valid) state. //! ~default_searcher() = default; // Destroy this 'default_searcher' object. // MANIPULATORS //! default_searcher& operator=(const default_searcher& rhs) = default; // Assign to this object the state of the specified 'rhs' object, and // return a non-'const' reference to this searcher. //! default_searcher& operator=( //! BloombergLP::bslmf::MovableRef<default_searcher> //! rhs) = default; // Assign to this object the state of the specified 'rhs' object and // return a non-'const' reference to this searcher. // ACCESSORS template<class ForwardIterator2> BSLS_KEYWORD_CONSTEXPR pair<ForwardIterator2, ForwardIterator2> operator()( ForwardIterator2 first, ForwardIterator2 last) const; // Search the specified range '[first, last)' for the first sequence of // 'value_type' values specified on construction. Return the range // where those values are found, or the range '[last, last)' if that // sequence is not found. The search is performed using a "naive" // algorithm that has time complexity of: //.. // bsl::distance(pat_first, pat_last) * bsl::distance(first, last); //.. // Values of the two sequences are compared using the equality // comparison functor specified on construction. The behavior is // undefined unless 'first' can be advanced to equal 'last' and the // iterators used to construct this object are still valid. Note that // if the sought sequence is empty, the range '[first, first)' is // returned. Also note that if the sequence sought is longer than the // sequence searched -- thus the sought sequence cannot be found -- the // range '[last, last)' is returned. }; } // close namespace bsl #endif // BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_FUNCTORS // ---------------------------------------------------------------------------- // INLINE DEFINITIONS // ---------------------------------------------------------------------------- namespace BloombergLP { namespace bslstl { // --------------------- // class DefaultSearcher // --------------------- //CREATORS template <class FORWARD_ITR_NEEDLE, class EQUAL> inline DefaultSearcher<FORWARD_ITR_NEEDLE, EQUAL>:: DefaultSearcher(FORWARD_ITR_NEEDLE needleFirst, FORWARD_ITR_NEEDLE needleLast, EQUAL equal) : d_needleFirst(needleFirst) , d_needleLast( needleLast) , d_equal(equal) { BSLS_ASSERT(0 <= bsl::distance(needleFirst, needleLast)); } // ACCESSORS template <class FORWARD_ITR_NEEDLE, class EQUAL> template <class FORWARD_ITR_HAYSTACK> inline bsl::pair<FORWARD_ITR_HAYSTACK, FORWARD_ITR_HAYSTACK> DefaultSearcher<FORWARD_ITR_NEEDLE, EQUAL>::operator()( FORWARD_ITR_HAYSTACK haystackFirst, FORWARD_ITR_HAYSTACK haystackLast) const { BSLMF_ASSERT((bsl::is_same< typename bsl::iterator_traits<FORWARD_ITR_NEEDLE >::value_type, typename bsl::iterator_traits<FORWARD_ITR_HAYSTACK>::value_type >::value)); return BloombergLP::bslstl:: DefaultSearcher_ImpUtil::doSearch<FORWARD_ITR_NEEDLE, EQUAL, FORWARD_ITR_HAYSTACK>( haystackFirst, haystackLast, d_needleFirst, d_needleLast, d_equal); } template <class FORWARD_ITR_NEEDLE, class EQUAL> inline FORWARD_ITR_NEEDLE DefaultSearcher<FORWARD_ITR_NEEDLE, EQUAL>::needleFirst() const { return d_needleFirst; } template <class FORWARD_ITR_NEEDLE, class EQUAL> inline FORWARD_ITR_NEEDLE DefaultSearcher<FORWARD_ITR_NEEDLE, EQUAL>::needleLast() const { return d_needleLast; } template <class FORWARD_ITR_NEEDLE, class EQUAL> inline EQUAL DefaultSearcher<FORWARD_ITR_NEEDLE, EQUAL>::equal() const { return d_equal; } // ----------------------------- // class DefaultSearcher_ImpUtil // ----------------------------- // CLASS METHODS template <class FORWARD_ITR_NEEDLE, class EQUAL, class FORWARD_ITR_HAYSTACK> inline typename bsl::enable_if< ! DefaultSearcher_CanOptimize<FORWARD_ITR_NEEDLE, EQUAL, FORWARD_ITR_HAYSTACK>::value , bsl::pair<FORWARD_ITR_HAYSTACK, FORWARD_ITR_HAYSTACK> >::type DefaultSearcher_ImpUtil::doSearch( const FORWARD_ITR_HAYSTACK& haystackFirst, const FORWARD_ITR_HAYSTACK& haystackLast, const FORWARD_ITR_NEEDLE& needleFirst, const FORWARD_ITR_NEEDLE& needleLast, const EQUAL& equal) { BSLS_ASSERT(0 <= bsl::distance(haystackFirst, haystackLast)); for (FORWARD_ITR_HAYSTACK itrHaystackOuter = haystackFirst; itrHaystackOuter != haystackLast; ++itrHaystackOuter) { FORWARD_ITR_HAYSTACK itrHaystackInner = itrHaystackOuter; for (FORWARD_ITR_NEEDLE itrNeedle = needleFirst; /* tests below */ ; ++itrNeedle, ++itrHaystackInner) { if (needleLast == itrNeedle) { // Needle match in haystack! return std::make_pair(itrHaystackOuter, itrHaystackInner); // RETURN } if (haystackLast == itrHaystackInner) { // Hit end of haystack. return std::make_pair(haystackLast, haystackLast); // RETURN } if (equal(*itrHaystackInner, *itrNeedle)) { continue; // Needle match still possible. } else { break; // Move starting point in haystack and try again. } } } // Ran out of haystack without match. return std::make_pair(haystackLast, haystackLast); } template <class FORWARD_ITR_NEEDLE, class EQUAL, class FORWARD_ITR_HAYSTACK> inline typename bsl::enable_if< DefaultSearcher_CanOptimize<FORWARD_ITR_NEEDLE, EQUAL, FORWARD_ITR_HAYSTACK>::value , bsl::pair<FORWARD_ITR_HAYSTACK, FORWARD_ITR_HAYSTACK> >::type DefaultSearcher_ImpUtil::doSearch( const FORWARD_ITR_HAYSTACK& haystackFirst, const FORWARD_ITR_HAYSTACK& haystackLast, const FORWARD_ITR_NEEDLE& needleFirst, const FORWARD_ITR_NEEDLE& needleLast, const EQUAL& ) { ///Implementation Note ///------------------- // This specialization is used only when the 'EQUAL' template parameter // was specified as 'bsl::equal_to<value_type>', the default value. We // ignore that argument and perform its "moral equivalent" for the various // ranges using 'std::memcmp'. typedef typename bsl::iterator_traits<FORWARD_ITR_HAYSTACK>:: difference_type HaystackDifference; typedef typename bsl::iterator_traits<FORWARD_ITR_NEEDLE>::difference_type NeedleDifference; const NeedleDifference needleLength = needleLast - needleFirst; const HaystackDifference haystackLength = haystackLast - haystackFirst; BSLS_ASSERT(0 <= needleLength); BSLS_ASSERT(0 <= haystackLength); if (haystackLength < needleLength) { // Cannot match. return std::make_pair(haystackLast, haystackLast); // RETURN } if (0 == needleLength || 0 == haystackLength) { return std::make_pair(haystackFirst, haystackFirst); // RETURN } for (FORWARD_ITR_HAYSTACK itr = haystackFirst; itr < haystackLast - needleLength + 1; ++itr) { FORWARD_ITR_HAYSTACK itrInner = itr; FORWARD_ITR_NEEDLE needleItrInner = needleFirst; NeedleDifference needleLengthInner = needleLength; if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(*itr == *needleFirst)) { if (1 == needleLength) { return std::make_pair(itr, itr + needleLength); // RETURN } ++itrInner; ++needleItrInner; --needleLengthInner; } else { continue; // Avoided 'memcmp' call } if (0 == std::memcmp( itrInner, needleItrInner, needleLengthInner)) { return std::make_pair(itr, itr + needleLength); // RETURN } } // Ran out of haystack without match. return std::make_pair(haystackLast, haystackLast); } } // close package namespace } // close enterprise namespace #ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_FUNCTORS namespace bsl { // ---------------------- // class default_searcher // ---------------------- // CREATORS template <class ForwardIterator1, class BinaryPredicate> inline BSLS_KEYWORD_CONSTEXPR default_searcher<ForwardIterator1, BinaryPredicate>::default_searcher(ForwardIterator1 pat_first, ForwardIterator1 pat_last, BinaryPredicate pred) : d_imp(pat_first, pat_last, pred) { } // ACCESSORS template <class ForwardIterator1, class BinaryPredicate> template <class ForwardIterator2> inline BSLS_KEYWORD_CONSTEXPR pair<ForwardIterator2, ForwardIterator2> default_searcher<ForwardIterator1, BinaryPredicate>::operator()( ForwardIterator2 first, ForwardIterator2 last) const { return d_imp(first, last); } } // close namespace bsl #endif // BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_FUNCTORS #endif // ---------------------------------------------------------------------------- // Copyright 2019 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------