1// (C) Copyright Jesse Williamson 2009
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 <iostream>
7#include <vector>
8
9#include <boost/config.hpp>
10#include <boost/algorithm/clamp.hpp>
11
12#define BOOST_TEST_MAIN
13#include <boost/test/unit_test.hpp>
14
15namespace ba = boost::algorithm;
16
17bool intGreater ( int lhs, int rhs ) { return lhs > rhs; }
18bool doubleGreater ( double lhs, double rhs ) { return lhs > rhs; }
19
20class custom {
21public:
22 custom ( int x ) : v(x) {}
23 custom ( const custom &rhs ) : v(rhs.v) {}
24 ~custom () {}
25 custom & operator = ( const custom &rhs ) { v = rhs.v; return *this; }
26
27 bool operator < ( const custom &rhs ) const { return v < rhs.v; }
28 bool operator == ( const custom &rhs ) const { return v == rhs.v; } // need this for the test
29
30 std::ostream & print ( std::ostream &os ) const { return os << v; }
31
32 int v;
33 };
34
35std::ostream & operator << ( std::ostream & os, const custom &x ) { return x.print ( os ); }
36
37bool customLess ( const custom &lhs, const custom &rhs ) { return lhs.v < rhs.v; }
38
39void test_ints()
40{
41
42// Inside the range, equal to the endpoints, and outside the endpoints.
43 BOOST_CHECK_EQUAL ( 3, ba::clamp ( 3, 1, 10 ));
44 BOOST_CHECK_EQUAL ( 1, ba::clamp ( 1, 1, 10 ));
45 BOOST_CHECK_EQUAL ( 1, ba::clamp ( 0, 1, 10 ));
46 BOOST_CHECK_EQUAL ( 10, ba::clamp ( 10, 1, 10 ));
47 BOOST_CHECK_EQUAL ( 10, ba::clamp ( 11, 1, 10 ));
48
49 BOOST_CHECK_EQUAL ( 3, ba::clamp ( 3, 10, 1, intGreater ));
50 BOOST_CHECK_EQUAL ( 1, ba::clamp ( 1, 10, 1, intGreater ));
51 BOOST_CHECK_EQUAL ( 1, ba::clamp ( 0, 10, 1, intGreater ));
52 BOOST_CHECK_EQUAL ( 10, ba::clamp ( 10, 10, 1, intGreater ));
53 BOOST_CHECK_EQUAL ( 10, ba::clamp ( 11, 10, 1, intGreater ));
54
55// Negative numbers
56 BOOST_CHECK_EQUAL ( -3, ba::clamp ( -3, -10, -1 ));
57 BOOST_CHECK_EQUAL ( -1, ba::clamp ( -1, -10, -1 ));
58 BOOST_CHECK_EQUAL ( -1, ba::clamp ( 0, -10, -1 ));
59 BOOST_CHECK_EQUAL ( -10, ba::clamp ( -10, -10, -1 ));
60 BOOST_CHECK_EQUAL ( -10, ba::clamp ( -11, -10, -1 ));
61
62// Mixed positive and negative numbers
63 BOOST_CHECK_EQUAL ( 5, ba::clamp ( 5, -10, 10 ));
64 BOOST_CHECK_EQUAL ( -10, ba::clamp ( -10, -10, 10 ));
65 BOOST_CHECK_EQUAL ( -10, ba::clamp ( -15, -10, 10 ));
66 BOOST_CHECK_EQUAL ( 10, ba::clamp ( 10, -10, 10 ));
67 BOOST_CHECK_EQUAL ( 10, ba::clamp ( 15, -10, 10 ));
68
69// Unsigned
70 BOOST_CHECK_EQUAL ( 5U, ba::clamp ( 5U, 1U, 10U ));
71 BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 1U, 1U, 10U ));
72 BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 0U, 1U, 10U ));
73 BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 10U, 1U, 10U ));
74 BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 15U, 1U, 10U ));
75
76// Mixed (1)
77 BOOST_CHECK_EQUAL ( 5U, ba::clamp ( 5U, 1, 10 ));
78 BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 1U, 1, 10 ));
79 BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 0U, 1, 10 ));
80 BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 10U, 1, 10 ));
81 BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 15U, 1, 10 ));
82
83// Mixed (3)
84 BOOST_CHECK_EQUAL ( 5U, ba::clamp ( 5U, 1, 10. ));
85 BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 1U, 1, 10. ));
86 BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 0U, 1, 10. ));
87 BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 10U, 1, 10. ));
88 BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 15U, 1, 10. ));
89
90 short foo = 50;
91 BOOST_CHECK_EQUAL ( 56, ba::clamp ( foo, 56.9, 129 ));
92 BOOST_CHECK_EQUAL ( 24910, ba::clamp ( foo, 12345678, 123456999 ));
93 }
94
95
96void test_floats()
97{
98
99// Inside the range, equal to the endpoints, and outside the endpoints.
100 BOOST_CHECK_EQUAL ( 3.0, ba::clamp ( 3.0, 1.0, 10.0 ));
101 BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 1.0, 1.0, 10.0 ));
102 BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 0.0, 1.0, 10.0 ));
103 BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 10.0, 1.0, 10.0 ));
104 BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 11.0, 1.0, 10.0 ));
105
106 BOOST_CHECK_EQUAL ( 3.0, ba::clamp ( 3.0, 10.0, 1.0, doubleGreater ));
107 BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 1.0, 10.0, 1.0, doubleGreater ));
108 BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 0.0, 10.0, 1.0, doubleGreater ));
109 BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 10.0, 10.0, 1.0, doubleGreater ));
110 BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 11.0, 10.0, 1.0, doubleGreater ));
111
112// Negative numbers
113 BOOST_CHECK_EQUAL ( -3.f, ba::clamp ( -3.f, -10.f, -1.f ));
114 BOOST_CHECK_EQUAL ( -1.f, ba::clamp ( -1.f, -10.f, -1.f ));
115 BOOST_CHECK_EQUAL ( -1.f, ba::clamp ( 0.f, -10.f, -1.f ));
116 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10.f, -1.f ));
117 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -11.f, -10.f, -1.f ));
118
119// Mixed positive and negative numbers
120 BOOST_CHECK_EQUAL ( 5.f, ba::clamp ( 5.f, -10.f, 10.f ));
121 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10.f, 10.f ));
122 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -15.f, -10.f, 10.f ));
123 BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 10.f, -10.f, 10.f ));
124 BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 15.f, -10.f, 10.f ));
125
126// Mixed (1)
127 BOOST_CHECK_EQUAL ( 5.f, ba::clamp ( 5.f, -10., 10. ));
128 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10., 10. ));
129 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -15.f, -10., 10. ));
130 BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 10.f, -10., 10. ));
131 BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 15.f, -10., 10. ));
132
133// Mixed (2)
134 BOOST_CHECK_EQUAL ( 5.f, ba::clamp ( 5.f, -10, 10 ));
135 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10, 10 ));
136 BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -15.f, -10, 10 ));
137 BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 10.f, -10, 10 ));
138 BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 15.f, -10, 10 ));
139}
140
141void test_custom()
142{
143
144// Inside the range, equal to the endpoints, and outside the endpoints.
145 BOOST_CHECK_EQUAL ( custom( 3), ba::clamp ( custom( 3), custom(1), custom(10)));
146 BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 1), custom(1), custom(10)));
147 BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 0), custom(1), custom(10)));
148 BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(10), custom(1), custom(10)));
149 BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(11), custom(1), custom(10)));
150
151 BOOST_CHECK_EQUAL ( custom( 3), ba::clamp ( custom( 3), custom(1), custom(10), customLess ));
152 BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 1), custom(1), custom(10), customLess ));
153 BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 0), custom(1), custom(10), customLess ));
154 BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(10), custom(1), custom(10), customLess ));
155 BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(11), custom(1), custom(10), customLess ));
156
157// Fail!!
158// BOOST_CHECK_EQUAL ( custom(1), ba::clamp ( custom(11), custom(1), custom(10)));
159}
160
161#define elementsof(v) (sizeof (v) / sizeof (v[0]))
162#define a_begin(v) (&v[0])
163#define a_end(v) (v + elementsof (v))
164#define a_range(v) v
165#define b_e(v) a_begin(v),a_end(v)
166
167void test_int_range ()
168{
169 int inputs [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 19, 99, 999, -1, -3, -99, 234234 };
170 int outputs [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, -1, -1, -1, 10 };
171 std::vector<int> results;
172 std::vector<int> in_v;
173
174 std::copy ( a_begin(inputs), a_end(inputs), std::back_inserter ( in_v ));
175
176 ba::clamp_range ( a_begin(inputs), a_end(inputs), std::back_inserter ( results ), -1, 10 );
177 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
178 results.clear ();
179 ba::clamp_range ( in_v.begin (), in_v.end (), std::back_inserter ( results ), -1, 10 );
180 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
181 results.clear ();
182
183 ba::clamp_range ( a_begin(inputs), a_end(inputs), std::back_inserter ( results ), 10, -1, intGreater );
184 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
185 results.clear ();
186 ba::clamp_range ( in_v.begin (), in_v.end (), std::back_inserter ( results ), 10, -1, intGreater );
187 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
188 results.clear ();
189
190 ba::clamp_range ( a_range(inputs), std::back_inserter ( results ), -1, 10 );
191 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
192 results.clear ();
193 ba::clamp_range ( in_v, std::back_inserter ( results ), -1, 10 );
194 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
195 results.clear ();
196
197 ba::clamp_range ( a_range(inputs), std::back_inserter ( results ), 10, -1, intGreater );
198 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
199 results.clear ();
200 ba::clamp_range ( in_v, std::back_inserter ( results ), 10, -1, intGreater );
201 BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
202 results.clear ();
203
204 int junk[elementsof(inputs)];
205 ba::clamp_range ( inputs, junk, 10, -1, intGreater );
206 BOOST_CHECK ( std::equal ( b_e(junk), outputs ));
207}
208
209BOOST_AUTO_TEST_CASE( test_main )
210{
211 test_ints ();
212 test_floats ();
213 test_custom ();
214
215 test_int_range ();
216// test_float_range ();
217// test_custom_range ();
218}
219