Compare commits

...

29 Commits

Author SHA1 Message Date
daef6d41c5 C++17 algorithms 2017-06-28 20:13:38 -07:00
f14719c3a9 Replace an assert in a test with BOOST_CHECK 2017-06-28 10:04:25 -07:00
6bd8bc197a use boost::algorithm::iota in the tests instead of std::iota, which requires C++11 2017-06-28 07:58:21 -07:00
334737eebe Implement the C++17 new algorithms 2017-06-27 16:43:17 -07:00
055075aa61 Bug fixes and is_partititioned_XXX for the 1.65.0 release 2017-06-14 18:49:39 -07:00
d6b7f3da90 Use boost::begin/end instead of macros 2017-05-03 22:38:21 -07:00
0e62dfb92e Merge pull request #33 from ZaMaZaN4iK/feature_branch/is_partitioned_until
is_partitioned_until support
2017-05-03 18:15:09 -07:00
f250014931 Merge pull request #38 from DanielaE/fix/narrowing
fix narrowing conversions
2017-05-03 18:14:28 -07:00
56d88410c6 fix narrowing conversions
Signed-off-by: Daniela Engert <dani@ngrt.de>
2017-04-22 18:35:17 +02:00
5d76dab9b8 Merge remote-tracking branch 'refs/remotes/origin/feature_branch/is_partitioned_until'
Conflicts:
	README.md
2017-02-22 01:26:16 +03:00
6f34145390 Removed empty README.md, fixed docs 2017-02-22 01:25:38 +03:00
a446ef0758 Cleaned README 2017-02-15 00:11:10 +03:00
383e800df9 Added examples, tests, doc 2017-02-14 15:59:07 +03:00
a838feb81a Added is_partitioned_until
* Fixed doxygen comment in is_partitioned algorithm.
2017-02-14 12:22:49 +03:00
17d4f70e97 Merge pull request #32 from jhunold/extra_semi
Remove trailing ";" - thanks!
2017-01-06 18:19:59 -08:00
d22c60c2d4 Remove trailing ";"
clang warning: extra ';' after member function definition [-Wextra-semi]
2017-01-06 09:59:12 +01:00
037fe4e33d Merge pull request #31 from danieljames/fix-algorithm-location
Build the algorithm documentation standalone.
2016-12-13 19:30:52 -08:00
25d54bd1e8 Build the algorithm documentation standalone. 2016-12-13 21:38:40 +00:00
e442420d49 Change name of (another) parameter; fixes 'shadowing' warning (Trac #12623) 2016-11-25 20:50:53 -08:00
42db8a4403 Change name of parameter; fixes 'shadowing' warning (Trac #12623) 2016-11-25 08:11:01 -08:00
9b19fc00c2 use std::shuffle instead of random_shuffle in C++11 and later 2016-11-20 17:24:19 -08:00
7977bd0cdc Remove all mentions of (unary|binary)_function; not needed and they have been removed for C++17 2016-11-20 17:02:49 -08:00
efd7a8b544 Updated the docs for the searchers to reflect the new interface, and added rationale for the change. 2016-10-26 11:22:37 -07:00
8dfebc4580 Added README.md 2016-10-25 14:31:26 +03:00
6a650ade1d Merge pull request #28 from ZaMaZaN4iK/feature_branch/is_palindromic
Delete duplicate version is_palindrome
2016-10-12 16:42:14 -07:00
303ff13b86 Delete duplicate version os is_palindrome 2016-10-12 22:22:30 +03:00
d029402f05 Add, and update, documentation build targets. 2016-10-10 11:24:26 -05:00
eccac19108 Add, and update, documentation build targets. 2016-10-07 23:03:40 -05:00
8627d02f20 Merge pull request #2 from boostorg/develop
Sync develop branch with master
2016-08-19 21:44:27 +03:00
42 changed files with 1793 additions and 97 deletions

View File

@ -16,17 +16,17 @@ using quickbook ;
using doxygen ;
using boostbook ;
doxygen autodoc
:
[ glob ../../../boost/algorithm/*.hpp
doxygen autodoc
:
[ glob ../../../boost/algorithm/*.hpp
../../../boost/algorithm/searching/*.hpp
../../../boost/algorithm/cxx11/*.hpp
../../../boost/algorithm/cxx14/*.hpp
]
:
:
<doxygen:param>"PREDEFINED=\"BOOST_ALGORITHM_DOXYGEN=1\""
<doxygen:param>WARNINGS=YES # Default NO, but useful to see warnings, especially in a logfile.
;
;
xml algorithm : algorithm.qbk ;
@ -35,7 +35,7 @@ boostbook standalone
:
algorithm
:
<dependency>autodoc
<dependency>autodoc
<xsl:param>boost.root=../../../..
<xsl:param>"boost.doxygen.reftitle=Boost.Algorithms C++ Reference"
<xsl:param>chapter.autolabel=0
@ -44,3 +44,13 @@ boostbook standalone
<xsl:param>toc.max.depth=2
<xsl:param>generate.section.toc.level=1
;
###############################################################################
alias boostdoc
: ../string/doc/string_algo.xml
:
: <dependency>../string/doc//autodoc
: ;
explicit boostdoc ;
alias boostrelease : standalone ;
explicit boostrelease ;

View File

@ -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]

View File

@ -37,7 +37,7 @@ public:
~boyer_moore ();
template <typename corpusIter>
corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last );
pair<corpusIter, corpusIter> operator () ( corpusIter corpus_first, corpusIter corpus_last );
};
``
@ -45,14 +45,28 @@ and here is the corresponding procedural interface:
``
template <typename patIter, typename corpusIter>
corpusIter boyer_moore_search (
pair<corpusIter, corpusIter> boyer_moore_search (
corpusIter corpus_first, corpusIter corpus_last,
patIter pat_first, patIter pat_last );
``
Each of the functions is passed two pairs of iterators. The first two define the corpus and the second two define the pattern. Note that the two pairs need not be of the same type, but they do need to "point" at the same type. In other words, `patIter::value_type` and `curpusIter::value_type` need to be the same type.
The return value of the function is an iterator pointing to the start of the pattern in the corpus. If the pattern is not found, it returns the end of the corpus (`corpus_last`).
The return value of the function is a pair of iterators pointing to the position of the pattern in the corpus. If the pattern is empty, it returns at empty range at the start of the corpus (`corpus_first`, `corpus_first`). If the pattern is not found, it returns at empty range at the end of the corpus (`corpus_last`, `corpus_last`).
[heading Compatibility Note]
Earlier versions of this searcher returned only a single iterator. As explained in [@https://cplusplusmusings.wordpress.com/2016/02/01/sometimes-you-get-things-wrong/], this was a suboptimal interface choice, and has been changed, starting in the 1.62.0 release. Old code that is expecting a single iterator return value can be updated by replacing the return value of the searcher's `operator ()` with the `.first` field of the pair.
Instead of:
``
iterator foo = searcher(a, b);
``
you now write:
``
iterator foo = searcher(a, b).first;
``
[heading Performance]

View File

@ -35,7 +35,7 @@ public:
~boyer_moore_horspool ();
template <typename corpusIter>
corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last );
pair<corpusIter, corpusIter> operator () ( corpusIter corpus_first, corpusIter corpus_last );
};
``
@ -43,14 +43,28 @@ and here is the corresponding procedural interface:
``
template <typename patIter, typename corpusIter>
corpusIter boyer_moore_horspool_search (
pair<corpusIter, corpusIter> boyer_moore_horspool_search (
corpusIter corpus_first, corpusIter corpus_last,
patIter pat_first, patIter pat_last );
``
Each of the functions is passed two pairs of iterators. The first two define the corpus and the second two define the pattern. Note that the two pairs need not be of the same type, but they do need to "point" at the same type. In other words, `patIter::value_type` and `curpusIter::value_type` need to be the same type.
The return value of the function is an iterator pointing to the start of the pattern in the corpus. If the pattern is not found, it returns the end of the corpus (`corpus_last`).
The return value of the function is a pair of iterators pointing to the position of the pattern in the corpus. If the pattern is empty, it returns at empty range at the start of the corpus (`corpus_first`, `corpus_first`). If the pattern is not found, it returns at empty range at the end of the corpus (`corpus_last`, `corpus_last`).
[heading Compatibility Note]
Earlier versions of this searcher returned only a single iterator. As explained in [@https://cplusplusmusings.wordpress.com/2016/02/01/sometimes-you-get-things-wrong/], this was a suboptimal interface choice, and has been changed, starting in the 1.62.0 release. Old code that is expecting a single iterator return value can be updated by replacing the return value of the searcher's `operator ()` with the `.first` field of the pair.
Instead of:
``
iterator foo = searcher(a, b);
``
you now write:
``
iterator foo = searcher(a, b).first;
``
[heading Performance]

View File

@ -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]

View File

@ -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<typename InputIterator, typename Predicate>
InputIterator is_partitioned_until ( InputIterator first, InputIterator last, Predicate p );
template<typename Range, typename Predicate>
typename boost::range_iterator<const Range>::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).
]

View File

@ -39,7 +39,7 @@ public:
~knuth_morris_pratt ();
template <typename corpusIter>
corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last );
pair<corpusIter, corpusIter> operator () ( corpusIter corpus_first, corpusIter corpus_last );
};
``
@ -47,15 +47,28 @@ and here is the corresponding procedural interface:
``
template <typename patIter, typename corpusIter>
corpusIter knuth_morris_pratt_search (
pair<corpusIter, corpusIter> knuth_morris_pratt_search (
corpusIter corpus_first, corpusIter corpus_last,
patIter pat_first, patIter pat_last );
``
Each of the functions is passed two pairs of iterators. The first two define the corpus and the second two define the pattern. Note that the two pairs need not be of the same type, but they do need to "point" at the same type. In other words, `patIter::value_type` and `curpusIter::value_type` need to be the same type.
The return value of the function is an iterator pointing to the start of the pattern in the corpus. If the pattern is not found, it returns the end of the corpus (`corpus_last`).
The return value of the function is a pair of iterators pointing to the position of the pattern in the corpus. If the pattern is empty, it returns at empty range at the start of the corpus (`corpus_first`, `corpus_first`). If the pattern is not found, it returns at empty range at the end of the corpus (`corpus_last`, `corpus_last`).
[heading Compatibility Note]
Earlier versions of this searcher returned only a single iterator. As explained in [@https://cplusplusmusings.wordpress.com/2016/02/01/sometimes-you-get-things-wrong/], this was a suboptimal interface choice, and has been changed, starting in the 1.62.0 release. Old code that is expecting a single iterator return value can be updated by replacing the return value of the searcher's `operator ()` with the `.first` field of the pair.
Instead of:
``
iterator foo = searcher(a, b);
``
you now write:
``
iterator foo = searcher(a, b).first;
``
[heading Performance]
The execution time of the Knuth-Morris-Pratt algorithm is linear in the size of the string being searched. Generally the algorithm gets faster as the pattern being searched for becomes longer. Its efficiency derives from the fact that with each unsuccessful attempt to find a match between the search string and the text it is searching, it uses the information gained from that attempt to rule out as many positions of the text as possible where the string cannot match.

View File

@ -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;

View File

@ -0,0 +1,70 @@
/*
Copyright (c) Alexander Zaitsev <zamazan4ik@gmail.by>, 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 <vector>
#include <functional>
#include <iostream>
#include <boost/algorithm/is_partitioned_until.hpp>
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<int> good({1, 2, 4});
std::vector<int> 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;
}

View File

@ -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

View File

@ -13,7 +13,6 @@
#define BOOST_ALGORITHM_EQUAL_HPP
#include <algorithm> // for std::equal
#include <functional> // for std::binary_function
#include <iterator>
namespace boost { namespace algorithm {
@ -21,7 +20,7 @@ namespace boost { namespace algorithm {
namespace detail {
template <class T1, class T2>
struct eq : public std::binary_function<T1, T2, bool> {
struct eq {
bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;}
};

View File

@ -0,0 +1,52 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file exclusive_scan.hpp
/// \brief ???
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_EXCLUSIVE_SCAN_HPP
#define BOOST_ALGORITHM_EXCLUSIVE_SCAN_HPP
#include <functional> // for std::plus
#include <iterator> // for std::iterator_traits
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
namespace boost { namespace algorithm {
template<class InputIterator, class OutputIterator, class T, class BinaryOperation>
OutputIterator exclusive_scan(InputIterator first, InputIterator last,
OutputIterator result, T init, BinaryOperation bOp)
{
if (first != last)
{
T saved = init;
do
{
init = bOp(init, *first);
*result = saved;
saved = init;
++result;
} while (++first != last);
}
return result;
}
template<class InputIterator, class OutputIterator, class T>
OutputIterator exclusive_scan(InputIterator first, InputIterator last,
OutputIterator result, T init)
{
typedef typename std::iterator_traits<InputIterator>::value_type VT;
return exclusive_scan(first, last, result, init, std::plus<VT>());
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_EXCLUSIVE_SCAN_HPP

View File

@ -0,0 +1,37 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file for_each_n.hpp
/// \brief Apply a functor to the elements of a sequence
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_FOR_EACH_N_HPP
#define BOOST_ALGORITHM_FOR_EACH_N_HPP
#include <utility> // for std::pair
namespace boost { namespace algorithm {
/// \fn for_each_n(InputIterator first, Size n, Function f);
/// \return first + n
///
/// \param first The start of the first range.
/// \param n One past the end of the first range.
/// \param f A functor to apply to the elements of the sequence
/// \note If f returns a result, the result is ignored.
template<class InputIterator, class Size, class Function>
InputIterator for_each_n(InputIterator first, Size n, Function f)
{
for ( ; n > 0; --n, ++first )
f(*first);
return first;
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_FOR_EACH_N_HPP

View File

@ -0,0 +1,60 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file transform_reduce.hpp
/// \brief Combine the (transformed) elements of a sequence (or two) into a single value.
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP
#define BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP
#include <functional> // for std::plus
#include <iterator> // for std::iterator_traits
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
namespace boost { namespace algorithm {
template<class InputIterator, class OutputIterator, class T, class BinaryOperation>
OutputIterator inclusive_scan(InputIterator first, InputIterator last,
OutputIterator result, BinaryOperation bOp, T init)
{
for (; first != last; ++first, (void) ++result) {
init = bOp(init, *first);
*result = init;
}
return result;
}
template<class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator inclusive_scan(InputIterator first, InputIterator last,
OutputIterator result, BinaryOperation bOp)
{
if (first != last) {
typename std::iterator_traits<InputIterator>::value_type init = *first;
*result++ = init;
if (++first != last)
return inclusive_scan(first, last, result, bOp, init);
}
return result;
}
template<class InputIterator, class OutputIterator>
OutputIterator inclusive_scan(InputIterator first, InputIterator last,
OutputIterator result)
{
typedef typename std::iterator_traits<InputIterator>::value_type VT;
return inclusive_scan(first, last, result, std::plus<VT>());
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP

View File

@ -0,0 +1,72 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file reduce.hpp
/// \brief Combine the elements of a sequence into a single value
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_REDUCE_HPP
#define BOOST_ALGORITHM_REDUCE_HPP
#include <functional> // for std::plus
#include <iterator> // for std::iterator_traits
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
namespace boost { namespace algorithm {
template<class InputIterator, class T, class BinaryOperation>
T reduce(InputIterator first, InputIterator last, T init, BinaryOperation bOp)
{
;
for (; first != last; ++first)
init = bOp(init, *first);
return init;
}
template<class InputIterator, class T>
T reduce(InputIterator first, InputIterator last, T init)
{
typedef typename std::iterator_traits<InputIterator>::value_type VT;
return reduce(first, last, init, std::plus<VT>());
}
template<class InputIterator>
typename std::iterator_traits<InputIterator>::value_type
reduce(InputIterator first, InputIterator last)
{
return reduce(first, last,
typename std::iterator_traits<InputIterator>::value_type());
}
template<class Range>
typename boost::range_value<Range>::type
reduce(const Range &r)
{
return reduce(boost::begin(r), boost::end(r));
}
// Not sure that this won't be ambiguous (1)
template<class Range, class T>
T reduce(const Range &r, T init)
{
return reduce(boost::begin (r), boost::end (r), init);
}
// Not sure that this won't be ambiguous (2)
template<class Range, class T, class BinaryOperation>
T reduce(const Range &r, T init, BinaryOperation bOp)
{
return reduce(boost::begin(r), boost::end(r), init, bOp);
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_REDUCE_HPP

View File

@ -0,0 +1,46 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file transform_exclusive_scan.hpp
/// \brief ????
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_TRANSFORM_EXCLUSIVE_SCAN_HPP
#define BOOST_ALGORITHM_TRANSFORM_EXCLUSIVE_SCAN_HPP
#include <functional> // for std::plus
#include <iterator> // for std::iterator_traits
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
namespace boost { namespace algorithm {
template<class InputIterator, class OutputIterator, class T,
class BinaryOperation, class UnaryOperation>
OutputIterator transform_exclusive_scan(InputIterator first, InputIterator last,
OutputIterator result, T init,
BinaryOperation bOp, UnaryOperation uOp)
{
if (first != last)
{
T saved = init;
do
{
init = bOp(init, uOp(*first));
*result = saved;
saved = init;
++result;
} while (++first != last);
}
return result;
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_TRANSFORM_EXCLUSIVE_SCAN_HPP

View File

@ -0,0 +1,58 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file transform_reduce.hpp
/// \brief Combine the (transformed) elements of a sequence (or two) into a single value.
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP
#define BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP
#include <functional> // for std::plus
#include <iterator> // for std::iterator_traits
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
namespace boost { namespace algorithm {
template<class InputIterator, class OutputIterator,
class BinaryOperation, class UnaryOperation, class T>
OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last,
OutputIterator result,
BinaryOperation bOp, UnaryOperation uOp,
T init)
{
for (; first != last; ++first, (void) ++result) {
init = bOp(init, uOp(*first));
*result = init;
}
return result;
}
template<class InputIterator, class OutputIterator,
class BinaryOperation, class UnaryOperation>
OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last,
OutputIterator result,
BinaryOperation bOp, UnaryOperation uOp)
{
if (first != last) {
typename std::iterator_traits<InputIterator>::value_type init = uOp(*first);
*result++ = init;
if (++first != last)
return transform_inclusive_scan(first, last, result, bOp, uOp, init);
}
return result;
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP

View File

@ -0,0 +1,55 @@
/*
Copyright (c) Marshall Clow 2017.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
/// \file transform_reduce.hpp
/// \brief Combine the (transformed) elements of a sequence (or two) into a single value.
/// \author Marshall Clow
#ifndef BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP
#define BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP
#include <functional> // for std::plus
#include <iterator> // for std::iterator_traits
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
namespace boost { namespace algorithm {
template<class InputIterator1, class InputIterator2, class T,
class BinaryOperation1, class BinaryOperation2>
T transform_reduce(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, T init,
BinaryOperation1 bOp1, BinaryOperation2 bOp2)
{
for (; first1 != last1; ++first1, (void) ++first2)
init = bOp1(init, bOp2(*first1, *first2));
return init;
}
template<class InputIterator, class T,
class BinaryOperation, class UnaryOperation>
T transform_reduce(InputIterator first, InputIterator last,
T init, BinaryOperation bOp, UnaryOperation uOp)
{
for (; first != last; ++first)
init = bOp(init, uOp(*first));
return init;
}
template<class InputIterator1, class InputIterator2, class T>
T transform_reduce(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, T init)
{
return transform_reduce(first1, last1, first2, init,
std::plus<T>(), std::multiplies<T>());
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP

View File

@ -73,7 +73,7 @@ namespace detail {
else if ( c >= 'A' && c <= 'F' ) retval = c - 'A' + 10;
else if ( c >= 'a' && c <= 'f' ) retval = c - 'a' + 10;
else BOOST_THROW_EXCEPTION (non_hex_input() << bad_char (c));
return retval;
return static_cast<char>(retval);
}
// My own iterator_traits class.

View File

@ -35,7 +35,7 @@ namespace boost { namespace algorithm {
/// For other sequences function will return false.
/// Complexity: O(N).
template <typename BidirectionalIterator, typename Predicate>
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p )
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p)
{
if(begin == end)
{
@ -63,7 +63,7 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi
/// \return true if the entire sequence is palindrome
///
/// \param begin The start of the input sequence
/// \param end One past the end of the input sequence
/// \param end One past the end of the input sequence
///
/// \note This function will return true for empty sequences and for palindromes.
/// For other sequences function will return false.
@ -71,26 +71,8 @@ bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predi
template <typename BidirectionalIterator>
bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end)
{
if(begin == end)
{
return true;
}
--end;
while(begin != end)
{
if(!(*begin == *end))
{
return false;
}
++begin;
if(begin == end)
{
break;
}
--end;
}
return true;
return is_palindrome(begin, end,
std::equal_to<typename std::iterator_traits<BidirectionalIterator>::value_type> ());
}
/// \fn is_palindrome ( const R& range )
@ -122,7 +104,6 @@ bool is_palindrome(const R& range, Predicate p)
return is_palindrome(boost::begin(range), boost::end(range), p);
}
/// \fn is_palindrome ( const char* str )
/// \return true if the entire sequence is palindrome
///
@ -138,7 +119,6 @@ bool is_palindrome(const char* str)
return is_palindrome(str, str + strlen(str));
}
/// \fn is_palindrome ( const char* str, Predicate p )
/// \return true if the entire sequence is palindrome
///
@ -155,7 +135,6 @@ bool is_palindrome(const char* str, Predicate p)
return true;
return is_palindrome(str, str + strlen(str), p);
}
}}
#endif // BOOST_ALGORITHM_IS_PALINDROME_HPP

View File

@ -0,0 +1,63 @@
/*
Copyright (c) Alexander Zaitsev <zamazan4ik@gmail.by>, 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 <boost/range/begin.hpp>
#include <boost/range/end.hpp>
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 <typename InputIterator, typename UnaryPredicate>
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 Range, typename UnaryPredicate>
typename boost::range_iterator<const Range>::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

View File

@ -152,8 +152,8 @@ Requirements:
template<typename Iter, typename Container>
void compute_bm_prefix ( Iter pat_first, Iter pat_last, Container &prefix ) {
const std::size_t count = std::distance ( pat_first, pat_last );
void compute_bm_prefix ( Iter first, Iter last, Container &prefix ) {
const std::size_t count = std::distance ( first, last );
BOOST_ASSERT ( count > 0 );
BOOST_ASSERT ( prefix.size () == count );
@ -161,26 +161,26 @@ Requirements:
std::size_t k = 0;
for ( std::size_t i = 1; i < count; ++i ) {
BOOST_ASSERT ( k < count );
while ( k > 0 && ( pat_first[k] != pat_first[i] )) {
while ( k > 0 && ( first[k] != first[i] )) {
BOOST_ASSERT ( k < count );
k = prefix [ k - 1 ];
}
if ( pat_first[k] == pat_first[i] )
if ( first[k] == first[i] )
k++;
prefix [ i ] = k;
}
}
void build_suffix_table ( patIter pat_first, patIter pat_last ) {
const std::size_t count = (std::size_t) std::distance ( pat_first, pat_last );
void build_suffix_table ( patIter first, patIter last ) {
const std::size_t count = (std::size_t) std::distance ( first, last );
if ( count > 0 ) { // empty pattern
std::vector<typename std::iterator_traits<patIter>::value_type> reversed(count);
(void) std::reverse_copy ( pat_first, pat_last, reversed.begin ());
(void) std::reverse_copy ( first, last, reversed.begin ());
std::vector<difference_type> prefix (count);
compute_bm_prefix ( pat_first, pat_last, prefix );
compute_bm_prefix ( first, last, prefix );
std::vector<difference_type> prefix_reversed (count);
compute_bm_prefix ( reversed.begin (), reversed.end (), prefix_reversed );

View File

@ -155,9 +155,9 @@ namespace boost { namespace algorithm {
void preKmp ( patIter first, patIter last ) {
const /*std::size_t*/ int count = std::distance ( first, last );
const difference_type count = std::distance ( first, last );
int i, j;
difference_type i, j;
i = 0;
j = skip_[0] = -1;
@ -177,7 +177,7 @@ namespace boost { namespace algorithm {
void init_skip_table ( patIter first, patIter last ) {
const difference_type count = std::distance ( first, last );
int j;
difference_type j;
skip_ [ 0 ] = -1;
for ( int i = 1; i <= count; ++i ) {
j = skip_ [ i - 1 ];

View File

@ -30,8 +30,10 @@ namespace boost {
// a tolower functor
template<typename CharT>
struct to_lowerF : public std::unary_function<CharT, CharT>
struct to_lowerF
{
typedef CharT argument_type;
typedef CharT result_type;
// Constructor
to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {}
@ -50,8 +52,10 @@ namespace boost {
// a toupper functor
template<typename CharT>
struct to_upperF : public std::unary_function<CharT, CharT>
struct to_upperF
{
typedef CharT argument_type;
typedef CharT result_type;
// Constructor
to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {}

View File

@ -40,7 +40,7 @@ namespace boost {
// Protected construction/destruction
// Default constructor
find_iterator_base() {};
find_iterator_base() {}
// Copy construction
find_iterator_base( const find_iterator_base& Other ) :
m_Finder(Other.m_Finder) {}

View File

@ -89,9 +89,10 @@ namespace boost {
template<
typename SeqT,
typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator >
struct copy_iterator_rangeF :
public std::unary_function< iterator_range<IteratorT>, SeqT >
struct copy_iterator_rangeF
{
typedef iterator_range<IteratorT> argument_type;
typedef SeqT result_type;
SeqT operator()( const iterator_range<IteratorT>& Range ) const
{
return copy_range<SeqT>(Range);

View File

@ -12,7 +12,7 @@ import testing ;
alias unit_test_framework
: # sources
/boost//unit_test_framework
;
;
{
@ -31,13 +31,13 @@ alias unit_test_framework
[ run clamp_test.cpp unit_test_framework : : : : clamp_test ]
[ run power_test.cpp unit_test_framework : : : : power_test ]
[ compile-fail power_fail1.cpp : : : : ]
# Cxx11 tests
[ run all_of_test.cpp unit_test_framework : : : : all_of_test ]
[ run any_of_test.cpp unit_test_framework : : : : any_of_test ]
[ run none_of_test.cpp unit_test_framework : : : : none_of_test ]
[ run one_of_test.cpp unit_test_framework : : : : one_of_test ]
[ run ordered_test.cpp unit_test_framework : : : : ordered_test ]
[ run find_if_not_test1.cpp unit_test_framework : : : : find_if_not_test1 ]
[ run copy_if_test1.cpp unit_test_framework : : : : copy_if_test1 ]
@ -53,6 +53,16 @@ alias unit_test_framework
[ run equal_test.cpp unit_test_framework : : : : equal_test ]
[ run mismatch_test.cpp unit_test_framework : : : : mismatch_test ]
# Cxx17 tests
[ run for_each_n_test.cpp unit_test_framework : : : : for_each_n_test ]
[ run reduce_test.cpp unit_test_framework : : : : reduce_test ]
[ run transform_reduce_test.cpp unit_test_framework : : : : transform_reduce_test ]
[ run inclusive_scan_test.cpp unit_test_framework : : : : inclusive_scan_test ]
[ run exclusive_scan_test.cpp unit_test_framework : : : : exclusive_scan_test ]
[ run transform_inclusive_scan_test.cpp unit_test_framework : : : : transform_inclusive_scan_test ]
[ run transform_exclusive_scan_test.cpp unit_test_framework : : : : transform_exclusive_scan_test ]
# Maybe GCD and LCM as well
# Hex tests
[ run hex_test1.cpp unit_test_framework : : : : hex_test1 ]
[ run hex_test2.cpp unit_test_framework : : : : hex_test2 ]
@ -70,6 +80,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 ]
;
}

View File

@ -18,7 +18,7 @@
#include <list>
template<typename T>
struct is_ : public std::unary_function<T, bool> {
struct is_ {
is_ ( T v ) : val_ ( v ) {}
~is_ () {}
bool operator () ( T comp ) const { return val_ == comp; }

View File

@ -18,7 +18,7 @@
#include <list>
template<typename T>
struct is_ : public std::unary_function<T, bool> {
struct is_ {
is_ ( T v ) : val_ ( v ) {}
~is_ () {}
bool operator () ( T comp ) const { return val_ == comp; }

View File

@ -0,0 +1,72 @@
/*
Copyright (c) Marshall Clow 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 <vector>
#include <functional>
#include <numeric>
#include <algorithm>
#include <boost/config.hpp>
#include <boost/algorithm/cxx11/iota.hpp>
#include <boost/algorithm/cxx17/exclusive_scan.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
int triangle(int n) { return n*(n+1)/2; }
void basic_tests_init()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::exclusive_scan(v.begin(), v.end(), v.begin(), 50);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 50 + (int) i * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::exclusive_scan(v.begin(), v.end(), v.begin(), 30);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 30 + triangle(i-1));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::exclusive_scan(v.begin(), v.end(), v.begin(), 40);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 40 + triangle(i));
}
}
void test_exclusive_scan_init()
{
basic_tests_init();
}
void test_exclusive_scan_init_op()
{
BOOST_CHECK(true);
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_exclusive_scan_init();
test_exclusive_scan_init_op();
}

66
test/for_each_n_test.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
Copyright (c) Marshall Clow 2013.
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 <boost/config.hpp>
#include <boost/algorithm/cxx17/for_each_n.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
struct for_each_test
{
for_each_test() {}
static int count;
void operator()(int& i) {++i; ++count;}
};
int for_each_test::count = 0;
void test_for_each_n ()
{
typedef input_iterator<int*> Iter;
int ia[] = {0, 1, 2, 3, 4, 5};
const unsigned s = sizeof(ia)/sizeof(ia[0]);
{
for_each_test::count = 0;
Iter it = ba::for_each_n(Iter(ia), 0, for_each_test());
BOOST_CHECK(it == Iter(ia));
BOOST_CHECK(for_each_test::count == 0);
}
{
for_each_test::count = 0;
Iter it = ba::for_each_n(Iter(ia), s, for_each_test());
BOOST_CHECK(it == Iter(ia+s));
BOOST_CHECK(for_each_test::count == s);
for (unsigned i = 0; i < s; ++i)
BOOST_CHECK(ia[i] == static_cast<int>(i+1));
}
{
for_each_test::count = 0;
Iter it = ba::for_each_n(Iter(ia), 1, for_each_test());
BOOST_CHECK(it == Iter(ia+1));
BOOST_CHECK(for_each_test::count == 1);
for (unsigned i = 0; i < 1; ++i)
BOOST_CHECK(ia[i] == static_cast<int>(i+2));
}
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_for_each_n ();
}

View File

@ -0,0 +1,153 @@
/*
Copyright (c) Marshall Clow 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 <vector>
#include <functional>
#include <numeric>
#include <algorithm>
#include <boost/config.hpp>
#include <boost/algorithm/cxx11/iota.hpp>
#include <boost/algorithm/cxx17/inclusive_scan.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
int triangle(int n) { return n*(n+1)/2; }
void basic_tests_op()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>());
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == (int)(i+1) * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>());
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == triangle(i));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>());
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == triangle(i + 1));
}
{
std::vector<int> v, res;
ba::inclusive_scan(v.begin(), v.end(), std::back_inserter(res), std::plus<int>());
assert(res.empty());
}
}
void test_inclusive_scan_op()
{
basic_tests_op();
BOOST_CHECK(true);
}
void basic_tests_init()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), 50);
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == 50 + (int)(i+1) * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), 40);
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == 40 + triangle(i));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), 30);
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == 30 + triangle(i + 1));
}
{
std::vector<int> v, res;
ba::inclusive_scan(v.begin(), v.end(), std::back_inserter(res), std::plus<int>(), 40);
assert(res.empty());
}
}
void test_inclusive_scan_init()
{
basic_tests_init();
BOOST_CHECK(true);
}
void basic_tests_op_init()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), 50);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 50 + (int)(i+1) * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), 40);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 40 + triangle(i));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), 30);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 30 + triangle(i + 1));
}
{
std::vector<int> v, res;
ba::inclusive_scan(v.begin(), v.end(), std::back_inserter(res), std::plus<int>(), 40);
BOOST_CHECK(res.empty());
}
}
void test_inclusive_scan_op_init()
{
basic_tests_op_init();
BOOST_CHECK(true);
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_inclusive_scan_op();
test_inclusive_scan_init();
test_inclusive_scan_op_init();
}

View File

@ -38,9 +38,6 @@ struct functorComparator
}
};
#define Begin(arr) (arr)
#define End(arr) (arr+(sizeof(arr)/(sizeof(arr[0]))))
void test_is_palindrome()
{
const std::list<int> empty;
@ -54,14 +51,14 @@ void test_is_palindrome()
// Test a default operator==
BOOST_CHECK ( ba::is_palindrome(empty));
BOOST_CHECK ( ba::is_palindrome(singleElement));
BOOST_CHECK (!ba::is_palindrome(Begin(oddNonPalindrome), End(oddNonPalindrome)));
BOOST_CHECK ( ba::is_palindrome(Begin(oddPalindrome), End(oddPalindrome)));
BOOST_CHECK ( ba::is_palindrome(Begin(evenPalindrome), End(evenPalindrome)));
BOOST_CHECK (!ba::is_palindrome(Begin(evenNonPalindrome), End(evenNonPalindrome)));
BOOST_CHECK (!ba::is_palindrome(boost::begin(oddNonPalindrome), boost::end(oddNonPalindrome)));
BOOST_CHECK ( ba::is_palindrome(boost::begin(oddPalindrome), boost::end(oddPalindrome)));
BOOST_CHECK ( ba::is_palindrome(boost::begin(evenPalindrome), boost::end(evenPalindrome)));
BOOST_CHECK (!ba::is_palindrome(boost::begin(evenNonPalindrome), boost::end(evenNonPalindrome)));
//Test the custom comparators
BOOST_CHECK ( ba::is_palindrome(empty.begin(), empty.end(), functorComparator()));
BOOST_CHECK (!ba::is_palindrome(Begin(oddNonPalindrome), End(oddNonPalindrome), funcComparator<int>));
BOOST_CHECK (!ba::is_palindrome(boost::begin(oddNonPalindrome), boost::end(oddNonPalindrome), funcComparator<int>));
BOOST_CHECK ( ba::is_palindrome(evenPalindrome, std::equal_to<int>()));
//Test C-strings like cases

View File

@ -0,0 +1,63 @@
/*
Copyright (c) Marshall Clow 2011-2012, Alexander Zaitsev <zamazan4ik@gmail.com>, 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 <iostream>
#include <boost/config.hpp>
#include <boost/algorithm/is_partitioned_until.hpp>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <string>
#include <vector>
#include <list>
namespace ba = boost::algorithm;
// namespace ba = boost;
template <typename T>
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<int> v;
v.clear ();
for ( int i = 5; i < 15; ++i )
v.push_back ( i );
BOOST_CHECK ( ba::is_partitioned_until ( v, less_than<int>(3)) == v.end()); // no elements
BOOST_CHECK ( ba::is_partitioned_until ( v, less_than<int>(6)) == v.end()); // only the first element
BOOST_CHECK ( ba::is_partitioned_until ( v, less_than<int>(10)) == v.end()); // in the middle somewhere
BOOST_CHECK ( ba::is_partitioned_until ( v, less_than<int>(99)) == v.end()); // all elements satisfy
// With bidirectional iterators.
std::list<int> l;
for ( int i = 5; i < 15; ++i )
l.push_back ( i );
BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than<int>(3)) == l.end()); // no elements
BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than<int>(6)) == l.end()); // only the first element
BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than<int>(10)) == l.end()); // in the middle somewhere
BOOST_CHECK ( ba::is_partitioned_until ( l.begin (), l.end (), less_than<int>(99)) == l.end()); // all elements satisfy
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_sequence1 ();
}

View File

@ -18,7 +18,7 @@
#include <list>
template<typename T>
struct is_ : public std::unary_function<T, bool> {
struct is_ {
is_ ( T v ) : val_ ( v ) {}
~is_ () {}
bool operator () ( T comp ) const { return val_ == comp; }

View File

@ -18,7 +18,7 @@
#include <list>
template<typename T>
struct is_ : public std::unary_function<T, bool> {
struct is_ {
is_ ( T v ) : val_ ( v ) {}
~is_ () {}
bool operator () ( T comp ) const { return val_ == comp; }

View File

@ -7,6 +7,20 @@
#include <vector>
#include <iostream>
#if __cplusplus >= 201103L
#include <random>
std::default_random_engine gen;
template<typename RandomIt>
void do_shuffle(RandomIt first, RandomIt last)
{ std::shuffle(first, last, gen); }
#else
template<typename RandomIt>
void do_shuffle(RandomIt first, RandomIt last)
{ std::random_shuffle(first, last); }
#endif
namespace ba = boost::algorithm;
template <typename Iter>
@ -72,14 +86,14 @@ BOOST_AUTO_TEST_CASE( test_main )
// BOOST_CHECK_EQUAL(v[5], 5);
// Mix them up and try again - single element
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b + 7, b + 8);
check_sequence (b, v.end(), b + 7, b + 8);
// BOOST_CHECK_EQUAL(v[7], 7);
// Mix them up and try again - at the end
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b + 7, v.end());
check_sequence (b, v.end(), b + 7, v.end());
@ -88,7 +102,7 @@ BOOST_AUTO_TEST_CASE( test_main )
// BOOST_CHECK_EQUAL(v[9], 9);
// Mix them up and try again - at the beginning
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b, b + 2);
check_sequence (b, v.end(), b, b + 2);
@ -96,12 +110,12 @@ BOOST_AUTO_TEST_CASE( test_main )
// BOOST_CHECK_EQUAL(v[1], 1);
// Mix them up and try again - empty subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b, b);
check_sequence (b, v.end(), b, b);
// Mix them up and try again - entire subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b, v.end());
check_sequence (b, v.end(), b, v.end());
}
@ -120,14 +134,14 @@ BOOST_AUTO_TEST_CASE( test_main )
// BOOST_CHECK_EQUAL(v[5], 4);
// Mix them up and try again - single element
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b + 7, b + 8, std::greater<int>());
check_sequence (b, v.end(), b + 7, b + 8, std::greater<int>());
// BOOST_CHECK_EQUAL(v[7], 2);
// Mix them up and try again - at the end
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b + 7, v.end(), std::greater<int>());
check_sequence (b, v.end(), b + 7, v.end(), std::greater<int>());
@ -136,7 +150,7 @@ BOOST_AUTO_TEST_CASE( test_main )
// BOOST_CHECK_EQUAL(v[9], 0);
// Mix them up and try again - at the beginning
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b, b + 2, std::greater<int>());
check_sequence (b, v.end(), b, b + 2, std::greater<int>());
@ -144,12 +158,12 @@ BOOST_AUTO_TEST_CASE( test_main )
// BOOST_CHECK_EQUAL(v[1], 8);
// Mix them up and try again - empty subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b, b, std::greater<int>());
check_sequence (b, v.end(), b, b, std::greater<int>());
// Mix them up and try again - entire subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::partition_subrange(b, v.end(), b, v.end(), std::greater<int>());
check_sequence (b, v.end(), b, v.end(), std::greater<int>());
}

128
test/reduce_test.cpp Normal file
View File

@ -0,0 +1,128 @@
/*
Copyright (c) Marshall Clow 2013.
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 <vector>
#include <functional>
#include <boost/config.hpp>
#include <boost/algorithm/cxx17/reduce.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
template <class Iter, class T, class Op>
void
test_reduce(Iter first, Iter last, T init, Op op, T x)
{
BOOST_CHECK(ba::reduce(first, last, init, op) == x);
}
template <class Iter, class T, class Op>
void
test_reduce(Iter first, Iter last, Op op, T x)
{
BOOST_CHECK(ba::reduce(first, last, op) == x);
}
template <class Iter, class T>
void
test_reduce(Iter first, Iter last, T x)
{
BOOST_CHECK(ba::reduce(first, last) == x);
}
template <class Iter>
void
test_init_op()
{
int ia[] = {1, 2, 3, 4, 5, 6};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
test_reduce(Iter(ia), Iter(ia), 0, std::plus<int>(), 0);
test_reduce(Iter(ia), Iter(ia), 1, std::multiplies<int>(), 1);
test_reduce(Iter(ia), Iter(ia+1), 0, std::plus<int>(), 1);
test_reduce(Iter(ia), Iter(ia+1), 2, std::multiplies<int>(), 2);
test_reduce(Iter(ia), Iter(ia+2), 0, std::plus<int>(), 3);
test_reduce(Iter(ia), Iter(ia+2), 3, std::multiplies<int>(), 6);
test_reduce(Iter(ia), Iter(ia+sa), 0, std::plus<int>(), 21);
test_reduce(Iter(ia), Iter(ia+sa), 4, std::multiplies<int>(), 2880);
}
void test_reduce_init_op()
{
test_init_op<input_iterator<const int*> >();
test_init_op<forward_iterator<const int*> >();
test_init_op<bidirectional_iterator<const int*> >();
test_init_op<random_access_iterator<const int*> >();
test_init_op<const int*>();
{
char ia[] = {1, 2, 3, 4, 5, 6, 7, 8};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
unsigned res = boost::algorithm::reduce(ia, ia+sa, 1U, std::multiplies<unsigned>());
BOOST_CHECK(res == 40320); // 8! will not fit into a char
}
}
template <class Iter>
void
test_init()
{
int ia[] = {1, 2, 3, 4, 5, 6};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
test_reduce(Iter(ia), Iter(ia), 0, 0);
test_reduce(Iter(ia), Iter(ia), 1, 1);
test_reduce(Iter(ia), Iter(ia+1), 0, 1);
test_reduce(Iter(ia), Iter(ia+1), 2, 3);
test_reduce(Iter(ia), Iter(ia+2), 0, 3);
test_reduce(Iter(ia), Iter(ia+2), 3, 6);
test_reduce(Iter(ia), Iter(ia+sa), 0, 21);
test_reduce(Iter(ia), Iter(ia+sa), 4, 25);
}
void test_reduce_init()
{
test_init<input_iterator<const int*> >();
test_init<forward_iterator<const int*> >();
test_init<bidirectional_iterator<const int*> >();
test_init<random_access_iterator<const int*> >();
test_init<const int*>();
}
template <class Iter>
void
test()
{
int ia[] = {1, 2, 3, 4, 5, 6};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
test_reduce(Iter(ia), Iter(ia), 0);
test_reduce(Iter(ia), Iter(ia+1), 1);
test_reduce(Iter(ia), Iter(ia+2), 3);
test_reduce(Iter(ia), Iter(ia+sa), 21);
}
void test_reduce()
{
test<input_iterator<const int*> >();
test<forward_iterator<const int*> >();
test<bidirectional_iterator<const int*> >();
test<random_access_iterator<const int*> >();
test<const int*>();
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_reduce();
test_reduce_init();
test_reduce_init_op();
}

View File

@ -7,6 +7,20 @@
#include <vector>
#include <iostream>
#if __cplusplus >= 201103L
#include <random>
std::default_random_engine gen;
template<typename RandomIt>
void do_shuffle(RandomIt first, RandomIt last)
{ std::shuffle(first, last, gen); }
#else
template<typename RandomIt>
void do_shuffle(RandomIt first, RandomIt last)
{ std::random_shuffle(first, last); }
#endif
namespace ba = boost::algorithm;
template <typename Iter>
@ -53,14 +67,14 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_CHECK_EQUAL(v[5], 5);
// Mix them up and try again - single element
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b + 7, b + 8);
check_sequence (b, v.end(), b + 7, b + 8);
BOOST_CHECK_EQUAL(v[7], 7);
// Mix them up and try again - at the end
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b + 7, v.end());
check_sequence (b, v.end(), b + 7, v.end());
@ -69,7 +83,7 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_CHECK_EQUAL(v[9], 9);
// Mix them up and try again - at the beginning
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b, b + 2);
check_sequence (b, v.end(), b, b + 2);
@ -77,12 +91,12 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_CHECK_EQUAL(v[1], 1);
// Mix them up and try again - empty subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b, b);
check_sequence (b, v.end(), b, b);
// Mix them up and try again - entire subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b, v.end());
check_sequence (b, v.end(), b, v.end());
}
@ -101,14 +115,14 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_CHECK_EQUAL(v[5], 4);
// Mix them up and try again - single element
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b + 7, b + 8, std::greater<int>());
check_sequence (b, v.end(), b + 7, b + 8, std::greater<int>());
BOOST_CHECK_EQUAL(v[7], 2);
// Mix them up and try again - at the end
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b + 7, v.end(), std::greater<int>());
check_sequence (b, v.end(), b + 7, v.end(), std::greater<int>());
@ -117,7 +131,7 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_CHECK_EQUAL(v[9], 0);
// Mix them up and try again - at the beginning
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b, b + 2, std::greater<int>());
check_sequence (b, v.end(), b, b + 2, std::greater<int>());
@ -125,12 +139,12 @@ BOOST_AUTO_TEST_CASE( test_main )
BOOST_CHECK_EQUAL(v[1], 8);
// Mix them up and try again - empty subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b, b, std::greater<int>());
check_sequence (b, v.end(), b, b, std::greater<int>());
// Mix them up and try again - entire subrange
std::random_shuffle(v.begin(), v.end());
do_shuffle(v.begin(), v.end());
ba::sort_subrange(b, v.end(), b, v.end(), std::greater<int>());
check_sequence (b, v.end(), b, v.end(), std::greater<int>());
}

View File

@ -0,0 +1,137 @@
/*
Copyright (c) Marshall Clow 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 <vector>
#include <functional>
#include <numeric>
#include <boost/config.hpp>
#include <boost/algorithm/cxx11/iota.hpp>
#include <boost/algorithm/cxx17/transform_exclusive_scan.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
int triangle(int n) { return n*(n+1)/2; }
template <class _Tp>
struct identity
{
const _Tp& operator()(const _Tp& __x) const { return __x;}
};
template <class Iter1, class BOp, class UOp, class T, class Iter2>
void
test(Iter1 first, Iter1 last, BOp bop, UOp uop, T init, Iter2 rFirst, Iter2 rLast)
{
std::vector<typename std::iterator_traits<Iter1>::value_type> v;
// Test not in-place
ba::transform_exclusive_scan(first, last, std::back_inserter(v), init, bop, uop);
BOOST_CHECK(std::distance(rFirst, rLast) == v.size());
BOOST_CHECK(std::equal(v.begin(), v.end(), rFirst));
// Test in-place
v.clear();
v.assign(first, last);
ba::transform_exclusive_scan(v.begin(), v.end(), v.begin(), init, bop, uop);
BOOST_CHECK(std::distance(rFirst, rLast) == v.size());
BOOST_CHECK(std::equal(v.begin(), v.end(), rFirst));
}
template <class Iter>
void
test()
{
int ia[] = { 1, 3, 5, 7, 9};
const int pResI0[] = { 0, 1, 4, 9, 16}; // with identity
const int mResI0[] = { 0, 0, 0, 0, 0};
const int pResN0[] = { 0, -1, -4, -9, -16}; // with negate
const int mResN0[] = { 0, 0, 0, 0, 0};
const int pResI2[] = { 2, 3, 6, 11, 18}; // with identity
const int mResI2[] = { 2, 2, 6, 30, 210};
const int pResN2[] = { 2, 1, -2, -7, -14}; // with negate
const int mResN2[] = { 2, -2, 6, -30, 210};
const unsigned sa = sizeof(ia) / sizeof(ia[0]);
BOOST_CHECK(sa == sizeof(pResI0) / sizeof(pResI0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResI0) / sizeof(mResI0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResN0) / sizeof(pResN0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResN0) / sizeof(mResN0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResI2) / sizeof(pResI2[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResI2) / sizeof(mResI2[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResN2) / sizeof(pResN2[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResN2) / sizeof(mResN2[0])); // just to be sure
for (unsigned int i = 0; i < sa; ++i ) {
test(Iter(ia), Iter(ia + i), std::plus<int>(), identity<int>(), 0, pResI0, pResI0 + i);
test(Iter(ia), Iter(ia + i), std::multiplies<int>(), identity<int>(), 0, mResI0, mResI0 + i);
test(Iter(ia), Iter(ia + i), std::plus<int>(), std::negate<int>(), 0, pResN0, pResN0 + i);
test(Iter(ia), Iter(ia + i), std::multiplies<int>(), std::negate<int>(), 0, mResN0, mResN0 + i);
test(Iter(ia), Iter(ia + i), std::plus<int>(), identity<int>(), 2, pResI2, pResI2 + i);
test(Iter(ia), Iter(ia + i), std::multiplies<int>(), identity<int>(), 2, mResI2, mResI2 + i);
test(Iter(ia), Iter(ia + i), std::plus<int>(), std::negate<int>(), 2, pResN2, pResN2 + i);
test(Iter(ia), Iter(ia + i), std::multiplies<int>(), std::negate<int>(), 2, mResN2, mResN2 + i);
}
}
void basic_tests()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 50, std::plus<int>(), identity<int>());
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 50 + (int) i * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 30, std::plus<int>(), identity<int>());
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 30 + triangle(i-1));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 40, std::plus<int>(), identity<int>());
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 40 + triangle(i));
}
{
std::vector<int> v, res;
ba::transform_exclusive_scan(v.begin(), v.end(), std::back_inserter(res), 40, std::plus<int>(), identity<int>());
BOOST_CHECK(res.empty());
}
}
void test_transform_exclusive_scan_init()
{
basic_tests();
// All the iterator categories
test<input_iterator <const int*> >();
test<forward_iterator <const int*> >();
test<bidirectional_iterator<const int*> >();
test<random_access_iterator<const int*> >();
test<const int*>();
test< int*>();
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_transform_exclusive_scan_init();
}

View File

@ -0,0 +1,233 @@
/*
Copyright (c) Marshall Clow 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 <vector>
#include <functional>
#include <numeric>
#include <boost/config.hpp>
#include <boost/algorithm/cxx11/iota.hpp>
#include <boost/algorithm/cxx17/transform_inclusive_scan.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
int triangle(int n) { return n*(n+1)/2; }
template <class _Tp>
struct identity
{
const _Tp& operator()(const _Tp& __x) const { return __x;}
};
template <class Iter1, class BOp, class UOp, class Iter2>
void
transform_inclusive_scan_test(Iter1 first, Iter1 last, BOp bop, UOp uop, Iter2 rFirst, Iter2 rLast)
{
std::vector<typename std::iterator_traits<Iter1>::value_type> v;
// Test not in-place
ba::transform_inclusive_scan(first, last, std::back_inserter(v), bop, uop);
BOOST_CHECK(std::distance(first, last) == v.size());
BOOST_CHECK(std::equal(v.begin(), v.end(), rFirst));
// Test in-place
v.clear();
v.assign(first, last);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), bop, uop);
BOOST_CHECK(std::distance(first, last) == v.size());
BOOST_CHECK(std::equal(v.begin(), v.end(), rFirst));
}
template <class Iter>
void
transform_inclusive_scan_test()
{
int ia[] = { 1, 3, 5, 7, 9};
const int pResI0[] = { 1, 4, 9, 16, 25}; // with identity
const int mResI0[] = { 1, 3, 15, 105, 945};
const int pResN0[] = { -1, -4, -9, -16, -25}; // with negate
const int mResN0[] = { -1, 3, -15, 105, -945};
const unsigned sa = sizeof(ia) / sizeof(ia[0]);
BOOST_CHECK(sa == sizeof(pResI0) / sizeof(pResI0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResI0) / sizeof(mResI0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResN0) / sizeof(pResN0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResN0) / sizeof(mResN0[0])); // just to be sure
for (unsigned int i = 0; i < sa; ++i ) {
transform_inclusive_scan_test(Iter(ia), Iter(ia + i), std::plus<int>(), identity<int>(), pResI0, pResI0 + i);
transform_inclusive_scan_test(Iter(ia), Iter(ia + i), std::multiplies<int>(), identity<int>(), mResI0, mResI0 + i);
transform_inclusive_scan_test(Iter(ia), Iter(ia + i), std::plus<int>(), std::negate<int>(), pResN0, pResN0 + i);
transform_inclusive_scan_test(Iter(ia), Iter(ia + i), std::multiplies<int>(), std::negate<int>(), mResN0, mResN0 + i);
}
}
// Basic sanity
void basic_transform_inclusive_scan_tests()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), identity<int>());
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == (int)(i+1) * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), identity<int>());
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == triangle(i));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), identity<int>());
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == triangle(i + 1));
}
{
std::vector<int> v, res;
ba::transform_inclusive_scan(v.begin(), v.end(), std::back_inserter(res), std::plus<int>(), identity<int>());
BOOST_CHECK(res.empty());
}
}
void test_transform_inclusive_scan()
{
basic_transform_inclusive_scan_tests();
// All the iterator categories
transform_inclusive_scan_test<input_iterator <const int*> >();
transform_inclusive_scan_test<forward_iterator <const int*> >();
transform_inclusive_scan_test<bidirectional_iterator<const int*> >();
transform_inclusive_scan_test<random_access_iterator<const int*> >();
transform_inclusive_scan_test<const int*>();
transform_inclusive_scan_test< int*>();
}
template <class Iter1, class BOp, class UOp, class T, class Iter2>
void
transform_inclusive_scan_init_test(Iter1 first, Iter1 last, BOp bop, UOp uop, T init, Iter2 rFirst, Iter2 rLast)
{
std::vector<typename std::iterator_traits<Iter1>::value_type> v;
// Test not in-place
ba::transform_inclusive_scan(first, last, std::back_inserter(v), bop, uop, init);
BOOST_CHECK(std::distance(rFirst, rLast) == v.size());
BOOST_CHECK(std::equal(v.begin(), v.end(), rFirst));
// Test in-place
v.clear();
v.assign(first, last);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), bop, uop, init);
BOOST_CHECK(std::distance(rFirst, rLast) == v.size());
BOOST_CHECK(std::equal(v.begin(), v.end(), rFirst));
}
template <class Iter>
void
transform_inclusive_scan_init_test()
{
int ia[] = { 1, 3, 5, 7, 9};
const int pResI0[] = { 1, 4, 9, 16, 25}; // with identity
const int mResI0[] = { 0, 0, 0, 0, 0};
const int pResN0[] = { -1, -4, -9, -16, -25}; // with negate
const int mResN0[] = { 0, 0, 0, 0, 0};
const int pResI2[] = { 3, 6, 11, 18, 27}; // with identity
const int mResI2[] = { 2, 6, 30, 210, 1890};
const int pResN2[] = { 1, -2, -7, -14, -23}; // with negate
const int mResN2[] = { -2, 6, -30, 210, -1890};
const unsigned sa = sizeof(ia) / sizeof(ia[0]);
BOOST_CHECK(sa == sizeof(pResI0) / sizeof(pResI0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResI0) / sizeof(mResI0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResN0) / sizeof(pResN0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResN0) / sizeof(mResN0[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResI2) / sizeof(pResI2[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResI2) / sizeof(mResI2[0])); // just to be sure
BOOST_CHECK(sa == sizeof(pResN2) / sizeof(pResN2[0])); // just to be sure
BOOST_CHECK(sa == sizeof(mResN2) / sizeof(mResN2[0])); // just to be sure
for (unsigned int i = 0; i < sa; ++i ) {
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::plus<int>(), identity<int>(), 0, pResI0, pResI0 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::multiplies<int>(), identity<int>(), 0, mResI0, mResI0 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::plus<int>(), std::negate<int>(), 0, pResN0, pResN0 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::multiplies<int>(), std::negate<int>(), 0, mResN0, mResN0 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::plus<int>(), identity<int>(), 2, pResI2, pResI2 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::multiplies<int>(), identity<int>(), 2, mResI2, mResI2 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::plus<int>(), std::negate<int>(), 2, pResN2, pResN2 + i);
transform_inclusive_scan_init_test(Iter(ia), Iter(ia + i), std::multiplies<int>(), std::negate<int>(), 2, mResN2, mResN2 + i);
}
}
// Basic sanity
void basic_transform_inclusive_scan_init_tests()
{
{
std::vector<int> v(10);
std::fill(v.begin(), v.end(), 3);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), identity<int>(), 50);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 50 + (int) (i + 1) * 3);
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 0);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), identity<int>(), 30);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 30 + triangle(i));
}
{
std::vector<int> v(10);
ba::iota(v.begin(), v.end(), 1);
ba::transform_inclusive_scan(v.begin(), v.end(), v.begin(), std::plus<int>(), identity<int>(), 40);
for (size_t i = 0; i < v.size(); ++i)
BOOST_CHECK(v[i] == 40 + triangle(i + 1));
}
{
std::vector<int> v, res;
ba::transform_inclusive_scan(v.begin(), v.end(), std::back_inserter(res), std::plus<int>(), identity<int>(), 1);
BOOST_CHECK(res.empty());
}
}
void test_transform_inclusive_scan_init()
{
basic_transform_inclusive_scan_init_tests();
// All the iterator categories
transform_inclusive_scan_init_test<input_iterator <const int*> >();
transform_inclusive_scan_init_test<forward_iterator <const int*> >();
transform_inclusive_scan_init_test<bidirectional_iterator<const int*> >();
transform_inclusive_scan_init_test<random_access_iterator<const int*> >();
transform_inclusive_scan_init_test<const int*>();
transform_inclusive_scan_init_test< int*>();
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_transform_inclusive_scan();
test_transform_inclusive_scan_init();
}

View File

@ -0,0 +1,188 @@
/*
Copyright (c) Marshall Clow 2013.
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 <boost/config.hpp>
#include <boost/algorithm/cxx17/transform_reduce.hpp>
#include "iterator_test.hpp"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
namespace ba = boost::algorithm;
template <class _Tp>
struct identity
{
const _Tp& operator()(const _Tp& __x) const { return __x;}
};
template <class _Tp>
struct twice
{
const _Tp operator()(const _Tp& __x) const { return 2 * __x; }
};
template <class Iter1, class T, class BOp, class UOp>
void
test_init_bop_uop(Iter1 first1, Iter1 last1, T init, BOp bOp, UOp uOp, T x)
{
BOOST_CHECK(ba::transform_reduce(first1, last1, init, bOp, uOp) == x);
}
template <class Iter>
void
test_init_bop_uop()
{
int ia[] = {1, 2, 3, 4, 5, 6};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
test_init_bop_uop(Iter(ia), Iter(ia), 0, std::plus<int>(), identity<int>(), 0);
test_init_bop_uop(Iter(ia), Iter(ia), 1, std::multiplies<int>(), identity<int>(), 1);
test_init_bop_uop(Iter(ia), Iter(ia+1), 0, std::multiplies<int>(), identity<int>(), 0);
test_init_bop_uop(Iter(ia), Iter(ia+1), 2, std::plus<int>(), identity<int>(), 3);
test_init_bop_uop(Iter(ia), Iter(ia+2), 0, std::plus<int>(), identity<int>(), 3);
test_init_bop_uop(Iter(ia), Iter(ia+2), 3, std::multiplies<int>(), identity<int>(), 6);
test_init_bop_uop(Iter(ia), Iter(ia+sa), 4, std::multiplies<int>(), identity<int>(), 2880);
test_init_bop_uop(Iter(ia), Iter(ia+sa), 4, std::plus<int>(), identity<int>(), 25);
test_init_bop_uop(Iter(ia), Iter(ia), 0, std::plus<int>(), twice<int>(), 0);
test_init_bop_uop(Iter(ia), Iter(ia), 1, std::multiplies<int>(), twice<int>(), 1);
test_init_bop_uop(Iter(ia), Iter(ia+1), 0, std::multiplies<int>(), twice<int>(), 0);
test_init_bop_uop(Iter(ia), Iter(ia+1), 2, std::plus<int>(), twice<int>(), 4);
test_init_bop_uop(Iter(ia), Iter(ia+2), 0, std::plus<int>(), twice<int>(), 6);
test_init_bop_uop(Iter(ia), Iter(ia+2), 3, std::multiplies<int>(), twice<int>(), 24);
test_init_bop_uop(Iter(ia), Iter(ia+sa), 4, std::multiplies<int>(), twice<int>(), 184320); // 64 * 2880
test_init_bop_uop(Iter(ia), Iter(ia+sa), 4, std::plus<int>(), twice<int>(), 46);
}
void test_transform_reduce_init_bop_uop()
{
BOOST_CHECK ( true );
}
template <class Iter1, class Iter2, class T, class Op1, class Op2>
void
test_init_bop_bop(Iter1 first1, Iter1 last1, Iter2 first2, T init, Op1 op1, Op2 op2, T x)
{
BOOST_CHECK(ba::transform_reduce(first1, last1, first2, init, op1, op2) == x);
}
template <class SIter, class UIter>
void
test_init_bop_bop()
{
int ia[] = {1, 2, 3, 4, 5, 6};
unsigned int ua[] = {2, 4, 6, 8, 10,12};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
BOOST_CHECK(sa == sizeof(ua) / sizeof(ua[0])); // just to be sure
test_init_bop_bop(SIter(ia), SIter(ia), UIter(ua), 0, std::plus<int>(), std::multiplies<int>(), 0);
test_init_bop_bop(UIter(ua), UIter(ua), SIter(ia), 1, std::multiplies<int>(), std::plus<int>(), 1);
test_init_bop_bop(SIter(ia), SIter(ia+1), UIter(ua), 0, std::multiplies<int>(), std::plus<int>(), 0);
test_init_bop_bop(UIter(ua), UIter(ua+1), SIter(ia), 2, std::plus<int>(), std::multiplies<int>(), 4);
test_init_bop_bop(SIter(ia), SIter(ia+2), UIter(ua), 0, std::plus<int>(), std::multiplies<int>(), 10);
test_init_bop_bop(UIter(ua), UIter(ua+2), SIter(ia), 3, std::multiplies<int>(), std::plus<int>(), 54);
test_init_bop_bop(SIter(ia), SIter(ia+sa), UIter(ua), 4, std::multiplies<int>(), std::plus<int>(), 2099520);
test_init_bop_bop(UIter(ua), UIter(ua+sa), SIter(ia), 4, std::plus<int>(), std::multiplies<int>(), 186);
}
void test_transform_reduce_init_bop_bop()
{
// All the iterator categories
test_init_bop_bop<input_iterator <const int*>, input_iterator <const unsigned int*> >();
test_init_bop_bop<input_iterator <const int*>, forward_iterator <const unsigned int*> >();
test_init_bop_bop<input_iterator <const int*>, bidirectional_iterator<const unsigned int*> >();
test_init_bop_bop<input_iterator <const int*>, random_access_iterator<const unsigned int*> >();
test_init_bop_bop<forward_iterator <const int*>, input_iterator <const unsigned int*> >();
test_init_bop_bop<forward_iterator <const int*>, forward_iterator <const unsigned int*> >();
test_init_bop_bop<forward_iterator <const int*>, bidirectional_iterator<const unsigned int*> >();
test_init_bop_bop<forward_iterator <const int*>, random_access_iterator<const unsigned int*> >();
test_init_bop_bop<bidirectional_iterator<const int*>, input_iterator <const unsigned int*> >();
test_init_bop_bop<bidirectional_iterator<const int*>, forward_iterator <const unsigned int*> >();
test_init_bop_bop<bidirectional_iterator<const int*>, bidirectional_iterator<const unsigned int*> >();
test_init_bop_bop<bidirectional_iterator<const int*>, random_access_iterator<const unsigned int*> >();
test_init_bop_bop<random_access_iterator<const int*>, input_iterator <const unsigned int*> >();
test_init_bop_bop<random_access_iterator<const int*>, forward_iterator <const unsigned int*> >();
test_init_bop_bop<random_access_iterator<const int*>, bidirectional_iterator<const unsigned int*> >();
test_init_bop_bop<random_access_iterator<const int*>, random_access_iterator<const unsigned int*> >();
// just plain pointers (const vs. non-const, too)
test_init_bop_bop<const int*, const unsigned int *>();
test_init_bop_bop<const int*, unsigned int *>();
test_init_bop_bop< int*, const unsigned int *>();
test_init_bop_bop< int*, unsigned int *>();
}
template <class Iter1, class Iter2, class T>
void
test_init(Iter1 first1, Iter1 last1, Iter2 first2, T init, T x)
{
BOOST_CHECK(ba::transform_reduce(first1, last1, first2, init) == x);
}
template <class SIter, class UIter>
void
test_init()
{
int ia[] = {1, 2, 3, 4, 5, 6};
unsigned int ua[] = {2, 4, 6, 8, 10,12};
unsigned sa = sizeof(ia) / sizeof(ia[0]);
BOOST_CHECK(sa == sizeof(ua) / sizeof(ua[0])); // just to be sure
test_init(SIter(ia), SIter(ia), UIter(ua), 0, 0);
test_init(UIter(ua), UIter(ua), SIter(ia), 1, 1);
test_init(SIter(ia), SIter(ia+1), UIter(ua), 0, 2);
test_init(UIter(ua), UIter(ua+1), SIter(ia), 2, 4);
test_init(SIter(ia), SIter(ia+2), UIter(ua), 0, 10);
test_init(UIter(ua), UIter(ua+2), SIter(ia), 3, 13);
test_init(SIter(ia), SIter(ia+sa), UIter(ua), 0, 182);
test_init(UIter(ua), UIter(ua+sa), SIter(ia), 4, 186);
}
void test_transform_reduce_init()
{
// All the iterator categories
test_init<input_iterator <const int*>, input_iterator <const unsigned int*> >();
test_init<input_iterator <const int*>, forward_iterator <const unsigned int*> >();
test_init<input_iterator <const int*>, bidirectional_iterator<const unsigned int*> >();
test_init<input_iterator <const int*>, random_access_iterator<const unsigned int*> >();
test_init<forward_iterator <const int*>, input_iterator <const unsigned int*> >();
test_init<forward_iterator <const int*>, forward_iterator <const unsigned int*> >();
test_init<forward_iterator <const int*>, bidirectional_iterator<const unsigned int*> >();
test_init<forward_iterator <const int*>, random_access_iterator<const unsigned int*> >();
test_init<bidirectional_iterator<const int*>, input_iterator <const unsigned int*> >();
test_init<bidirectional_iterator<const int*>, forward_iterator <const unsigned int*> >();
test_init<bidirectional_iterator<const int*>, bidirectional_iterator<const unsigned int*> >();
test_init<bidirectional_iterator<const int*>, random_access_iterator<const unsigned int*> >();
test_init<random_access_iterator<const int*>, input_iterator <const unsigned int*> >();
test_init<random_access_iterator<const int*>, forward_iterator <const unsigned int*> >();
test_init<random_access_iterator<const int*>, bidirectional_iterator<const unsigned int*> >();
test_init<random_access_iterator<const int*>, random_access_iterator<const unsigned int*> >();
// just plain pointers (const vs. non-const, too)
test_init<const int*, const unsigned int *>();
test_init<const int*, unsigned int *>();
test_init< int*, const unsigned int *>();
test_init< int*, unsigned int *>();
}
BOOST_AUTO_TEST_CASE( test_main )
{
test_transform_reduce_init();
test_transform_reduce_init_bop_uop();
test_transform_reduce_init_bop_bop();
}