diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 64e8dfb..50b3044 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -106,6 +106,16 @@ Generate an increasing series Apply a functor to the elements of a sequence [endsect:for_each_n] +[section:transform_inclusive_scan transform_inclusive_scan] +[*[^[link boost.algorithm.transform_inclusive_scan transform_inclusive_scan] ] ] +Transform each element in a range then combine adjacent elements to create an output range. Inclusive scaning means that the nth input is present in the nth output. +[endsect:transform_inclusive_scan] + +[section:transform_exclusive_scan transform_exclusive_scan] +[*[^[link boost.algorithm.transform_exclusive_scan transform_exclusive_scan] ] ] +Transform each element in a range then combine adjacent elements to create an output range. Exclusive scanning means that the nth input is not present in the nth output. +[endsect:transform_exclusive_scan] + [endsect:CXX17_inner_algorithms] [endsect:CXX17] @@ -234,8 +244,6 @@ Raise a value to an integral power ([^constexpr] since C++14) * [*[^[link header.boost.algorithm.cxx17.exclusive_scan_hpp exclusive_scan] ] ] * [*[^[link header.boost.algorithm.cxx17.inclusive_scan_hpp inclusive_scan] ] ] * [*[^[link header.boost.algorithm.cxx17.reduce_hpp reduce] ] ] -* [*[^[link header.boost.algorithm.cxx17.transform_exclusive_scan_hpp transform_exclusive_scan] ] ] -* [*[^[link header.boost.algorithm.cxx17.transform_inclusive_scan_hpp transform_inclusive_scan] ] ] * [*[^[link header.boost.algorithm.cxx17.transform_reduce_hpp transform_reduce] ] ] [endsect:not_yet_documented_cxx17_algos] diff --git a/include/boost/algorithm/clamp.hpp b/include/boost/algorithm/clamp.hpp index 82a99bd..1378f95 100644 --- a/include/boost/algorithm/clamp.hpp +++ b/include/boost/algorithm/clamp.hpp @@ -26,14 +26,14 @@ #include #include #include -#include // for identity -#include // for boost::disable_if +#include // for boost::type_identity +#include // for boost::disable_if namespace boost { namespace algorithm { /// \fn clamp ( T const& val, -/// typename boost::mpl::identity::type const & lo, -/// typename boost::mpl::identity::type const & hi, Pred p ) +/// typename boost::type_identity::type const & lo, +/// typename boost::type_identity::type const & hi, Pred p ) /// \return the value "val" brought into the range [ lo, hi ] /// using the comparison predicate p. /// If p ( val, lo ) return lo. @@ -48,8 +48,8 @@ namespace boost { namespace algorithm { /// template BOOST_CXX14_CONSTEXPR T const & clamp ( T const& val, - typename boost::mpl::identity::type const & lo, - typename boost::mpl::identity::type const & hi, Pred p ) + typename boost::type_identity::type const & lo, + typename boost::type_identity::type const & hi, Pred p ) { // assert ( !p ( hi, lo )); // Can't assert p ( lo, hi ) b/c they might be equal return p ( val, lo ) ? lo : p ( hi, val ) ? hi : val; @@ -57,8 +57,8 @@ namespace boost { namespace algorithm { /// \fn clamp ( T const& val, -/// typename boost::mpl::identity::type const & lo, -/// typename boost::mpl::identity::type const & hi ) +/// typename boost::identity::type const & lo, +/// typename boost::identity::type const & hi ) /// \return the value "val" brought into the range [ lo, hi ]. /// If the value is less than lo, return lo. /// If the value is greater than "hi", return hi. @@ -70,8 +70,8 @@ namespace boost { namespace algorithm { /// template BOOST_CXX14_CONSTEXPR T const& clamp ( const T& val, - typename boost::mpl::identity::type const & lo, - typename boost::mpl::identity::type const & hi ) + typename boost::type_identity::type const & lo, + typename boost::type_identity::type const & hi ) { return boost::algorithm::clamp ( val, lo, hi, std::less()); } diff --git a/include/boost/algorithm/cxx11/is_sorted.hpp b/include/boost/algorithm/cxx11/is_sorted.hpp index 0aa8122..e02fb36 100644 --- a/include/boost/algorithm/cxx11/is_sorted.hpp +++ b/include/boost/algorithm/cxx11/is_sorted.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include // for boost::type_identity namespace boost { namespace algorithm { @@ -127,7 +127,7 @@ namespace boost { namespace algorithm { /// \param p A binary predicate that returns true if two elements are ordered. /// template - BOOST_CXX14_CONSTEXPR typename boost::lazy_disable_if_c< boost::is_same::value, boost::mpl::identity >::type + BOOST_CXX14_CONSTEXPR typename boost::lazy_disable_if_c< boost::is_same::value, boost::type_identity >::type is_sorted ( const R &range, Pred p ) { return boost::algorithm::is_sorted ( boost::begin ( range ), boost::end ( range ), p ); diff --git a/include/boost/algorithm/cxx17/transform_exclusive_scan.hpp b/include/boost/algorithm/cxx17/transform_exclusive_scan.hpp index 68318a5..86446b8 100644 --- a/include/boost/algorithm/cxx17/transform_exclusive_scan.hpp +++ b/include/boost/algorithm/cxx17/transform_exclusive_scan.hpp @@ -22,6 +22,21 @@ namespace boost { namespace algorithm { +/// \fn transform_exclusive_scan ( InputIterator first, InputIterator last, OutputIterator result, BinaryOperation bOp, UnaryOperation uOp, T init ) +/// \brief Transforms elements from the input range with uOp and then combines +/// those transformed elements with bOp such that the n-1th element and the nth +/// element are combined. Exclusivity means that the nth element is not +/// included in the nth combination. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last The end of the input sequence +/// \param result The output iterator to write the results into +/// \param bOp The operation for combining transformed input elements +/// \param uOp The operation for transforming input elements +/// \param init The initial value +/// +/// \note This function is part of the C++17 standard library template OutputIterator transform_exclusive_scan(InputIterator first, InputIterator last, diff --git a/include/boost/algorithm/cxx17/transform_inclusive_scan.hpp b/include/boost/algorithm/cxx17/transform_inclusive_scan.hpp index 3160770..9d877c0 100644 --- a/include/boost/algorithm/cxx17/transform_inclusive_scan.hpp +++ b/include/boost/algorithm/cxx17/transform_inclusive_scan.hpp @@ -22,6 +22,21 @@ namespace boost { namespace algorithm { +/// \fn transform_inclusive_scan ( InputIterator first, InputIterator last, OutputIterator result, BinaryOperation bOp, UnaryOperation uOp, T init ) +/// \brief Transforms elements from the input range with uOp and then combines +/// those transformed elements with bOp such that the n-1th element and the nth +/// element are combined. Inclusivity means that the nth element is included in +/// the nth combination. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last The end of the input sequence +/// \param result The output iterator to write the results into +/// \param bOp The operation for combining transformed input elements +/// \param uOp The operation for transforming input elements +/// \param init The initial value +/// +/// \note This function is part of the C++17 standard library template OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, @@ -37,6 +52,20 @@ OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, return result; } +/// \fn transform_inclusive_scan ( InputIterator first, InputIterator last, OutputIterator result, BinaryOperation bOp, UnaryOperation uOp, T init ) +/// \brief Transforms elements from the input range with uOp and then combines +/// those transformed elements with bOp such that the n-1th element and the nth +/// element are combined. Inclusivity means that the nth element is included in +/// the nth combination. The first value will be used as the init. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last The end of the input sequence +/// \param result The output iterator to write the results into +/// \param bOp The operation for combining transformed input elements +/// \param uOp The operation for transforming input elements +/// +/// \note This function is part of the C++17 standard library template OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, diff --git a/include/boost/algorithm/is_clamped.hpp b/include/boost/algorithm/is_clamped.hpp new file mode 100644 index 0000000..72287d3 --- /dev/null +++ b/include/boost/algorithm/is_clamped.hpp @@ -0,0 +1,72 @@ +/* + Copyright (c) Ivan Matek, Marshall Clow 2021. + + 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_clamped.hpp +/// \brief IsClamped algorithm +/// \authors Ivan Matek, Marshall Clow +/// + +#ifndef BOOST_ALGORITHM_IS_CLAMPED_HPP +#define BOOST_ALGORITHM_IS_CLAMPED_HPP + +#include // for std::less +#include + +#include // for boost::type_identity + +namespace boost { namespace algorithm { + +/// \fn is_clamped ( T const& val, +/// typename boost::type_identity::type const & lo, +/// typename boost::type_identity::type const & hi, Pred p ) +/// \returns true if value "val" is in the range [ lo, hi ] +/// using the comparison predicate p. +/// If p ( val, lo ) return false. +/// If p ( hi, val ) return false. +/// Otherwise, returns true. +/// +/// \param val The value to be checked +/// \param lo The lower bound of the range +/// \param hi The upper bound of the range +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + BOOST_CXX14_CONSTEXPR bool is_clamped( + T const& val, typename boost::type_identity::type const& lo, + typename boost::type_identity::type const& hi, Pred p) { + // assert ( !p ( hi, lo )); // Can't assert p ( lo, hi ) b/c they + // might be equal + return p(val, lo) ? false : p(hi, val) ? false : true; + } + +/// \fn is_clamped ( T const& val, +/// typename boost::type_identity::type const & lo, +/// typename boost::type_identity::type const & hi) +/// \returns true if value "val" is in the range [ lo, hi ] +/// using operator < for comparison. +/// If the value is less than lo, return false. +/// If the value is greater than hi, return false. +/// Otherwise, returns true. +/// +/// \param val The value to be checked +/// \param lo The lower bound of the range +/// \param hi The upper bound of the range +/// + + template + BOOST_CXX14_CONSTEXPR bool is_clamped ( const T& val, + typename boost::type_identity::type const & lo, + typename boost::type_identity::type const & hi ) + { + return boost::algorithm::is_clamped ( val, lo, hi, std::less()); + } + +}} + +#endif // BOOST_ALGORITHM_CLAMP_HPP diff --git a/include/boost/algorithm/string/detail/find_iterator.hpp b/include/boost/algorithm/string/detail/find_iterator.hpp index 4f90a98..c990785 100644 --- a/include/boost/algorithm/string/detail/find_iterator.hpp +++ b/include/boost/algorithm/string/detail/find_iterator.hpp @@ -40,10 +40,18 @@ namespace boost { // Protected construction/destruction // Default constructor - find_iterator_base() {} + BOOST_DEFAULTED_FUNCTION(find_iterator_base(), {}) + // Copy construction - find_iterator_base( const find_iterator_base& Other ) : + BOOST_DEFAULTED_FUNCTION(find_iterator_base( const find_iterator_base& Other ), : m_Finder(Other.m_Finder) {} + ) + + // Assignment + BOOST_DEFAULTED_FUNCTION(find_iterator_base& operator=( const find_iterator_base& Other ), { + m_Finder = Other.m_Finder; + return *this; + }) // Constructor template @@ -51,7 +59,7 @@ namespace boost { m_Finder(Finder) {} // Destructor - ~find_iterator_base() {} + BOOST_DEFAULTED_FUNCTION(~find_iterator_base(), {}) // Find operation match_type do_find( diff --git a/include/boost/algorithm/string/find_iterator.hpp b/include/boost/algorithm/string/find_iterator.hpp index 5a52d92..47c20e6 100644 --- a/include/boost/algorithm/string/find_iterator.hpp +++ b/include/boost/algorithm/string/find_iterator.hpp @@ -74,7 +74,7 @@ namespace boost { \post eof()==true */ - find_iterator() {} + BOOST_DEFAULTED_FUNCTION(find_iterator(), {}) //! Copy constructor /*! @@ -85,6 +85,18 @@ namespace boost { m_Match(Other.m_Match), m_End(Other.m_End) {} + //! Copy assignment + /*! + Assigns a copy of the find_iterator + */ + BOOST_DEFAULTED_FUNCTION(find_iterator& operator=( const find_iterator& Other ), { + if (this == &Other) return *this; + this->base_type::operator=(Other); + m_Match = Other.m_Match; + m_End = Other.m_End; + return *this; + }) + //! Constructor /*! Construct new find_iterator for a given finder @@ -248,6 +260,20 @@ namespace boost { m_bEof(Other.m_bEof) {} + //! Assignment operator + /*! + Assigns a copy of the split_iterator + */ + BOOST_DEFAULTED_FUNCTION(split_iterator& operator=( const split_iterator& Other ), { + if (this == &Other) return *this; + this->base_type::operator=(Other); + m_Match = Other.m_Match; + m_Next = Other.m_Next; + m_End = Other.m_End; + m_bEof = Other.m_bEof; + return *this; + }) + //! Constructor /*! Construct new split_iterator for a given finder diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e7091e0..5f5e73c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -29,6 +29,7 @@ alias unit_test_framework # Misc tests [ run clamp_test.cpp unit_test_framework : : : : clamp_test ] + [ run is_clamped_test.cpp unit_test_framework : : : : is_clamped_test ] [ run power_test.cpp unit_test_framework : : : : power_test ] [ compile-fail power_fail1.cpp : : : : ] diff --git a/test/is_clamped_test.cpp b/test/is_clamped_test.cpp new file mode 100644 index 0000000..575e343 --- /dev/null +++ b/test/is_clamped_test.cpp @@ -0,0 +1,246 @@ +// (C) Copyright Ivan Matek, Marshall Clow 2021. +// 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) + +#include +#include +#include +#include +#ifdef __cpp_impl_three_way_comparison +#if __has_include() +#define BOOST_IS_CLAMPED_TEST_SPACESHIP +#endif +#ifdef BOOST_IS_CLAMPED_TEST_SPACESHIP +#include +#endif +#endif +#include +#include +#include + +#define BOOST_TEST_MAIN +#include + +namespace ba = boost::algorithm; + +BOOST_CONSTEXPR bool intGreater(int lhs, int rhs) { return lhs > rhs; } + +class custom { + public: + custom(int x) : v(x) {} + custom(const custom &rhs) : v(rhs.v) {} + + bool operator<(const custom &rhs) const { return v < rhs.v; } + bool operator==(const custom &rhs) const { + return v == rhs.v; + } // need this for the test + int v; +}; + +static bool customLess(const custom &lhs, const custom &rhs) { return lhs.v < rhs.v; } + +void test_ints() { + // Inside the range, equal to the endpoints, and outside the endpoints. + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 3, 1, 6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 1, 1, 6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 6, 1, 6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0, 1, 6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 7, 1, 6 )); + + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 3, 6, 1, intGreater )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 1, 6, 1, intGreater )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 6, 6, 1, intGreater )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0, 6, 1, intGreater )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 7, 6, 1, intGreater )); + + // Negative numbers + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( -3, -6, -1 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( -1, -6, -1 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( -6, -6, -1 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0, -6, -1 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( -7, -6, -1 )); + + // Mixed positive and negative numbers + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 1, -5, 5 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( -5, -5, 5 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 5, -5, 5 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( -6, -5, 5 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 6, -5, 5 )); + + // Unsigned + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 5U, 1U, 6U )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 1U, 1U, 6U )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 6U, 1U, 6U )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0U, 1U, 6U )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 8U, 1U, 6U )); + + // Mixed (1) + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 5U, 1, 6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 1U, 1, 6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 6U, 1, 6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0U, 1, 6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 8U, 1, 6 )); + + // Mixed (2) + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 5U, 1, 6. )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 1U, 1, 6. )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 6U, 1, 6. )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0U, 1, 6. )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 8U, 1, 6. )); + + // float->short conversion does not round + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( 50, 50.999, 100 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 50, 51.001, 100 )); +} + +void test_floats() { + // If floats are IEEE754 certain floats have exact representations. + if (std::numeric_limits::is_iec559) { + const float lo = 0.125; + const float hi = 0.625; + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( lo, lo, hi )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( hi, lo, hi )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( lo + 0.01, lo, hi )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( lo - 0.01, lo, hi )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( hi + 0.01, lo, hi )); + // If we have nextafterf we can be more precise. + #if __cplusplus >= 201103L + assert(lo < hi); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( hi, lo, hi )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( std::nextafterf( lo, hi ), lo, hi )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( std::nextafterf( hi, lo ), lo, hi )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( (lo + hi) / 2, lo, hi )); + // 1.0 is just for direction of nextafterf, value of 1.0 is not significant. + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::nextafterf( lo, lo - 1.0f ), lo, hi )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::nextafterf( hi, hi + 1.0f ), lo, hi )); + #endif + } +} + +void test_std_string() { + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( std::string("a3"), std::string("a1"), std::string("a6") )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( std::string("a1"), std::string("a1"), std::string("a6") )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( std::string("a6"), std::string("a1"), std::string("a6") )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::string("a7"), std::string("a1"), std::string("a6") )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::string("a0"), std::string("a1"), std::string("a6") )); +} + +void test_custom() { + // Inside the range, equal to the endpoints, and outside the endpoints. + const custom c0(0); + const custom c1(1); + const custom c3(3); + const custom c6(6); + const custom c7(7); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( c3, c1, c6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( c1, c1, c6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( c6, c1, c6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c0, c1, c6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c7, c1, c6 )); + + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( c3, c1, c6, customLess )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( c1, c1, c6, customLess )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped ( c6, c1, c6, customLess )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c0, c1, c6, customLess )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c7, c1, c6, customLess )); +} + +void test_point_interval() { + BOOST_CHECK_EQUAL(true, ba::is_clamped(1, 1, 1)); + BOOST_CHECK_EQUAL(false, ba::is_clamped(0, 1, 1)); + BOOST_CHECK_EQUAL(false, ba::is_clamped(2, 1, 1)); +} + +void test_first_argument_determines_types() { + // all arguments are int + BOOST_CHECK_EQUAL(true, ba::is_clamped(5, 5.9, 6.1)); + BOOST_CHECK_EQUAL(true, ba::is_clamped(6, 5.9, 6.1)); + // all arguments are double + BOOST_CHECK_EQUAL(false, ba::is_clamped(5.0, 5.9, 6.1)); + BOOST_CHECK_EQUAL(false, ba::is_clamped(6.2, 5.9, 6.1)); +} + +void test_constexpr() { + #if __cplusplus >= 201402L + { + constexpr bool is_clamped = (ba::is_clamped ( 3, 1, 6 )); + BOOST_CHECK_EQUAL (true, is_clamped ); + } + { + constexpr bool is_clamped = (ba::is_clamped ( 1, 1, 6 )); + BOOST_CHECK_EQUAL (true, is_clamped ); + } + { + constexpr bool is_clamped = (ba::is_clamped ( 6, 1, 6 )); + BOOST_CHECK_EQUAL (true, is_clamped ); + } + { + constexpr bool is_clamped = (ba::is_clamped ( 0, 1, 6 )); + BOOST_CHECK_EQUAL(false, is_clamped ); + } + { + constexpr bool is_clamped = (ba::is_clamped ( 7, 1, 6 )); + BOOST_CHECK_EQUAL(false, is_clamped ); + } + #endif +} + + +#ifdef BOOST_IS_CLAMPED_TEST_SPACESHIP +struct custom_with_spaceship { + int v; + auto operator<=>(const custom_with_spaceship&) const = default; +}; +#endif + +void test_spaceship() { + #ifdef BOOST_IS_CLAMPED_TEST_SPACESHIP + // Inside the range, equal to the endpoints, and outside the endpoints. + const custom_with_spaceship c0(0); + const custom_with_spaceship c1(1); + const custom_with_spaceship c3(3); + const custom_with_spaceship c6(6); + const custom_with_spaceship c7(7); + BOOST_CHECK_EQUAL ( true, ba::is_clamped (c3, c1, c6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped (c1, c1, c6 )); + BOOST_CHECK_EQUAL ( true, ba::is_clamped (c6, c1, c6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped (c0, c1, c6 )); + BOOST_CHECK_EQUAL ( false, ba::is_clamped (c7, c1, c6 )); + { + constexpr custom_with_spaceship c1(1); + constexpr custom_with_spaceship c3(3); + constexpr custom_with_spaceship c6(6); + constexpr bool clamped = ba::is_clamped (c3, c1, c6 ); + BOOST_CHECK_EQUAL ( true, clamped ); + } + #endif +} + +BOOST_AUTO_TEST_CASE(test_main) { + test_ints(); + test_floats(); + test_std_string(); + test_custom(); + test_point_interval(); + test_first_argument_determines_types(); + test_constexpr(); + test_spaceship(); +} + +#if __cplusplus >= 201103L +typedef std::tuple test_types_tuple; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_extremes, T, test_types_tuple) { + const T max = std::numeric_limits::max(); + BOOST_CHECK_EQUAL(true, ba::is_clamped( max, max, max )); + BOOST_CHECK_EQUAL(true, ba::is_clamped( max, max - 1, max )); + BOOST_CHECK_EQUAL(false, ba::is_clamped( max - 1, max, max )); + + const T min = std::numeric_limits::min(); + BOOST_CHECK_EQUAL(true, ba::is_clamped( min, min, min )); + BOOST_CHECK_EQUAL(true, ba::is_clamped( min, min, min + 1 )); + BOOST_CHECK_EQUAL(false, ba::is_clamped( min, min + 1, min + 1 )); +} +#endif