diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 1568fb5..becad46 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -67,6 +67,7 @@ Thanks to all the people who have reviewed this library and made suggestions for [include gather.qbk] [include hex.qbk] [include is_palindrome.qbk] +[include is_partitioned_until.qbk] [endsect] diff --git a/doc/is_partitioned.qbk b/doc/is_partitioned.qbk index 7a6c458..0ed1f80 100644 --- a/doc/is_partitioned.qbk +++ b/doc/is_partitioned.qbk @@ -57,7 +57,7 @@ Both of the variants of `is_partitioned` take their parameters by value or const * The iterator-based version of the routine `is_partitioned` is also available as part of the C++11 standard. -* `is_partitioned` returns true for empty ranges, no matter what predicate is passed to test against. +* `is_partitioned` returns true for empty and single-element ranges, no matter what predicate is passed to test against. [endsect] diff --git a/doc/is_partitioned_until.qbk b/doc/is_partitioned_until.qbk new file mode 100644 index 0000000..9e0879b --- /dev/null +++ b/doc/is_partitioned_until.qbk @@ -0,0 +1,67 @@ +[/ File is_partitioned_until.qbk] + +[section:is_partitioned_until is_partitioned_until ] + +[/license +Copyright (c) 2017 Alexander Zaitsev + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +The header file 'is_partitioned_until.hpp' contains two variants of a single algorithm, `is_partitioned_until`. The algorithm tests to see if a sequence is partitioned according to a predicate; in other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. + +The routine `is_partitioned_until` takes a sequence and a predicate. It returns the last iterator 'it' in the sequence [begin, end) for which the is_partitioned(begin, it) is true. + +`is_partitioned_until` come in two forms; the first one takes two iterators to define the range. The second form takes a single range parameter, and uses Boost.Range to traverse it. + + +[heading interface] + +The function `is_partitioned_until` returns the last iterator 'it' in the sequence [begin, end) for which the is_partitioned(begin, it) is true. There are two versions; one takes two iterators, and the other takes a range. + +`` +template + InputIterator is_partitioned_until ( InputIterator first, InputIterator last, Predicate p ); +template + typename boost::range_iterator::type is_partitioned_until ( const Range &r, Predicate p ); +`` + +[heading Examples] + +Given the container `c` containing `{ 0, 1, 2, 3, 14, 15 }`, then +`` +bool isOdd ( int i ) { return i % 2 == 1; } +bool lessThan10 ( int i ) { return i < 10; } + +is_partitioned_until ( c, isOdd ) --> iterator to '1' +is_partitioned_until ( c, lessThan10 ) --> end +is_partitioned_until ( c.begin (), c.end (), lessThan10 ) --> end +is_partitioned_until ( c.begin (), c.begin () + 3, lessThan10 ) --> end +is_partitioned_until ( c.end (), c.end (), isOdd ) --> end // empty range +`` + +[heading Iterator Requirements] + +`is_partitioned_until` works on all iterators except output iterators. + +[heading Complexity] + +Both of the variants of `is_partitioned_until` run in ['O(N)] (linear) time; that is, they compare against each element in the list once. If the sequence is found to be not partitioned at any point, the routine will terminate immediately, without examining the rest of the elements. + +[heading Exception Safety] + +Both of the variants of `is_partitioned_until` take their parameters by value or const reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee. + +[heading Notes] + +* `is_partitioned_until` returns iterator to the end for empty and single-element ranges, no matter what predicate is passed to test against. + +[endsect] + +[/ File is_partitioned_until.qbk +Copyright 2017 Alexander Zaitsev +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). +] + diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index ce067cf..4512a53 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -21,4 +21,5 @@ project /boost/algorithm/example exe clamp_example : clamp_example.cpp ; exe search_example : search_example.cpp ; exe is_palindrome_example : is_palindrome_example.cpp; +exe is_partitioned_until_example : is_partitioned_until_example.cpp; diff --git a/example/is_partitioned_until_example.cpp b/example/is_partitioned_until_example.cpp new file mode 100644 index 0000000..759176b --- /dev/null +++ b/example/is_partitioned_until_example.cpp @@ -0,0 +1,70 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#include +#include +#include + +#include + + +namespace ba = boost::algorithm; + +bool isOdd(const int v1) +{ + return v1 % 2 != 0; +} + +struct isOddComp +{ + bool operator()(const int v1) const + { + return v1 % 2 != 0; + } +}; + + +int main ( int /*argc*/, char * /*argv*/ [] ) +{ + std::vector good({1, 2, 4}); + std::vector bad({1, 2, 3}); + + //Use custom function + auto it1 = ba::is_partitioned_until(good.begin(), good.end(), isOdd); + if(it1 == good.end()) + { + std::cout << "The sequence is partitioned\n"; + } + else + { + std::cout << "is_partitioned_until check failed here: " << *it1 << std::endl; + } + + //Use custom comparator + auto it2 = ba::is_partitioned_until(good.begin(), good.end(), isOddComp()); + if(it2 == good.end()) + { + std::cout << "The sequence is partitioned\n"; + } + else + { + std::cout << "is_partitioned_until check failed here: " << *it2 << std::endl; + } + + auto it3 = ba::is_partitioned_until(bad, isOdd); + if(it3 == bad.end()) + { + std::cout << "The sequence is partitioned\n"; + } + else + { + std::cout << "is_partitioned_until check failed here: " << *it3 << std::endl; + } + return 0; +} diff --git a/include/boost/algorithm/cxx11/is_partitioned.hpp b/include/boost/algorithm/cxx11/is_partitioned.hpp index cb6c71e..c0076b9 100644 --- a/include/boost/algorithm/cxx11/is_partitioned.hpp +++ b/include/boost/algorithm/cxx11/is_partitioned.hpp @@ -18,7 +18,8 @@ namespace boost { namespace algorithm { /// \fn is_partitioned ( InputIterator first, InputIterator last, UnaryPredicate p ) -/// \brief Tests to see if a sequence is partitioned according to a predicate +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. /// /// \param first The start of the input sequence /// \param last One past the end of the input sequence @@ -39,7 +40,8 @@ bool is_partitioned ( InputIterator first, InputIterator last, UnaryPredicate p } /// \fn is_partitioned ( const Range &r, UnaryPredicate p ) -/// \brief Generates an increasing sequence of values, and stores them in the input Range. +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. /// /// \param r The input range /// \param p The predicate to test the values with diff --git a/include/boost/algorithm/is_partitioned_until.hpp b/include/boost/algorithm/is_partitioned_until.hpp new file mode 100644 index 0000000..42683e1 --- /dev/null +++ b/include/boost/algorithm/is_partitioned_until.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) Alexander Zaitsev , 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file is_partitioned_until.hpp +/// \brief Tell if a sequence is partitioned +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_IS_PARTITIONED_UNTIL_HPP +#define BOOST_ALGORITHM_IS_PARTITIONED_UNTIL_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_partitioned_until ( InputIterator first, InputIterator last, UnaryPredicate p ) +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p The predicate to test the values with +/// +/// \note Returns the first iterator 'it' in the sequence [first, last) for which is_partitioned(first, it, p) is false. +/// Returns last if the entire sequence is partitioned. +/// Complexity: O(N). +template +InputIterator is_partitioned_until ( InputIterator first, InputIterator last, UnaryPredicate p ) +{ +// Run through the part that satisfy the predicate + for ( ; first != last; ++first ) + if ( !p (*first)) + break; +// Now the part that does not satisfy the predicate + for ( ; first != last; ++first ) + if ( p (*first)) + return first; + return last; +} + +/// \fn is_partitioned_until ( const Range &r, UnaryPredicate p ) +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. +/// +/// \param r The input range +/// \param p The predicate to test the values with +/// +/// \note Returns the first iterator 'it' in the sequence [first, last) for which is_partitioned(first, it, p) is false. +/// Returns last if the entire sequence is partitioned. +/// Complexity: O(N). +template +typename boost::range_iterator::type is_partitioned_until ( const Range &r, UnaryPredicate p ) +{ + return boost::algorithm::is_partitioned_until (boost::begin(r), boost::end(r), p); +} + +}} + +#endif // BOOST_ALGORITHM_IS_PARTITIONED_UNTIL_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fb00843..fad1578 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -70,6 +70,9 @@ alias unit_test_framework # Is_palindrome tests [ run is_palindrome_test.cpp unit_test_framework : : : : is_palindrome_test ] + +# Is_partitioned_until tests + [ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ] ; } diff --git a/test/is_partitioned_until_test.cpp b/test/is_partitioned_until_test.cpp new file mode 100644 index 0000000..379c06e --- /dev/null +++ b/test/is_partitioned_until_test.cpp @@ -0,0 +1,63 @@ +/* + Copyright (c) Marshall Clow 2011-2012, Alexander Zaitsev , 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#include + +#include +#include + +#define BOOST_TEST_MAIN +#include + +#include +#include +#include + +namespace ba = boost::algorithm; +// namespace ba = boost; + +template +struct less_than { +public: + less_than ( T foo ) : val ( foo ) {} + less_than ( const less_than &rhs ) : val ( rhs.val ) {} + + bool operator () ( const T &v ) const { return v < val; } +private: + less_than (); + less_than operator = ( const less_than &rhs ); + T val; +}; + + +void test_sequence1 () { + std::vector v; + + v.clear (); + for ( int i = 5; i < 15; ++i ) + v.push_back ( i ); + BOOST_CHECK ( ba::is_partitioned_until ( v, less_than(3)) == v.end()); // no elements + BOOST_CHECK ( ba::is_partitioned_until ( v, less_than(6)) == v.end()); // only the first element + BOOST_CHECK ( ba::is_partitioned_until ( v, less_than(10)) == v.end()); // in the middle somewhere + BOOST_CHECK ( ba::is_partitioned_until ( v, less_than(99)) == v.end()); // all elements satisfy +// With bidirectional iterators. + std::list l; + for ( int i = 5; i < 15; ++i ) + l.push_back ( i ); + BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than(3)) == l.end()); // no elements + BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than(6)) == l.end()); // only the first element + BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than(10)) == l.end()); // in the middle somewhere + BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than(99)) == l.end()); // all elements satisfy +} + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test_sequence1 (); +}