forked from boostorg/algorithm
Compare commits
19 Commits
indirectSo
...
develop
Author | SHA1 | Date | |
---|---|---|---|
6eb48dd863 | |||
1395fe720c | |||
35a55238a7 | |||
7f07838f8b | |||
bbfcdf1322 | |||
5c8e6ce9ba | |||
0c0e84b112 | |||
81e46297b5 | |||
8189606c93 | |||
c63c45a932 | |||
1213b9fd1f | |||
b3b2ff4d0c | |||
14922e71c0 | |||
fcf95e504b | |||
6b1d2fc5ad | |||
dc14b69189 | |||
61fa3e461f | |||
3401f0398f | |||
1d9706feb7 |
11
Jamfile
11
Jamfile
@ -1,11 +0,0 @@
|
||||
# Boost.Algorithm Library Jamfile
|
||||
#
|
||||
# Copyright (c) 2018 James E. King III
|
||||
#
|
||||
# Use, modification, and distribution are subject to 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)
|
||||
|
||||
# please order by name to ease maintenance
|
||||
build-project example ;
|
||||
build-project test ;
|
42
build.jam
Normal file
42
build.jam
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2023-2024
|
||||
# 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)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
constant boost_dependencies :
|
||||
/boost/array//boost_array
|
||||
/boost/assert//boost_assert
|
||||
/boost/bind//boost_bind
|
||||
/boost/concept_check//boost_concept_check
|
||||
/boost/config//boost_config
|
||||
/boost/core//boost_core
|
||||
/boost/exception//boost_exception
|
||||
/boost/function//boost_function
|
||||
/boost/iterator//boost_iterator
|
||||
/boost/mpl//boost_mpl
|
||||
/boost/range//boost_range
|
||||
/boost/regex//boost_regex
|
||||
/boost/static_assert//boost_static_assert
|
||||
/boost/throw_exception//boost_throw_exception
|
||||
/boost/tuple//boost_tuple
|
||||
/boost/type_traits//boost_type_traits
|
||||
/boost/unordered//boost_unordered ;
|
||||
|
||||
project /boost/algorithm
|
||||
: common-requirements
|
||||
<include>include
|
||||
;
|
||||
|
||||
explicit
|
||||
[ alias boost_algorithm : : : : <library>$(boost_dependencies) ]
|
||||
[ alias all : boost_algorithm test
|
||||
example
|
||||
minmax/example minmax/test
|
||||
string/example string/test
|
||||
]
|
||||
;
|
||||
|
||||
call-if : boost-library algorithm
|
||||
;
|
@ -16,18 +16,18 @@ using quickbook ;
|
||||
using doxygen ;
|
||||
using boostbook ;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
[ glob ../../../boost/algorithm/*.hpp
|
||||
../../../boost/algorithm/searching/*.hpp
|
||||
../../../boost/algorithm/cxx11/*.hpp
|
||||
../../../boost/algorithm/cxx14/*.hpp
|
||||
../../../boost/algorithm/cxx17/*.hpp
|
||||
doxygen autodoc
|
||||
:
|
||||
[ glob ../include/boost/algorithm/*.hpp
|
||||
../include/boost/algorithm/searching/*.hpp
|
||||
../include/boost/algorithm/cxx11/*.hpp
|
||||
../include/boost/algorithm/cxx14/*.hpp
|
||||
../include/boost/algorithm/cxx17/*.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 ;
|
||||
@ -36,7 +36,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
|
||||
|
@ -233,8 +233,6 @@ Convert a sequence of hexadecimal characters into a sequence of integers or char
|
||||
Convert a sequence of integral types into a lower case hexadecimal sequence of characters
|
||||
[endsect:hex_lower]
|
||||
|
||||
[include indirect_sort.qbk]
|
||||
|
||||
[include is_palindrome.qbk]
|
||||
|
||||
[include is_partitioned_until.qbk]
|
||||
|
@ -1,111 +0,0 @@
|
||||
[/ File indirect_sort.qbk]
|
||||
|
||||
[section:indirect_sort indirect_sort ]
|
||||
|
||||
[/license
|
||||
Copyright (c) 2023 Marshall Clow
|
||||
|
||||
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)
|
||||
]
|
||||
|
||||
There are times that you want a sorted version of a sequence, but for some reason you don't want to modify it. Maybe the elements in the sequence can't be moved/copied, e.g. the sequence is const, or they're just really expensive to move around. An example of this might be a sequence of records from a database.
|
||||
|
||||
That's where indirect sorting comes in. In a "normal" sort, the elements of the sequence to be sorted are shuffled in place. In indirect sorting, the elements are unchanged, but the sort algorithm returns a "permutation" of the elements that, when applied, will put the elements in the sequence in a sorted order.
|
||||
|
||||
Assume have a sequence `[first, last)` of 1000 items that are expensive to swap:
|
||||
```
|
||||
std::sort(first, last); // ['O(N ln N)] comparisons and ['O(N ln N)] swaps (of the element type).
|
||||
```
|
||||
|
||||
On the other hand, using indirect sorting:
|
||||
```
|
||||
auto perm = indirect_sort(first, last); // ['O(N lg N)] comparisons and ['O(N lg N)] swaps (of size_t).
|
||||
apply_permutation(first, last, perm.begin(), perm.end()); // ['O(N)] swaps (of the element type)
|
||||
```
|
||||
|
||||
If the element type is sufficiently expensive to swap, then 10,000 swaps of size_t + 1000 swaps of the element_type could be cheaper than 10,000 swaps of the element_type.
|
||||
|
||||
Or maybe you don't need the elements to actually be sorted - you just want to traverse them in a sorted order:
|
||||
```
|
||||
auto permutation = indirect_sort(first, last);
|
||||
for (size_t idx: permutation)
|
||||
std::cout << first[idx] << std::endl;
|
||||
```
|
||||
|
||||
|
||||
Assume that instead of an "array of structures", you have a "struct of arrays".
|
||||
```
|
||||
struct AType {
|
||||
Type0 key;
|
||||
Type1 value1;
|
||||
Type1 value2;
|
||||
};
|
||||
|
||||
std::array<AType, 1000> arrayOfStruct;
|
||||
```
|
||||
|
||||
versus:
|
||||
|
||||
```
|
||||
template <size_t N>
|
||||
struct AType {
|
||||
std::array<Type0, N> key;
|
||||
std::array<Type1, N> value1;
|
||||
std::array<Type2, N> value2;
|
||||
};
|
||||
|
||||
AType<1000> structOfArrays;
|
||||
```
|
||||
|
||||
Sorting the first one is easy, because each set of fields (`key`, `value1`, `value2`) are part of the same struct. But with indirect sorting, the second one is easy to sort as well - just sort the keys, then apply the permutation to the keys and the values:
|
||||
```
|
||||
auto perm = indirect_sort(std::begin(structOfArrays.key), std::end(structOfArrays.key));
|
||||
apply_permutation(structOfArrays.key.begin(), structOfArrays.key.end(), perm.begin(), perm.end());
|
||||
apply_permutation(structOfArrays.value1.begin(), structOfArrays.value1.end(), perm.begin(), perm.end());
|
||||
apply_permutation(structOfArrays.value2.begin(), structOfArrays.value2.end(), perm.begin(), perm.end());
|
||||
```
|
||||
|
||||
[heading interface]
|
||||
|
||||
The function `indirect_sort` returns a `vector<size_t>` containing the permutation necessary to put the input sequence into a sorted order. One version uses `std::less` to do the comparisons; the other lets the caller pass predicate to do the comparisons.
|
||||
|
||||
There is also a variant called `indirect_stable_sort`; it bears the same relation to `indirect_sort` that `std::stable_sort` does to `std::sort`.
|
||||
|
||||
```
|
||||
template <typename RAIterator>
|
||||
std::vector<size_t> indirect_sort (RAIterator first, RAIterator last);
|
||||
|
||||
template <typename RAIterator, typename BinaryPredicate>
|
||||
std::vector<size_t> indirect_sort (RAIterator first, RAIterator last, BinaryPredicate pred);
|
||||
|
||||
template <typename RAIterator>
|
||||
std::vector<size_t> indirect_stable_sort (RAIterator first, RAIterator last);
|
||||
|
||||
template <typename RAIterator, typename BinaryPredicate>
|
||||
std::vector<size_t> indirect_stable_sort (RAIterator first, RAIterator last, BinaryPredicate pred);
|
||||
```
|
||||
|
||||
[heading Examples]
|
||||
|
||||
[heading Iterator Requirements]
|
||||
|
||||
`indirect_sort` requires random-access iterators.
|
||||
|
||||
[heading Complexity]
|
||||
|
||||
Both of the variants of `indirect_sort` run in ['O(N lg N)] time; they are not more (or less) efficient than `std::sort`. There is an extra layer of indirection on each comparison, but all of the swaps are done on values of type `size_t`
|
||||
|
||||
[heading Exception Safety]
|
||||
|
||||
[heading Notes]
|
||||
|
||||
In numpy, this algorithm is known as `argsort`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/ File indirect_sort.qbk
|
||||
Copyright 2023 Marshall Clow
|
||||
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).
|
||||
]
|
@ -8,9 +8,9 @@
|
||||
# See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
|
||||
project /boost/algorithm/example
|
||||
project
|
||||
: requirements
|
||||
<include>../../../
|
||||
<library>/boost/algorithm//boost_algorithm
|
||||
<optimization>speed
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<toolset>msvc:<define>NOMINMAX
|
||||
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Marshall Clow 2023.
|
||||
|
||||
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 indirect_sort.hpp
|
||||
/// \brief indirect sorting algorithms
|
||||
/// \author Marshall Clow
|
||||
///
|
||||
|
||||
#ifndef BOOST_ALGORITHM_INDIRECT_SORT
|
||||
#define BOOST_ALGORITHM_INDIRECT_SORT
|
||||
|
||||
#include <algorithm> // for std::sort (and others)
|
||||
#include <functional> // for std::less
|
||||
#include <vector> // for std::vector
|
||||
|
||||
#include <boost/algorithm/cxx11/iota.hpp>
|
||||
|
||||
namespace boost { namespace algorithm {
|
||||
|
||||
typedef std::vector<size_t> Permutation;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Predicate, class Iter>
|
||||
struct indirect_predicate {
|
||||
indirect_predicate (Predicate pred, Iter iter)
|
||||
: pred_(pred), iter_(iter) {}
|
||||
|
||||
bool operator ()(size_t a, size_t b) const {
|
||||
return pred_(iter_[a], iter_[b]);
|
||||
}
|
||||
|
||||
Predicate pred_;
|
||||
Iter iter_;
|
||||
};
|
||||
|
||||
// Initialize a permutation of size 'size'. [ 0, 1, 2, ... size-1 ]
|
||||
// Note: it would be nice to use 'iota' here, but that call writes over
|
||||
// existing elements - not append them. I don't want to initialize
|
||||
// the elements of the permutation to zero, and then immediately
|
||||
// overwrite them.
|
||||
void init_permutation (Permutation &p, size_t size) {
|
||||
p.reserve(size);
|
||||
boost::algorithm::iota_n(
|
||||
std::back_insert_iterator<Permutation>(p), size_t(0), size);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== sort =====
|
||||
|
||||
/// \fn indirect_sort (RAIterator first, RAIterator last, Predicate pred)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::sort(first, last, pred)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param last The end of the input sequence
|
||||
/// \param pred The predicate to compare elements with
|
||||
///
|
||||
template <typename RAIterator, typename Pred>
|
||||
Permutation indirect_sort (RAIterator first, RAIterator last, Pred pred) {
|
||||
|
||||
Permutation ret;
|
||||
detail::init_permutation(ret, std::distance(first, last));
|
||||
std::sort(ret.begin(), ret.end(),
|
||||
detail::indirect_predicate<Pred, RAIterator>(pred, first));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \fn indirect_sort (RAIterator first, RAIterator last)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::sort(first, last)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param last The end of the input sequence
|
||||
///
|
||||
template <typename RAIterator>
|
||||
Permutation indirect_sort (RAIterator first, RAIterator last) {
|
||||
return indirect_sort(first, last,
|
||||
std::less<typename std::iterator_traits<RAIterator>::value_type>());
|
||||
}
|
||||
|
||||
// ===== stable_sort =====
|
||||
|
||||
/// \fn indirect_stable_sort (RAIterator first, RAIterator last, Predicate pred)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::stable_sort(first, last, pred)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param last The end of the input sequence
|
||||
/// \param pred The predicate to compare elements with
|
||||
///
|
||||
template <typename RAIterator, typename Pred>
|
||||
Permutation indirect_stable_sort (RAIterator first, RAIterator last, Pred pred) {
|
||||
Permutation ret;
|
||||
detail::init_permutation(ret, std::distance(first, last));
|
||||
std::stable_sort(ret.begin(), ret.end(),
|
||||
detail::indirect_predicate<Pred, RAIterator>(pred, first));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \fn indirect_stable_sort (RAIterator first, RAIterator last)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::stable_sort(first, last)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param last The end of the input sequence
|
||||
///
|
||||
template <typename RAIterator>
|
||||
Permutation indirect_stable_sort (RAIterator first, RAIterator last) {
|
||||
return indirect_stable_sort(first, last,
|
||||
std::less<typename std::iterator_traits<RAIterator>::value_type>());
|
||||
}
|
||||
|
||||
// ===== partial_sort =====
|
||||
|
||||
/// \fn indirect_partial_sort (RAIterator first, RAIterator middle, RAIterator last, Predicate pred)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::partial_sort(first, middle, last, pred)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param middle The end of the range to be sorted
|
||||
/// \param last The end of the input sequence
|
||||
/// \param pred The predicate to compare elements with
|
||||
///
|
||||
template <typename RAIterator, typename Pred>
|
||||
Permutation indirect_partial_sort (RAIterator first, RAIterator middle,
|
||||
RAIterator last, Pred pred) {
|
||||
Permutation ret;
|
||||
detail::init_permutation(ret, std::distance(first, last));
|
||||
std::partial_sort(ret.begin(), ret.begin() + std::distance(first, middle), ret.end(),
|
||||
detail::indirect_predicate<Pred, RAIterator>(pred, first));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \fn indirect_partial_sort (RAIterator first, RAIterator middle, RAIterator last)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::partial_sort(first, middle, last)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param middle The end of the range to be sorted
|
||||
/// \param last The end of the input sequence
|
||||
///
|
||||
template <typename RAIterator>
|
||||
Permutation indirect_partial_sort (RAIterator first, RAIterator middle, RAIterator last) {
|
||||
return indirect_partial_sort(first, middle, last,
|
||||
std::less<typename std::iterator_traits<RAIterator>::value_type>());
|
||||
}
|
||||
|
||||
// ===== nth_element =====
|
||||
|
||||
/// \fn indirect_nth_element (RAIterator first, RAIterator nth, RAIterator last, Predicate p)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::nth_element(first, nth, last, p)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param nth The sort partition point in the input sequence
|
||||
/// \param last The end of the input sequence
|
||||
/// \param pred The predicate to compare elements with
|
||||
///
|
||||
template <typename RAIterator, typename Pred>
|
||||
Permutation indirect_nth_element (RAIterator first, RAIterator nth,
|
||||
RAIterator last, Pred pred) {
|
||||
Permutation ret;
|
||||
detail::init_permutation(ret, std::distance(first, last));
|
||||
std::nth_element(ret.begin(), ret.begin() + std::distance(first, nth), ret.end(),
|
||||
detail::indirect_predicate<Pred, RAIterator>(pred, first));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \fn indirect_nth_element (RAIterator first, RAIterator nth, RAIterator last)
|
||||
/// \returns a permutation of the elements in the range [first, last)
|
||||
/// such that when the permutation is applied to the sequence,
|
||||
/// the result is ordered as if 'std::nth_element(first, nth, last)'
|
||||
// was called on the sequence.
|
||||
///
|
||||
/// \param first The start of the input sequence
|
||||
/// \param nth The sort partition point in the input sequence
|
||||
/// \param last The end of the input sequence
|
||||
///
|
||||
template <typename RAIterator>
|
||||
Permutation indirect_nth_element (RAIterator first, RAIterator nth, RAIterator last) {
|
||||
return indirect_nth_element(first, nth, last,
|
||||
std::less<typename std::iterator_traits<RAIterator>::value_type>());
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_ALGORITHM_INDIRECT_SORT
|
@ -85,6 +85,22 @@ namespace boost {
|
||||
return detail::is_classifiedF(std::ctype_base::alpha, Loc);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11
|
||||
//! is_blank predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::blank category.
|
||||
|
||||
\param Loc A locale used for classification
|
||||
\return An instance of the \c is_classified predicate
|
||||
\since c++11
|
||||
*/
|
||||
inline detail::is_classifiedF
|
||||
is_blank(const std::locale& Loc=std::locale())
|
||||
{
|
||||
return detail::is_classifiedF(std::ctype_base::blank, Loc);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! is_cntrl predicate
|
||||
/*!
|
||||
Construct the \c is_classified predicate for the \c ctype_base::cntrl category.
|
||||
@ -294,6 +310,9 @@ namespace boost {
|
||||
// pull names to the boost namespace
|
||||
using algorithm::is_classified;
|
||||
using algorithm::is_space;
|
||||
#ifndef BOOST_NO_CXX11
|
||||
using algorithm::is_blank;
|
||||
#endif
|
||||
using algorithm::is_alnum;
|
||||
using algorithm::is_alpha;
|
||||
using algorithm::is_cntrl;
|
||||
|
@ -108,7 +108,6 @@ namespace boost {
|
||||
|
||||
\param Input An input sequence
|
||||
\param Loc A locale used for 'space' classification
|
||||
\return A trimmed copy of the input
|
||||
*/
|
||||
template<typename SequenceT>
|
||||
inline void trim_all(SequenceT& Input, const std::locale& Loc =std::locale())
|
||||
@ -191,7 +190,6 @@ namespace boost {
|
||||
\param Input An input sequence
|
||||
\param Fill A string used to fill the inner spaces
|
||||
\param Loc A locale used for 'space' classification
|
||||
\return A trimmed copy of the input
|
||||
*/
|
||||
template<typename SequenceT, typename RangeT>
|
||||
inline void trim_fill(SequenceT& Input, const RangeT& Fill, const std::locale& Loc =std::locale())
|
||||
|
@ -7,6 +7,11 @@
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
project
|
||||
: requirements
|
||||
<library>/boost/algorithm//boost_algorithm
|
||||
<library>/boost/timer//boost_timer ;
|
||||
|
||||
exe minmax_ex : minmax_ex.cpp ;
|
||||
exe minmax_timer : minmax_timer.cpp ;
|
||||
|
||||
|
@ -9,17 +9,19 @@
|
||||
|
||||
import testing ;
|
||||
|
||||
project : requirements <library>/boost/algorithm//boost_algorithm ;
|
||||
|
||||
alias unit_test_framework
|
||||
: # sources
|
||||
/boost//unit_test_framework
|
||||
;
|
||||
/boost/test//boost_unit_test_framework
|
||||
;
|
||||
|
||||
{
|
||||
test-suite algorithm/minmax
|
||||
: [ run minmax_element_test.cpp unit_test_framework
|
||||
: : : : minmax_element ]
|
||||
[ run minmax_test.cpp unit_test_framework
|
||||
: : : : minmax ]
|
||||
: : : : minmax ]
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -10,40 +10,40 @@
|
||||
import toolset ;
|
||||
toolset.using doxygen ;
|
||||
|
||||
boostbook string_algo : string_algo.xml autodoc
|
||||
boostbook string_algo : string_algo.xml autodoc
|
||||
:
|
||||
<xsl:param>boost.root=../../../../..
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
|
||||
;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
[ glob ../../../../boost/algorithm/string.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string_regex.hpp ]
|
||||
:
|
||||
[ glob ../../include/boost/algorithm/string.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string_regex.hpp ]
|
||||
|
||||
[ glob ../../../../boost/algorithm/string/classification.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/iterator_range.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/sequence_traits.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/std_containers_traits.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/concept.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/compare.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/constants.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/case_conv.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/find.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/finder.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/find_iterator.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/trim.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/predicate.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/split.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/iter_find.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/erase.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/join.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/replace.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/find_format.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/formatter.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/regex.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/regex_find_format.hpp ]
|
||||
[ glob ../../../../boost/algorithm/string/trim_all.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/classification.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/iterator_range.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/sequence_traits.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/std_containers_traits.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/concept.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/compare.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/constants.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/case_conv.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/find.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/finder.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/find_iterator.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/trim.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/predicate.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/split.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/iter_find.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/erase.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/join.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/replace.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/find_format.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/formatter.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/regex.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/regex_find_format.hpp ]
|
||||
[ glob ../../include/boost/algorithm/string/trim_all.hpp ]
|
||||
:
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
<doxygen:param>EXTRACT_PRIVATE=NO
|
||||
@ -53,7 +53,7 @@ doxygen autodoc
|
||||
<doxygen:param>SEARCH_INCLUDES=YES
|
||||
<doxygen:param>PREDEFINED="BOOST_STRING_TYPENAME=typename \"BOOST_STATIC_CONSTANT(type,var)=static const type var;\""
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -667,6 +667,13 @@
|
||||
<functionname>is_space()</functionname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>is_blank</entry>
|
||||
<entry>Recognize blanks</entry>
|
||||
<entry>
|
||||
<functionname>is_blank()</functionname>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>is_alnum</entry>
|
||||
<entry>Recognize alphanumeric characters</entry>
|
||||
|
@ -7,6 +7,7 @@
|
||||
#
|
||||
# See http://www.boost.org for updates, documentation, and revision history.
|
||||
|
||||
project : requirements <library>/boost/algorithm//boost_algorithm ;
|
||||
|
||||
exe conv_example : conv_example.cpp ;
|
||||
exe predicate_example : predicate_example.cpp ;
|
||||
|
@ -9,31 +9,33 @@
|
||||
|
||||
import testing ;
|
||||
|
||||
project : requirements <library>/boost/algorithm//boost_algorithm ;
|
||||
|
||||
alias unit_test_framework
|
||||
: # sources
|
||||
/boost//unit_test_framework
|
||||
;
|
||||
/boost/test//boost_unit_test_framework
|
||||
;
|
||||
|
||||
test-suite algorithm/string
|
||||
: [ run
|
||||
: [ run
|
||||
trim_test.cpp unit_test_framework
|
||||
: :
|
||||
:
|
||||
: trim
|
||||
]
|
||||
[ run
|
||||
[ run
|
||||
conv_test.cpp unit_test_framework
|
||||
: :
|
||||
:
|
||||
: conv
|
||||
]
|
||||
[ run
|
||||
[ run
|
||||
predicate_test.cpp unit_test_framework
|
||||
: :
|
||||
:
|
||||
: predicate
|
||||
]
|
||||
[ run
|
||||
[ run
|
||||
find_test.cpp unit_test_framework
|
||||
: :
|
||||
:
|
||||
@ -51,23 +53,23 @@ test-suite algorithm/string
|
||||
:
|
||||
: join
|
||||
]
|
||||
[ run
|
||||
[ run
|
||||
replace_test.cpp unit_test_framework
|
||||
: :
|
||||
:
|
||||
: replace
|
||||
]
|
||||
[ run
|
||||
[ run
|
||||
regex_test.cpp unit_test_framework
|
||||
../../../regex/build//boost_regex
|
||||
: :
|
||||
:
|
||||
:
|
||||
: regex
|
||||
]
|
||||
[ run
|
||||
[ run
|
||||
find_format_test.cpp unit_test_framework
|
||||
: :
|
||||
:
|
||||
:
|
||||
: find_format
|
||||
]
|
||||
;
|
||||
|
@ -138,7 +138,12 @@ void classification_test()
|
||||
TEST_CLASS( is_any_of( string("abc") ), "aaabbcc", "aaxb" );
|
||||
TEST_CLASS( is_any_of( "abc" ), "aaabbcc", "aaxb" );
|
||||
TEST_CLASS( is_from_range( 'a', 'c' ), "aaabbcc", "aaxb" );
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11
|
||||
TEST_CLASS( is_blank(), " \t", "\t \n\r" );
|
||||
TEST_CLASS( !is_blank(), "abc\n\v\f\r", "a x\t" );
|
||||
#endif
|
||||
|
||||
TEST_CLASS( !is_classified(std::ctype_base::space), "...", "..\n\r\t " );
|
||||
TEST_CLASS( ( !is_any_of("abc") && is_from_range('a','e') ) || is_space(), "d e", "abcde" );
|
||||
|
||||
|
@ -9,9 +9,11 @@
|
||||
|
||||
import testing ;
|
||||
|
||||
project : requirements <library>/boost/algorithm//boost_algorithm ;
|
||||
|
||||
alias unit_test_framework
|
||||
: # sources
|
||||
/boost//unit_test_framework
|
||||
/boost/test//boost_unit_test_framework
|
||||
;
|
||||
|
||||
|
||||
@ -85,13 +87,9 @@ alias unit_test_framework
|
||||
|
||||
# Is_partitioned_until tests
|
||||
[ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ]
|
||||
|
||||
|
||||
# Apply_permutation tests
|
||||
[ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ]
|
||||
|
||||
# Indirect_sort tests
|
||||
[ run indirect_sort_test.cpp unit_test_framework : : : : indirect_sort_test ]
|
||||
|
||||
# Find tests
|
||||
[ run find_not_test.cpp unit_test_framework : : : : find_not_test ]
|
||||
[ run find_backward_test.cpp unit_test_framework : : : : find_backward_test ]
|
||||
|
@ -1,348 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Marshall Clow 2023.
|
||||
|
||||
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/indirect_sort.hpp>
|
||||
#include <boost/algorithm/apply_permutation.hpp>
|
||||
#include <boost/algorithm/cxx11/is_sorted.hpp>
|
||||
#include <boost/algorithm/cxx11/all_of.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
using boost::algorithm::Permutation;
|
||||
|
||||
// A permutation of size N is a sequence of values in the range [0..N)
|
||||
// such that no value appears more than once in the permutation.
|
||||
bool is_a_permutation(Permutation p, size_t N) {
|
||||
if (p.size() != N) return false;
|
||||
|
||||
// Sort the permutation, and ensure that each value appears exactly once.
|
||||
std::sort(p.begin(), p.end());
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
if (p[i] != i) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iter,
|
||||
typename Comp = typename std::less<typename std::iterator_traits<Iter>::value_type> >
|
||||
struct indirect_comp {
|
||||
indirect_comp (Iter it, Comp c = Comp())
|
||||
: iter_(it), comp_(c) {}
|
||||
|
||||
bool operator ()(size_t a, size_t b) const { return comp_(iter_[a], iter_[b]);}
|
||||
|
||||
Iter iter_;
|
||||
Comp comp_;
|
||||
};
|
||||
|
||||
//// =======================
|
||||
//// ==== indirect_sort ====
|
||||
//// =======================
|
||||
template <typename Iter>
|
||||
void test_one_sort(Iter first, Iter last) {
|
||||
Permutation perm = boost::algorithm::indirect_sort(first, last);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(perm.begin(), perm.end(), indirect_comp<Iter>(first)));
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that it is sorted.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(v.begin(), v.end()));
|
||||
}
|
||||
|
||||
template <typename Iter, typename Comp>
|
||||
void test_one_sort(Iter first, Iter last, Comp comp) {
|
||||
Permutation perm = boost::algorithm::indirect_sort(first, last, comp);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(perm.begin(), perm.end(),
|
||||
indirect_comp<Iter, Comp>(first, comp)));
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that it is sorted.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(v.begin(), v.end(), comp));
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_sort) {
|
||||
int num[] = { 1,3,5,7,9, 2, 4, 6, 8, 10 };
|
||||
const int sz = sizeof (num)/sizeof(num[0]);
|
||||
int *first = &num[0];
|
||||
int const *cFirst = &num[0];
|
||||
|
||||
// Test subsets
|
||||
for (size_t i = 0; i <= sz; ++i) {
|
||||
test_one_sort(first, first + i);
|
||||
test_one_sort(first, first + i, std::greater<int>());
|
||||
|
||||
// test with constant inputs
|
||||
test_one_sort(cFirst, cFirst + i);
|
||||
test_one_sort(cFirst, cFirst + i, std::greater<int>());
|
||||
}
|
||||
|
||||
// make sure we work with iterators as well as pointers
|
||||
std::vector<int> v(first, first + sz);
|
||||
test_one_sort(v.begin(), v.end());
|
||||
test_one_sort(v.begin(), v.end(), std::greater<int>());
|
||||
}
|
||||
|
||||
|
||||
//// ==============================
|
||||
//// ==== indirect_stable_sort ====
|
||||
//// ==============================
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct MyPair {
|
||||
MyPair () {}
|
||||
|
||||
MyPair (const T1 &t1, const T2 &t2)
|
||||
: first(t1), second(t2) {}
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
bool operator < (const MyPair<T1, T2>& lhs, const MyPair<T1, T2>& rhs) {
|
||||
return lhs.first < rhs.first; // compare only the first elements
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
bool MyGreater (const MyPair<T1, T2>& lhs, const MyPair<T1, T2>& rhs) {
|
||||
return lhs.first > rhs.first; // compare only the first elements
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
void test_one_stable_sort(Iter first, Iter last) {
|
||||
Permutation perm = boost::algorithm::indirect_stable_sort(first, last);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(perm.begin(), perm.end(), indirect_comp<Iter>(first)));
|
||||
|
||||
if (first != last) {
|
||||
Iter iFirst = first;
|
||||
Iter iSecond = first; ++iSecond;
|
||||
|
||||
while (iSecond != last) {
|
||||
if (iFirst->first == iSecond->first)
|
||||
BOOST_CHECK(iFirst->second < iSecond->second);
|
||||
++iFirst;
|
||||
++iSecond;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that it is sorted.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(v.begin(), v.end()));
|
||||
}
|
||||
|
||||
template <typename Iter, typename Comp>
|
||||
void test_one_stable_sort(Iter first, Iter last, Comp comp) {
|
||||
Permutation perm = boost::algorithm::indirect_stable_sort(first, last, comp);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(perm.begin(), perm.end(), indirect_comp<Iter, Comp>(first, comp)));
|
||||
|
||||
if (first != last) {
|
||||
Iter iFirst = first;
|
||||
Iter iSecond = first; ++iSecond;
|
||||
|
||||
while (iSecond != last) {
|
||||
if (iFirst->first == iSecond->first)
|
||||
BOOST_CHECK(iFirst->second < iSecond->second);
|
||||
++iFirst;
|
||||
++iSecond;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that it is sorted.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(v.begin(), v.end(), comp));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_stable_sort) {
|
||||
typedef MyPair<int, long> Pair;
|
||||
const int sz = 10;
|
||||
Pair vals[sz];
|
||||
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
vals[i].first = 100 - (i >> 1);
|
||||
vals[i].second = i;
|
||||
}
|
||||
|
||||
Pair *first = &vals[0];
|
||||
Pair const *cFirst = &vals[0];
|
||||
|
||||
// Test subsets
|
||||
for (size_t i = 0; i <= sz; ++i) {
|
||||
test_one_stable_sort(first, first + i);
|
||||
test_one_stable_sort(first, first + i, MyGreater<int, long>);
|
||||
|
||||
// test with constant inputs
|
||||
test_one_sort(cFirst, cFirst + i);
|
||||
test_one_sort(cFirst, cFirst + i, MyGreater<int, long>);
|
||||
}
|
||||
}
|
||||
|
||||
//// ===============================
|
||||
//// ==== indirect_partial_sort ====
|
||||
//// ===============================
|
||||
|
||||
template <typename Iter>
|
||||
void test_one_partial_sort(Iter first, Iter middle, Iter last) {
|
||||
const size_t middleIdx = std::distance(first, middle);
|
||||
Permutation perm = boost::algorithm::indirect_partial_sort(first, middle, last);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(perm.begin(), perm.begin() + middleIdx, indirect_comp<Iter>(first)));
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that it is sorted.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(v.begin(), v.begin() + middleIdx));
|
||||
|
||||
// Make sure that [middle, end) are all "greater" than the sorted part
|
||||
if (middleIdx > 0) {
|
||||
typename Vector::iterator lastSorted = v.begin() + middleIdx - 1;
|
||||
for (typename Vector::iterator it = v.begin () + middleIdx; it != v.end(); ++it)
|
||||
BOOST_CHECK(*lastSorted < *it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iter, typename Comp>
|
||||
void test_one_partial_sort(Iter first, Iter middle, Iter last, Comp comp) {
|
||||
const size_t middleIdx = std::distance(first, middle);
|
||||
Permutation perm = boost::algorithm::indirect_partial_sort(first, middle, last, comp);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(perm.begin(), perm.begin() + middleIdx,
|
||||
indirect_comp<Iter, Comp>(first, comp)));
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that it is sorted.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
BOOST_CHECK (boost::algorithm::is_sorted(v.begin(), v.begin() + middleIdx, comp));
|
||||
|
||||
// Make sure that [middle, end) are all "greater" than the sorted part
|
||||
if (middleIdx > 0) {
|
||||
typename Vector::iterator lastSorted = v.begin() + middleIdx - 1;
|
||||
for (typename Vector::iterator it = v.begin () + middleIdx; it != v.end(); ++it)
|
||||
BOOST_CHECK(comp(*lastSorted, *it));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_partial_sort) {
|
||||
int num[] = { 1,3,5,7,9, 2, 4, 6, 8, 10 };
|
||||
const int sz = sizeof (num)/sizeof(num[0]);
|
||||
int *first = &num[0];
|
||||
int const *cFirst = &num[0];
|
||||
|
||||
// Test subsets
|
||||
for (size_t i = 0; i <= sz; ++i) {
|
||||
for (size_t j = 0; j < i; ++j) {
|
||||
test_one_partial_sort(first, first + j, first + i);
|
||||
test_one_partial_sort(first, first + j, first + i, std::greater<int>());
|
||||
|
||||
// test with constant inputs
|
||||
test_one_partial_sort(cFirst, cFirst + j, cFirst + i);
|
||||
test_one_partial_sort(cFirst, cFirst + j, cFirst + i, std::greater<int>());
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we work with iterators as well as pointers
|
||||
std::vector<int> v(first, first + sz);
|
||||
test_one_partial_sort(v.begin(), v.begin() + (sz / 2), v.end());
|
||||
test_one_partial_sort(v.begin(), v.begin() + (sz / 2), v.end(), std::greater<int>());
|
||||
}
|
||||
|
||||
|
||||
//// ===================================
|
||||
//// ==== indirect_nth_element_sort ====
|
||||
//// ===================================
|
||||
|
||||
template <typename Iter>
|
||||
void test_one_nth_element(Iter first, Iter nth, Iter last) {
|
||||
const size_t nthIdx = std::distance(first, nth);
|
||||
Permutation perm = boost::algorithm::indirect_nth_element(first, nth, last);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
|
||||
for (size_t i = 0; i < nthIdx; ++i)
|
||||
BOOST_CHECK(!(first[perm[nthIdx]] < first[perm[i]])); // all items before the nth element are <= the nth element
|
||||
for (size_t i = nthIdx; i < std::distance(first, last); ++i)
|
||||
BOOST_CHECK(!(first[perm[i]] < first[perm[nthIdx]])); // all items before the nth element are >= the nth element
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that the result is correct.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
|
||||
for (size_t i = 0; i < nthIdx; ++i)
|
||||
BOOST_CHECK(!(v[nthIdx] < v[i])); // all items before the nth element are <= the nth element
|
||||
for (size_t i = nthIdx; i < v.size(); ++i)
|
||||
BOOST_CHECK(!(v[i] < v[nthIdx])); // all items before the nth element are >= the nth element
|
||||
}
|
||||
|
||||
template <typename Iter, typename Comp>
|
||||
void test_one_nth_element(Iter first, Iter nth, Iter last, Comp comp) {
|
||||
const size_t nthIdx = std::distance(first, nth);
|
||||
|
||||
Permutation perm = boost::algorithm::indirect_nth_element(first, nth, last, comp);
|
||||
BOOST_CHECK (is_a_permutation(perm, std::distance(first, last)));
|
||||
for (size_t i = 0; i < nthIdx; ++i)
|
||||
BOOST_CHECK(!comp(first[perm[nthIdx]], first[perm[i]])); // all items before the nth element are <= the nth element
|
||||
for (size_t i = nthIdx; i < std::distance(first, last); ++i)
|
||||
BOOST_CHECK(!comp(first[perm[i]], first[perm[nthIdx]])); // all items before the nth element are >= the nth element
|
||||
|
||||
|
||||
// Make a copy of the data, apply the permutation, and ensure that the result is correct.
|
||||
typedef std::vector<typename std::iterator_traits<Iter>::value_type> Vector;
|
||||
Vector v(first, last);
|
||||
boost::algorithm::apply_permutation(v.begin(), v.end(), perm.begin(), perm.end());
|
||||
|
||||
for (size_t i = 0; i < nthIdx; ++i)
|
||||
BOOST_CHECK(!comp(v[nthIdx], v[i])); // all items before the nth element are <= the nth element
|
||||
for (size_t i = nthIdx; i < v.size(); ++i)
|
||||
BOOST_CHECK(!comp(v[i], v[nthIdx])); // all items before the nth element are >= the nth element
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_nth_element) {
|
||||
int num[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10, 1, 2, 3, 4, 5 };
|
||||
const int sz = sizeof (num)/sizeof(num[0]);
|
||||
int *first = &num[0];
|
||||
int const *cFirst = &num[0];
|
||||
|
||||
// Test subsets
|
||||
for (size_t i = 0; i <= sz; ++i) {
|
||||
for (size_t j = 0; j < i; ++j) {
|
||||
test_one_nth_element(first, first + j, first + i);
|
||||
test_one_nth_element(first, first + j, first + i, std::greater<int>());
|
||||
|
||||
// test with constant inputs
|
||||
test_one_nth_element(cFirst, cFirst + j, cFirst + i);
|
||||
test_one_nth_element(cFirst, cFirst + j, cFirst + i, std::greater<int>());
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we work with iterators as well as pointers
|
||||
std::vector<int> v(first, first + sz);
|
||||
test_one_nth_element(v.begin(), v.begin() + (sz / 2), v.end());
|
||||
test_one_nth_element(v.begin(), v.begin() + (sz / 2), v.end(), std::greater<int>());
|
||||
}
|
Reference in New Issue
Block a user