diff --git a/include/boost/algorithm/cxx11/is_permutation.hpp b/include/boost/algorithm/cxx11/is_permutation.hpp index 526ca2e..e1273f1 100644 --- a/include/boost/algorithm/cxx11/is_permutation.hpp +++ b/include/boost/algorithm/cxx11/is_permutation.hpp @@ -25,10 +25,6 @@ namespace boost { namespace algorithm { -#if __cplusplus >= 201103L -// Use the C++11 versions of is_permutation if it is available -using std::is_permutation; // Section 25.2.12 -#else /// \cond DOXYGEN_HIDE namespace detail { template @@ -38,18 +34,82 @@ namespace detail { template bool operator () ( const T1 &t1 ) const { return p_ ( *it_, t1 ); } private: - Predicate &p_; + Predicate p_; Iterator it_; }; + +// Preconditions: +// 1. The sequences are the same length +// 2. Any common elements on the front have been removed (not necessary for correctness, just for performance) + template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > + bool is_permutation_inner ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate p ) { + // for each unique value in the sequence [first1,last1), count how many times + // it occurs, and make sure it occurs the same number of times in [first2, last2) + for ( ForwardIterator1 iter = first1; iter != last1; ++iter ) { + value_predicate pred ( p, iter ); + + /* For each value we haven't seen yet... */ + if ( std::find_if ( first1, iter, pred ) == iter ) { + std::size_t dest_count = std::count_if ( first2, last2, pred ); + if ( dest_count == 0 || dest_count != (std::size_t) std::count_if ( iter, last1, pred )) + return false; + } + } + + return true; + } + + template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate> + bool is_permutation_tag ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate p, + std::forward_iterator_tag, std::forward_iterator_tag ) { + + // Skip the common prefix (if any) + while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) { + ++first1; + ++first2; + } + if ( first1 != last1 && first2 != last2 ) + return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, + std::equal_to::value_type> ()); + return first1 == last1 && first2 == last2; + } + + template + bool is_permutation_tag ( RandomAccessIterator1 first1, RandomAccessIterator1 last1, + RandomAccessIterator2 first2, RandomAccessIterator2 last2, + BinaryPredicate p, + std::random_access_iterator_tag, std::random_access_iterator_tag ) { + // Cheap check + if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 )) + return false; + // Skip the common prefix (if any) + while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) { + ++first1; + ++first2; + } + + if ( first1 != last1 && first2 != last2 ) + return is_permutation_inner (first1, last1, first2, last2, p); + return first1 == last1 && first2 == last2; + } + } /// \endcond +#if __cplusplus >= 201103L +// Use the C++11 versions of is_permutation if it is available +using std::is_permutation; // Section 25.2.12 +#else /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2, BinaryPredicate p ) /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 /// -/// \param first The start of the input sequence -/// \param last One past the end of the input sequence +/// \param first1 The start of the input sequence +/// \param last1 One past the end of the input sequence /// \param first2 The start of the second sequence /// \param p The predicate to compare elements with /// @@ -69,19 +129,7 @@ bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, // Create last2 ForwardIterator2 last2 = first2; std::advance ( last2, std::distance (first1, last1)); - - // for each unique value in the sequence [first1,last1), count how many times - // it occurs, and make sure it occurs the same number of times in [first2, last2) - for ( ForwardIterator1 iter = first1; iter != last1; ++iter ) { - detail::value_predicate pred ( p, iter ); - - /* For each value we haven't seen yet... */ - if ( std::find_if ( first1, iter, pred ) == iter ) { - std::size_t dest_count = std::count_if ( first2, last2, pred ); - if ( dest_count == 0 || dest_count != (std::size_t) std::count_if ( iter, last1, pred )) - return false; - } - } + return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, p ); } return true; @@ -90,23 +138,84 @@ bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2 ) /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 /// -/// \param first The start of the input sequence -/// \param last One past the end of the input sequence +/// \param first1 The start of the input sequence +/// \param last2 One past the end of the input sequence /// \param first2 The start of the second sequence /// \note This function is part of the C++2011 standard library. /// We will use the standard one if it is available, /// otherwise we have our own implementation. template< class ForwardIterator1, class ForwardIterator2 > -bool is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2 ) +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2 ) { // How should I deal with the idea that ForwardIterator1::value_type // and ForwardIterator2::value_type could be different? Define my own comparison predicate? - return boost::algorithm::is_permutation ( first, last, first2, - std::equal_to::value_type> ()); +// Skip the common prefix (if any) + std::pair eq = std::mismatch (first1, last1, first2 ); + first1 = eq.first; + first2 = eq.second; + if ( first1 != last1 ) { + // Create last2 + ForwardIterator2 last2 = first2; + std::advance ( last2, std::distance (first1, last1)); + return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, + std::equal_to::value_type> ()); + } + return true; } #endif +/// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, +/// ForwardIterator2 first2, ForwardIterator2 last2 ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param first1 The start of the input sequence +/// \param last2 One past the end of the input sequence +/// \param first2 The start of the second sequence +/// \param last1 One past the end of the second sequence +/// \note This function is part of the C++2011 standard library. +/// We will use the standard one if it is available, +/// otherwise we have our own implementation. +template< class ForwardIterator1, class ForwardIterator2 > +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 ) +{ +// How should I deal with the idea that ForwardIterator1::value_type +// and ForwardIterator2::value_type could be different? Define my own comparison predicate? + return boost::algorithm::detail::is_permutation_tag ( + first1, last1, first2, last2, + std::equal_to::value_type> (), + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +/// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, +/// ForwardIterator2 first2, ForwardIterator2 last2, +/// BinaryPredicate p ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param first1 The start of the input sequence +/// \param last1 One past the end of the input sequence +/// \param first2 The start of the second sequence +/// \param last2 One past the end of the second sequence +/// \param pred The predicate to compare elements with +/// +/// \note This function is part of the C++2011 standard library. +/// We will use the standard one if it is available, +/// otherwise we have our own implementation. +template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred ) +{ + return boost::algorithm::detail::is_permutation_tag ( + first1, last1, first2, last2, pred, + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + + + /// \fn is_permutation ( const Range &r, ForwardIterator first2 ) /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 /// diff --git a/include/boost/algorithm/cxx14/equal.hpp b/include/boost/algorithm/cxx14/equal.hpp new file mode 100644 index 0000000..d10c096 --- /dev/null +++ b/include/boost/algorithm/cxx14/equal.hpp @@ -0,0 +1,97 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + 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 equal.hpp +/// \brief Test ranges to if they are equal +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_EQUAL_HPP +#define BOOST_ALGORITHM_EQUAL_HPP + +#include // for std::equal +#include // for std::equal_to + +namespace boost { namespace algorithm { + +namespace detail { + + template + struct eq : public std::binary_function { + bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;} + }; + + template + bool equal ( RandomAccessIterator1 first1, RandomAccessIterator1 last1, + RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, + std::random_access_iterator_tag, std::random_access_iterator_tag ) + { + // Random-access iterators let is check the sizes in constant time + if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 )) + return false; + // If we know that the sequences are the same size, the original version is fine + return std::equal ( first1, last1, first2, pred ); + } + + template + bool equal ( InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, BinaryPredicate pred, + std::input_iterator_tag, std::input_iterator_tag ) + { + for (; first1 != last1 && first2 != last2; ++first1, ++first2 ) + if ( !pred(*first1, *first2 )) + return false; + + return first1 == last1 && first2 == last2; + } +} + +/// \fn equal ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2, +/// BinaryPredicate pred ) +/// \return true if all elements in the two ranges are equal +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +/// \param pred A predicate for comparing the elements of the ranges +template +bool equal ( InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, BinaryPredicate pred ) +{ + return boost::algorithm::detail::equal ( + first1, last1, first2, last2, pred, + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +/// \fn equal ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2 ) +/// \return true if all elements in the two ranges are equal +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +template +bool equal ( InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2 ) +{ + return boost::algorithm::detail::equal ( + first1, last1, first2, last2, + boost::algorithm::detail::eq< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type> (), + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +// There are already range-based versions of these. + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_EQUAL_HPP diff --git a/include/boost/algorithm/cxx14/is_permutation.hpp b/include/boost/algorithm/cxx14/is_permutation.hpp new file mode 100644 index 0000000..779acef --- /dev/null +++ b/include/boost/algorithm/cxx14/is_permutation.hpp @@ -0,0 +1,130 @@ +/* + 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) +*/ + +/// \file equal.hpp +/// \brief Determines if one +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_IS_PERMUTATION_HPP +#define BOOST_ALGORITHM_IS_PERMUTATION_HPP + +#include +#include // for std::equal_to + +namespace boost { namespace algorithm { + +namespace detail { + + template + struct is_perm_eq : public std::binary_function { + bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;} + }; + + + template + bool is_permutation ( RandomAccessIterator1 first1, RandomAccessIterator1 last1, + RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, + std::random_access_iterator_tag, std::random_access_iterator_tag ) + { + // Random-access iterators let is check the sizes in constant time + if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 )) + return false; + // If we know that the sequences are the same size, the original version is fine + return std::is_permutation ( first1, last1, first2, pred ); + } + + + template + bool is_permutation ( + ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred, + std::forward_iterator_tag, std::forward_iterator_tag ) + { + + // Look for common prefix + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + if (!pred(*first1, *first2)) + goto not_done; + // We've reached the end of one of the sequences without a mismatch. + return first1 == last1 && first2 == last2; + not_done: + + // Check and make sure that we have the same # of elements left + typedef typename std::iterator_traits::difference_type diff1_t; + diff1_t len1 = _VSTD::distance(first1, last1); + typedef typename std::iterator_traits::difference_type diff2_t; + diff2_t len2 = _VSTD::distance(first2, last2); + if (len1 != len2) + return false; + + // For each element in [f1, l1) see if there are the + // same number of equal elements in [f2, l2) + for ( ForwardIterator1 i = first1; i != last1; ++i ) + { + // Have we already counted this value? + ForwardIterator1 j; + for ( j = first1; j != i; ++j ) + if (pred(*j, *i)) + break; + if ( j == i ) // didn't find it... + { + // Count number of *i in [f2, l2) + diff1_t c2 = 0; + for ( ForwardIterator2 iter2 = first2; iter2 != last2; ++iter2 ) + if (pred(*i, *iter2)) + ++c2; + if (c2 == 0) + return false; + + // Count number of *i in [i, l1) + diff1_t c1 = 0; + for (_ForwardIterator1 iter1 = i; iter1 != last1; ++iter1 ) + if (pred(*i, *iter1)) + ++c1; + if (c1 != c2) + return false; + } + } + return true; + } + +} + + +template +bool is_permutation ( + ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred ) +{ + return boost::algorithm::detail::is_permutation ( + first1, last1, first2, last2, pred, + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +template +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 ) +{ + typedef typename iterator_traits<_ForwardIterator1>::value_type value1_t; + typedef typename iterator_traits<_ForwardIterator2>::value_type value2_t; + return boost::algorithm::detail::is_permutation ( + first1, last1, first2, last2, + boost::algorithm::detail::is_perm_eq< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type> (), + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +// There are already range-based versions of these. + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_IS_PERMUTATION_HPP diff --git a/include/boost/algorithm/cxx14/mismatch.hpp b/include/boost/algorithm/cxx14/mismatch.hpp new file mode 100644 index 0000000..5229e3b --- /dev/null +++ b/include/boost/algorithm/cxx14/mismatch.hpp @@ -0,0 +1,66 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt) +*/ + +/// \file mismatch.hpp +/// \brief Find the first mismatched element in a sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_MISMATCH_HPP +#define BOOST_ALGORITHM_MISMATCH_HPP + +#include // for std::mismatch +#include // for std::pair + +namespace boost { namespace algorithm { + +template + +/// \fn mismatch ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2, +/// BinaryPredicate pred ) +/// \return a pair of iterators pointing to the first elements in the sequence that do not match +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +/// \param pred A predicate for comparing the elements of the ranges +std::pair mismatch ( + InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + BinaryPredicate pred ) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + if ( !pred ( *first1, *first2 )) + break; + return std::pair(first1, first2); +} + +/// \fn mismatch ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2 ) +/// \return a pair of iterators pointing to the first elements in the sequence that do not match +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +template +std::pair mismatch ( + InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2 ) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + if ( *first1 != *first2 ) + break; + return std::pair(first1, first2); +} + +// There are already range-based versions of these. + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_MISMATCH_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1711ddc..ceea3a0 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -47,6 +47,10 @@ alias unit_test_framework [ run is_partitioned_test1.cpp unit_test_framework : : : : is_partitioned_test1 ] [ run partition_copy_test1.cpp unit_test_framework : : : : partition_copy_test1 ] +# Cxx14 tests + [ run equal_test.cpp unit_test_framework : : : : equal_test ] + [ run mismatch_test.cpp unit_test_framework : : : : mismatch_test ] + # Hex tests [ run hex_test1.cpp unit_test_framework : : : : hex_test1 ] [ run hex_test2.cpp unit_test_framework : : : : hex_test2 ] diff --git a/test/equal_test.cpp b/test/equal_test.cpp new file mode 100644 index 0000000..c54e64d --- /dev/null +++ b/test/equal_test.cpp @@ -0,0 +1,129 @@ +/* + 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 +#include + +#include "iterator_test.hpp" + +#define BOOST_TEST_MAIN +#include + +template +bool eq ( const T& a, const T& b ) { return a == b; } + +template +bool never_eq ( const T&, const T& ) { return false; } + +int comparison_count = 0; +template +bool counting_equals ( const T &a, const T &b ) { + ++comparison_count; + return a == b; + } + +namespace ba = boost::algorithm; + +void test_equal () +{ +// Note: The literal values here are tested against directly, careful if you change them: + int num[] = { 1, 1, 2, 3, 5 }; + const int sz = sizeof (num)/sizeof(num[0]); + + +// Empty sequences are equal to each other, but not to non-empty sequences + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num), + input_iterator(num), input_iterator(num))); + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num), + input_iterator(num), input_iterator(num), + never_eq )); + BOOST_CHECK ( ba::equal ( random_access_iterator(num), random_access_iterator(num), + random_access_iterator(num), random_access_iterator(num), + never_eq )); + + BOOST_CHECK (!ba::equal ( input_iterator(num), input_iterator(num), + input_iterator(num), input_iterator(num + 1))); + BOOST_CHECK (!ba::equal ( input_iterator(num + 1), input_iterator(num + 2), + input_iterator(num), input_iterator(num))); + BOOST_CHECK (!ba::equal ( random_access_iterator(num + 1), random_access_iterator(num + 2), + random_access_iterator(num), random_access_iterator(num))); + +// Single element sequences are equal if they contain the same value + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + 1), + input_iterator(num), input_iterator(num + 1))); + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + 1), + input_iterator(num), input_iterator(num + 1), + eq )); + BOOST_CHECK ( ba::equal ( random_access_iterator(num), random_access_iterator(num + 1), + random_access_iterator(num), random_access_iterator(num + 1), + eq )); + BOOST_CHECK (!ba::equal ( input_iterator(num), input_iterator(num + 1), + input_iterator(num), input_iterator(num + 1), + never_eq )); + BOOST_CHECK (!ba::equal ( random_access_iterator(num), random_access_iterator(num + 1), + random_access_iterator(num), random_access_iterator(num + 1), + never_eq )); + + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + 1), + input_iterator(num + 1), input_iterator(num + 2))); + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + 1), + input_iterator(num + 1), input_iterator(num + 2), + eq )); + + BOOST_CHECK (!ba::equal ( input_iterator(num + 2), input_iterator(num + 3), + input_iterator(num), input_iterator(num + 1))); + BOOST_CHECK (!ba::equal ( input_iterator(num + 2), input_iterator(num + 3), + input_iterator(num), input_iterator(num + 1), + eq )); + +// Identical long sequences are equal. + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz))); + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz), + eq )); + BOOST_CHECK (!ba::equal ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz), + never_eq )); + BOOST_CHECK ( ba::equal ( input_iterator(num), input_iterator(num + sz), + random_access_iterator(num), random_access_iterator(num + sz), + eq )); + +// different sequences are different + BOOST_CHECK (!ba::equal ( input_iterator(num + 1), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz))); + BOOST_CHECK (!ba::equal ( input_iterator(num + 1), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz), + eq )); + BOOST_CHECK (!ba::equal ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz - 1))); + BOOST_CHECK (!ba::equal ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz - 1), + eq )); + +// When there's a cheap check, bail early + comparison_count = 0; + BOOST_CHECK (!ba::equal ( random_access_iterator(num), random_access_iterator(num + sz), + random_access_iterator(num), random_access_iterator(num + sz - 1), + counting_equals )); + BOOST_CHECK ( comparison_count == 0 ); +// And when there's not, we can't + comparison_count = 0; + BOOST_CHECK (!ba::equal ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz - 1), + counting_equals )); + BOOST_CHECK ( comparison_count > 0 ); + +} + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test_equal (); +} diff --git a/test/is_permutation_test1.cpp b/test/is_permutation_test1.cpp index 2ccd06a..e819643 100644 --- a/test/is_permutation_test1.cpp +++ b/test/is_permutation_test1.cpp @@ -19,10 +19,95 @@ #include #include +#include "iterator_test.hpp" + +template +bool eq ( const T& a, const T& b ) { return a == b; } + +template +bool never_eq ( const T&, const T& ) { return false; } + namespace ba = boost::algorithm; -// namespace ba = boost; void test_sequence1 () { + int num[] = { 1, 1, 2, 3, 5 }; + const int sz = sizeof (num)/sizeof(num[0]); + +// Empty sequences + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num), + forward_iterator(num))); + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num), + forward_iterator(num), forward_iterator(num))); + BOOST_CHECK ( + ba::is_permutation ( + random_access_iterator(num), random_access_iterator(num), + random_access_iterator(num), random_access_iterator(num))); + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num), + forward_iterator(num), + never_eq )); // Since the sequences are empty, the pred is never called + +// Empty vs. non-empty + BOOST_CHECK ( ! + ba::is_permutation ( + forward_iterator(num), forward_iterator(num), + forward_iterator(num), forward_iterator(num + 1))); + + BOOST_CHECK ( ! + ba::is_permutation ( + forward_iterator(num + 1), forward_iterator(num + 2), + forward_iterator(num), forward_iterator(num))); + + BOOST_CHECK ( ! + ba::is_permutation ( + random_access_iterator(num + 1), random_access_iterator(num + 2), + random_access_iterator(num), random_access_iterator(num))); + + BOOST_CHECK ( ! + ba::is_permutation ( + random_access_iterator(num), random_access_iterator(num), + random_access_iterator(num + 1), random_access_iterator(num + 2))); + +// Something should be a permutation of itself + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num + sz), + forward_iterator(num))); + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num + sz), + forward_iterator(num), eq )); + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num + sz), + forward_iterator(num), forward_iterator(num + sz ))); + BOOST_CHECK ( + ba::is_permutation ( + forward_iterator(num), forward_iterator(num + sz), + forward_iterator(num), forward_iterator(num + sz ), + eq )); + + BOOST_CHECK ( + ba::is_permutation ( + random_access_iterator(num), random_access_iterator(num + sz), + random_access_iterator(num), random_access_iterator(num + sz))); + BOOST_CHECK ( + ba::is_permutation ( + random_access_iterator(num), random_access_iterator(num + sz), + random_access_iterator(num), random_access_iterator(num + sz), + eq )); + BOOST_CHECK ( + ba::is_permutation ( + random_access_iterator(num), random_access_iterator(num + sz), + forward_iterator(num), forward_iterator(num + sz), + eq )); + + std::vector v, v1; v.clear (); diff --git a/test/mismatch_test.cpp b/test/mismatch_test.cpp new file mode 100644 index 0000000..61a7506 --- /dev/null +++ b/test/mismatch_test.cpp @@ -0,0 +1,168 @@ +/* + 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 +#include + +#include "iterator_test.hpp" + +#define BOOST_TEST_MAIN +#include + +template +bool eq ( const T& a, const T& b ) { return a == b; } + +template +bool never_eq ( const T&, const T& ) { return false; } + +namespace ba = boost::algorithm; + +template +bool iter_eq ( std::pair pr, Iter1 first, Iter2 second ) { + return pr.first == first && pr.second == second; + } + +void test_mismatch () +{ +// Note: The literal values here are tested against directly, careful if you change them: + int num[] = { 1, 1, 2, 3, 5 }; + const int sz = sizeof (num)/sizeof(num[0]); + + +// No mismatch for empty sequences + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num), + input_iterator(num), input_iterator(num)), + input_iterator(num), input_iterator(num))); + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num), + input_iterator(num), input_iterator(num), + never_eq ), + input_iterator(num), input_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( random_access_iterator(num), random_access_iterator(num), + random_access_iterator(num), random_access_iterator(num), + never_eq ), + random_access_iterator(num), random_access_iterator(num))); + +// Empty vs. non-empty mismatch immediately + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num), + input_iterator(num), input_iterator(num + 1)), + input_iterator(num), input_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num + 1), input_iterator(num + 2), + input_iterator(num), input_iterator(num)), + input_iterator(num + 1), input_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( random_access_iterator(num + 1), random_access_iterator(num + 2), + random_access_iterator(num), random_access_iterator(num)), + random_access_iterator(num + 1), random_access_iterator(num))); + +// Single element sequences are equal if they contain the same value + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + 1), + input_iterator(num), input_iterator(num + 1)), + input_iterator(num + 1), input_iterator(num + 1))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + 1), + input_iterator(num), input_iterator(num + 1), + eq ), + input_iterator(num + 1), input_iterator(num + 1))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( random_access_iterator(num), random_access_iterator(num + 1), + random_access_iterator(num), random_access_iterator(num + 1), + eq ), + random_access_iterator(num + 1), random_access_iterator(num + 1))); + + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + 1), + input_iterator(num), input_iterator(num + 1), + never_eq ), + input_iterator(num), input_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( random_access_iterator(num), random_access_iterator(num + 1), + random_access_iterator(num), random_access_iterator(num + 1), + never_eq ), + random_access_iterator(num), random_access_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + 1), + input_iterator(num + 1), input_iterator(num + 2)), + input_iterator(num + 1), input_iterator(num + 2))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + 1), + input_iterator(num + 1), input_iterator(num + 2), + eq ), + input_iterator(num + 1), input_iterator(num + 2))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num + 2), input_iterator(num + 3), + input_iterator(num), input_iterator(num + 1)), + input_iterator(num + 2), input_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num + 2), input_iterator(num + 3), + input_iterator(num), input_iterator(num + 1), + eq ), + input_iterator(num + 2), input_iterator(num))); + + + +// Identical long sequences are equal. + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz)), + input_iterator(num + sz), input_iterator(num + sz))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz), + eq ), + input_iterator(num + sz), input_iterator(num + sz))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz), + never_eq ), + input_iterator(num), input_iterator(num))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num), input_iterator(num + sz), + random_access_iterator(num), random_access_iterator(num + sz), + never_eq ), + input_iterator(num), random_access_iterator(num))); + +// different sequences are different + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num + 1), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz)), + input_iterator(num + 2), input_iterator(num + 1))); + + BOOST_CHECK ( iter_eq ( + ba::mismatch ( input_iterator(num + 1), input_iterator(num + sz), + input_iterator(num), input_iterator(num + sz), + eq ), + input_iterator(num + 2), input_iterator(num + 1))); + +} + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test_mismatch (); +}