| 
 | 1 | +//  (C) Copyright Ivan Matek, Marshall Clow 2021.  | 
 | 2 | +//  Use, modification and distribution are subject to the  | 
 | 3 | +//  Boost Software License, Version 1.0. (See accompanying file  | 
 | 4 | +//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)  | 
 | 5 | + | 
 | 6 | +#include <boost/algorithm/is_clamped.hpp>  | 
 | 7 | +#include <boost/algorithm/clamp.hpp>  | 
 | 8 | +#include <cmath>  | 
 | 9 | +#include <cstdint>  | 
 | 10 | +#ifdef __cpp_impl_three_way_comparison  | 
 | 11 | +#if __has_include(<compare>)  | 
 | 12 | +#define BOOST_IS_CLAMPED_TEST_SPACESHIP  | 
 | 13 | +#endif  | 
 | 14 | +#ifdef BOOST_IS_CLAMPED_TEST_SPACESHIP  | 
 | 15 | +#include <compare>  | 
 | 16 | +#endif  | 
 | 17 | +#endif  | 
 | 18 | +#include <limits>  | 
 | 19 | +#include <string>  | 
 | 20 | +#include <tuple>  | 
 | 21 | + | 
 | 22 | +#define BOOST_TEST_MAIN  | 
 | 23 | +#include <boost/test/unit_test.hpp>  | 
 | 24 | + | 
 | 25 | +namespace ba = boost::algorithm;  | 
 | 26 | + | 
 | 27 | +BOOST_CONSTEXPR bool intGreater(int lhs, int rhs) { return lhs > rhs; }  | 
 | 28 | + | 
 | 29 | +class custom {  | 
 | 30 | + public:  | 
 | 31 | +  custom(int x) : v(x) {}  | 
 | 32 | +  custom(const custom &rhs) : v(rhs.v) {}  | 
 | 33 | + | 
 | 34 | +  bool operator<(const custom &rhs) const { return v < rhs.v; }  | 
 | 35 | +  bool operator==(const custom &rhs) const {  | 
 | 36 | +    return v == rhs.v;  | 
 | 37 | +  }  // need this for the test  | 
 | 38 | +  int v;  | 
 | 39 | +};  | 
 | 40 | + | 
 | 41 | +static bool customLess(const custom &lhs, const custom &rhs) { return lhs.v < rhs.v; }  | 
 | 42 | + | 
 | 43 | +void test_ints() {  | 
 | 44 | +  //  Inside the range, equal to the endpoints, and outside the endpoints.  | 
 | 45 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 3, 1, 6 ));  | 
 | 46 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 1, 1, 6 ));  | 
 | 47 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 6, 1, 6 ));  | 
 | 48 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0, 1, 6 ));  | 
 | 49 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 7, 1, 6 ));  | 
 | 50 | + | 
 | 51 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 3, 6, 1, intGreater ));  | 
 | 52 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 1, 6, 1, intGreater ));  | 
 | 53 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 6, 6, 1, intGreater ));  | 
 | 54 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0, 6, 1, intGreater ));  | 
 | 55 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 7, 6, 1, intGreater ));  | 
 | 56 | + | 
 | 57 | +  //  Negative numbers  | 
 | 58 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( -3, -6, -1 ));  | 
 | 59 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( -1, -6, -1 ));  | 
 | 60 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( -6, -6, -1 ));  | 
 | 61 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped (  0, -6, -1 ));  | 
 | 62 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( -7, -6, -1 ));  | 
 | 63 | + | 
 | 64 | +  //  Mixed positive and negative numbers  | 
 | 65 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped (  1, -5, 5 ));  | 
 | 66 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( -5, -5, 5 ));  | 
 | 67 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped (  5, -5, 5 ));  | 
 | 68 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( -6, -5, 5 ));  | 
 | 69 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped (  6, -5, 5 ));  | 
 | 70 | + | 
 | 71 | +  //  Unsigned  | 
 | 72 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 5U, 1U, 6U ));  | 
 | 73 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 1U, 1U, 6U ));  | 
 | 74 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 6U, 1U, 6U ));  | 
 | 75 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0U, 1U, 6U ));  | 
 | 76 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 8U, 1U, 6U ));  | 
 | 77 | + | 
 | 78 | +  //  Mixed (1)  | 
 | 79 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 5U, 1, 6 ));  | 
 | 80 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 1U, 1, 6 ));  | 
 | 81 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 6U, 1, 6 ));  | 
 | 82 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0U, 1, 6 ));  | 
 | 83 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 8U, 1, 6 ));  | 
 | 84 | + | 
 | 85 | +  //  Mixed (2)  | 
 | 86 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 5U, 1, 6. ));  | 
 | 87 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 1U, 1, 6. ));  | 
 | 88 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 6U, 1, 6. ));  | 
 | 89 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 0U, 1, 6. ));  | 
 | 90 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 8U, 1, 6. ));  | 
 | 91 | + | 
 | 92 | +  // float->short conversion does not round  | 
 | 93 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( 50, 50.999, 100 ));  | 
 | 94 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( 50, 51.001, 100 ));  | 
 | 95 | +}  | 
 | 96 | + | 
 | 97 | +void test_floats() {  | 
 | 98 | +  //  If floats are IEEE754 certain floats have exact representations.  | 
 | 99 | +  if (std::numeric_limits<float>::is_iec559) {  | 
 | 100 | +    const float lo = 0.125;  | 
 | 101 | +    const float hi = 0.625;  | 
 | 102 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( lo, lo, hi ));  | 
 | 103 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( hi, lo, hi ));  | 
 | 104 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( lo + 0.01, lo, hi ));  | 
 | 105 | +    BOOST_CHECK_EQUAL ( false, ba::is_clamped ( lo - 0.01, lo, hi ));  | 
 | 106 | +    BOOST_CHECK_EQUAL ( false, ba::is_clamped ( hi + 0.01, lo, hi ));  | 
 | 107 | +    // If we have nextafterf we can be more precise.  | 
 | 108 | +    #if __cplusplus >= 201103L  | 
 | 109 | +    assert(lo < hi);  | 
 | 110 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( hi, lo, hi ));  | 
 | 111 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( std::nextafterf( lo, hi ), lo, hi ));  | 
 | 112 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( std::nextafterf( hi, lo ), lo, hi ));  | 
 | 113 | +    BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( (lo + hi) / 2, lo, hi ));  | 
 | 114 | +    // 1.0 is just for direction of nextafterf, value of 1.0 is not significant.  | 
 | 115 | +    BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::nextafterf( lo, lo - 1.0f ), lo, hi ));  | 
 | 116 | +    BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::nextafterf( hi, hi + 1.0f ), lo, hi ));  | 
 | 117 | +    #endif  | 
 | 118 | +  }  | 
 | 119 | +}  | 
 | 120 | + | 
 | 121 | +void test_std_string() {  | 
 | 122 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( std::string("a3"), std::string("a1"), std::string("a6") ));  | 
 | 123 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( std::string("a1"), std::string("a1"), std::string("a6") ));  | 
 | 124 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( std::string("a6"), std::string("a1"), std::string("a6") ));  | 
 | 125 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::string("a7"), std::string("a1"), std::string("a6") ));  | 
 | 126 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( std::string("a0"), std::string("a1"), std::string("a6") ));  | 
 | 127 | +}  | 
 | 128 | + | 
 | 129 | +void test_custom() {  | 
 | 130 | +  //  Inside the range, equal to the endpoints, and outside the endpoints.  | 
 | 131 | +  const custom c0(0);  | 
 | 132 | +  const custom c1(1);  | 
 | 133 | +  const custom c3(3);  | 
 | 134 | +  const custom c6(6);  | 
 | 135 | +  const custom c7(7);  | 
 | 136 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( c3, c1, c6 ));  | 
 | 137 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( c1, c1, c6 ));  | 
 | 138 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( c6, c1, c6 ));  | 
 | 139 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c0, c1, c6 ));  | 
 | 140 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c7, c1, c6 ));  | 
 | 141 | + | 
 | 142 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( c3, c1, c6, customLess ));  | 
 | 143 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( c1, c1, c6, customLess ));  | 
 | 144 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped ( c6, c1, c6, customLess ));  | 
 | 145 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c0, c1, c6, customLess ));  | 
 | 146 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped ( c7, c1, c6, customLess ));  | 
 | 147 | +}  | 
 | 148 | + | 
 | 149 | +void test_point_interval() {  | 
 | 150 | +    BOOST_CHECK_EQUAL(true, ba::is_clamped(1, 1, 1));  | 
 | 151 | +    BOOST_CHECK_EQUAL(false, ba::is_clamped(0, 1, 1));  | 
 | 152 | +    BOOST_CHECK_EQUAL(false, ba::is_clamped(2, 1, 1));  | 
 | 153 | +}  | 
 | 154 | + | 
 | 155 | +void test_first_argument_determines_types() {  | 
 | 156 | +    // all arguments are int  | 
 | 157 | +    BOOST_CHECK_EQUAL(true, ba::is_clamped(5, 5.9, 6.1));  | 
 | 158 | +    BOOST_CHECK_EQUAL(true, ba::is_clamped(6, 5.9, 6.1));  | 
 | 159 | +    // all arguments are double  | 
 | 160 | +    BOOST_CHECK_EQUAL(false, ba::is_clamped(5.0, 5.9, 6.1));  | 
 | 161 | +    BOOST_CHECK_EQUAL(false, ba::is_clamped(6.2, 5.9, 6.1));  | 
 | 162 | +}  | 
 | 163 | + | 
 | 164 | +void test_constexpr() {  | 
 | 165 | +  #if __cplusplus >= 201402L  | 
 | 166 | +  {  | 
 | 167 | +    constexpr bool is_clamped = (ba::is_clamped ( 3, 1, 6 ));  | 
 | 168 | +    BOOST_CHECK_EQUAL (true, is_clamped );  | 
 | 169 | +  }  | 
 | 170 | +  {  | 
 | 171 | +    constexpr bool is_clamped = (ba::is_clamped ( 1, 1, 6 ));  | 
 | 172 | +    BOOST_CHECK_EQUAL (true, is_clamped );  | 
 | 173 | +  }  | 
 | 174 | +  {  | 
 | 175 | +    constexpr bool is_clamped = (ba::is_clamped ( 6, 1, 6 ));  | 
 | 176 | +    BOOST_CHECK_EQUAL (true, is_clamped );  | 
 | 177 | +  }  | 
 | 178 | +  {  | 
 | 179 | +    constexpr bool is_clamped = (ba::is_clamped ( 0, 1, 6 ));  | 
 | 180 | +    BOOST_CHECK_EQUAL(false, is_clamped );  | 
 | 181 | +  }  | 
 | 182 | +  {  | 
 | 183 | +    constexpr bool is_clamped = (ba::is_clamped ( 7, 1, 6 ));  | 
 | 184 | +    BOOST_CHECK_EQUAL(false, is_clamped );  | 
 | 185 | +  }  | 
 | 186 | +  #endif  | 
 | 187 | +}  | 
 | 188 | + | 
 | 189 | + | 
 | 190 | +#ifdef BOOST_IS_CLAMPED_TEST_SPACESHIP  | 
 | 191 | +struct custom_with_spaceship {  | 
 | 192 | +  int v;  | 
 | 193 | +  auto operator<=>(const custom_with_spaceship&) const = default;  | 
 | 194 | +};  | 
 | 195 | +#endif  | 
 | 196 | + | 
 | 197 | +void test_spaceship() {  | 
 | 198 | +  #ifdef BOOST_IS_CLAMPED_TEST_SPACESHIP  | 
 | 199 | +  //  Inside the range, equal to the endpoints, and outside the endpoints.  | 
 | 200 | +  const custom_with_spaceship c0(0);  | 
 | 201 | +  const custom_with_spaceship c1(1);  | 
 | 202 | +  const custom_with_spaceship c3(3);  | 
 | 203 | +  const custom_with_spaceship c6(6);  | 
 | 204 | +  const custom_with_spaceship c7(7);  | 
 | 205 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped (c3, c1, c6 ));  | 
 | 206 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped (c1, c1, c6 ));  | 
 | 207 | +  BOOST_CHECK_EQUAL ( true,  ba::is_clamped (c6, c1, c6 ));  | 
 | 208 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped (c0, c1, c6 ));  | 
 | 209 | +  BOOST_CHECK_EQUAL ( false, ba::is_clamped (c7, c1, c6 ));  | 
 | 210 | +  {  | 
 | 211 | +    constexpr custom_with_spaceship c1(1);  | 
 | 212 | +    constexpr custom_with_spaceship c3(3);  | 
 | 213 | +    constexpr custom_with_spaceship c6(6);  | 
 | 214 | +    constexpr bool clamped = ba::is_clamped (c3, c1, c6 );  | 
 | 215 | +    BOOST_CHECK_EQUAL ( true, clamped );  | 
 | 216 | +  }  | 
 | 217 | +  #endif  | 
 | 218 | +}  | 
 | 219 | + | 
 | 220 | +BOOST_AUTO_TEST_CASE(test_main) {  | 
 | 221 | +  test_ints();  | 
 | 222 | +  test_floats();  | 
 | 223 | +  test_std_string();  | 
 | 224 | +  test_custom();  | 
 | 225 | +  test_point_interval();  | 
 | 226 | +  test_first_argument_determines_types();  | 
 | 227 | +  test_constexpr();  | 
 | 228 | +  test_spaceship();  | 
 | 229 | +}  | 
 | 230 | + | 
 | 231 | +#if __cplusplus >= 201103L  | 
 | 232 | +typedef std::tuple<std::uint8_t, std::int8_t, std::uint16_t, std::int16_t,  | 
 | 233 | +                   std::int32_t, std::uint32_t, std::int64_t, std::uint64_t> test_types_tuple;  | 
 | 234 | + | 
 | 235 | +BOOST_AUTO_TEST_CASE_TEMPLATE(test_extremes, T, test_types_tuple) {  | 
 | 236 | +  const T max = std::numeric_limits<T>::max();  | 
 | 237 | +  BOOST_CHECK_EQUAL(true,  ba::is_clamped( max, max, max ));  | 
 | 238 | +  BOOST_CHECK_EQUAL(true,  ba::is_clamped( max, max - 1, max ));  | 
 | 239 | +  BOOST_CHECK_EQUAL(false, ba::is_clamped( max - 1, max, max ));  | 
 | 240 | + | 
 | 241 | +  const T min = std::numeric_limits<T>::min();  | 
 | 242 | +  BOOST_CHECK_EQUAL(true,  ba::is_clamped( min, min, min ));  | 
 | 243 | +  BOOST_CHECK_EQUAL(true,  ba::is_clamped( min, min, min + 1 ));  | 
 | 244 | +  BOOST_CHECK_EQUAL(false, ba::is_clamped( min, min + 1, min + 1 ));  | 
 | 245 | +}  | 
 | 246 | +#endif  | 
0 commit comments