proxygen
ConstexprMathTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <folly/ConstexprMath.h>
18 
19 #include <limits>
20 #include <type_traits>
21 
22 #include <folly/lang/Bits.h>
24 
25 namespace {
26 class ConstexprMathTest : public testing::Test {};
27 } // namespace
28 
29 TEST_F(ConstexprMathTest, constexpr_min) {
30  constexpr auto x = uint16_t(3);
31  constexpr auto y = uint16_t(7);
32  constexpr auto z = uint16_t(4);
33  constexpr auto a = folly::constexpr_min(x, y, z);
34  EXPECT_EQ(3, a);
35  EXPECT_TRUE((std::is_same<const uint16_t, decltype(a)>::value));
36 }
37 
38 TEST_F(ConstexprMathTest, constexpr_max) {
39  constexpr auto x = uint16_t(3);
40  constexpr auto y = uint16_t(7);
41  constexpr auto z = uint16_t(4);
42  constexpr auto a = folly::constexpr_max(x, y, z);
43  EXPECT_EQ(7, a);
44  EXPECT_TRUE((std::is_same<const uint16_t, decltype(a)>::value));
45 }
46 
47 TEST_F(ConstexprMathTest, constexpr_clamp) {
48  constexpr auto lo = uint16_t(3);
49  constexpr auto hi = uint16_t(7);
50  constexpr auto x = folly::constexpr_clamp(uint16_t(2), lo, hi);
51  constexpr auto y = folly::constexpr_clamp(uint16_t(5), lo, hi);
52  constexpr auto z = folly::constexpr_clamp(uint16_t(8), lo, hi);
53  EXPECT_EQ(3, x);
54  EXPECT_EQ(5, y);
55  EXPECT_EQ(7, z);
56  EXPECT_TRUE((std::is_same<const uint16_t, decltype(y)>::value));
57 }
58 
59 TEST_F(ConstexprMathTest, constexpr_abs_unsigned) {
60  constexpr auto v = uint32_t(17);
61  constexpr auto a = folly::constexpr_abs(v);
62  EXPECT_EQ(17, a);
63  EXPECT_TRUE((std::is_same<const uint32_t, decltype(a)>::value));
64 }
65 
66 TEST_F(ConstexprMathTest, constexpr_abs_signed_positive) {
67  constexpr auto v = int32_t(17);
68  constexpr auto a = folly::constexpr_abs(v);
69  EXPECT_EQ(17, a);
70  EXPECT_TRUE((std::is_same<const uint32_t, decltype(a)>::value));
71 }
72 
73 TEST_F(ConstexprMathTest, constexpr_abs_signed_negative) {
74  constexpr auto v = int32_t(-17);
75  constexpr auto a = folly::constexpr_abs(v);
76  EXPECT_EQ(17, a);
77  EXPECT_TRUE((std::is_same<const uint32_t, decltype(a)>::value));
78 }
79 
80 TEST_F(ConstexprMathTest, constexpr_abs_float_positive) {
81  constexpr auto v = 17.5f;
82  constexpr auto a = folly::constexpr_abs(v);
83  EXPECT_EQ(17.5, a);
84  EXPECT_TRUE((std::is_same<const float, decltype(a)>::value));
85 }
86 
87 TEST_F(ConstexprMathTest, constexpr_abs_float_negative) {
88  constexpr auto v = -17.5f;
89  constexpr auto a = folly::constexpr_abs(v);
90  EXPECT_EQ(17.5, a);
91  EXPECT_TRUE((std::is_same<const float, decltype(a)>::value));
92 }
93 
94 TEST_F(ConstexprMathTest, constexpr_abs_double_positive) {
95  constexpr auto v = 17.5;
96  constexpr auto a = folly::constexpr_abs(v);
97  EXPECT_EQ(17.5, a);
98  EXPECT_TRUE((std::is_same<const double, decltype(a)>::value));
99 }
100 
101 TEST_F(ConstexprMathTest, constexpr_abs_double_negative) {
102  constexpr auto v = -17.5;
103  constexpr auto a = folly::constexpr_abs(v);
104  EXPECT_EQ(17.5, a);
105  EXPECT_TRUE((std::is_same<const double, decltype(a)>::value));
106 }
107 
108 TEST_F(ConstexprMathTest, constexpr_log2_1) {
109  constexpr auto v = 1ull;
110  constexpr auto a = folly::constexpr_log2(v);
111  EXPECT_EQ(0ull, a);
112  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
113 }
114 
115 TEST_F(ConstexprMathTest, constexpr_log2_2) {
116  constexpr auto v = 2ull;
117  constexpr auto a = folly::constexpr_log2(v);
118  EXPECT_EQ(1ull, a);
119  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
120 }
121 
122 TEST_F(ConstexprMathTest, constexpr_log2_64) {
123  constexpr auto v = 64ull;
124  constexpr auto a = folly::constexpr_log2(v);
125  EXPECT_EQ(6ull, a);
126  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
127 }
128 
129 TEST_F(ConstexprMathTest, constexpr_log2_ceil_1) {
130  constexpr auto v = 1ull;
131  constexpr auto a = folly::constexpr_log2_ceil(v);
132  EXPECT_EQ(0ull, a);
133  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
134 }
135 
136 TEST_F(ConstexprMathTest, constexpr_log2_ceil_2) {
137  constexpr auto v = 2ull;
138  constexpr auto a = folly::constexpr_log2_ceil(v);
139  EXPECT_EQ(1ull, a);
140  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
141 }
142 
143 TEST_F(ConstexprMathTest, constexpr_log2_ceil_3) {
144  constexpr auto v = 3ull;
145  constexpr auto a = folly::constexpr_log2_ceil(v);
146  EXPECT_EQ(2ull, a);
147  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
148 }
149 
150 TEST_F(ConstexprMathTest, constexpr_log2_ceil_63) {
151  constexpr auto v = 63ull;
152  constexpr auto a = folly::constexpr_log2_ceil(v);
153  EXPECT_EQ(6ull, a);
154  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
155 }
156 
157 TEST_F(ConstexprMathTest, constexpr_log2_ceil_64) {
158  constexpr auto v = 64ull;
159  constexpr auto a = folly::constexpr_log2_ceil(v);
160  EXPECT_EQ(6ull, a);
161  EXPECT_TRUE((std::is_same<decltype(v), decltype(a)>::value));
162 }
163 
164 TEST_F(ConstexprMathTest, constexpr_ceil) {
165  {
166  constexpr auto roundable = 20ull;
167  constexpr auto round = 6ull;
168  constexpr auto rounded = folly::constexpr_ceil(roundable, round);
169  EXPECT_EQ(24ull, rounded);
170  }
171  {
172  constexpr auto roundable = -20ll;
173  constexpr auto round = 6ll;
174  constexpr auto rounded = folly::constexpr_ceil(roundable, round);
175  EXPECT_EQ(-18ll, rounded);
176  }
177  {
178  constexpr auto roundable = -20ll;
179  constexpr auto round = 0ll;
180  constexpr auto rounded = folly::constexpr_ceil(roundable, round);
181  EXPECT_EQ(-20ll, rounded);
182  }
183 }
184 
185 TEST_F(ConstexprMathTest, constexpr_pow) {
186  {
187  constexpr auto a = folly::constexpr_pow(uint64_t(0), 15);
188  EXPECT_EQ(0, a);
189  }
190  {
191  constexpr auto a = folly::constexpr_pow(uint64_t(15), 0);
192  EXPECT_EQ(1, a);
193  }
194  {
195  constexpr auto a = folly::constexpr_pow(uint64_t(2), 6);
196  EXPECT_EQ(64, a);
197  }
198 }
199 
200 TEST_F(ConstexprMathTest, constexpr_find_last_set_examples) {
201  {
202  constexpr auto a = folly::constexpr_find_last_set(int64_t(0));
203  EXPECT_EQ(0, a);
204  }
205  {
206  constexpr auto a = folly::constexpr_find_last_set(int64_t(2));
207  EXPECT_EQ(2, a);
208  }
209  {
210  constexpr auto a = folly::constexpr_find_last_set(int64_t(4096 + 64));
211  EXPECT_EQ(13, a);
212  }
213 }
214 
215 TEST_F(ConstexprMathTest, constexpr_find_last_set_all_64_adjacents) {
216  using type = uint64_t;
217  constexpr auto const bits = std::numeric_limits<type>::digits;
219  for (size_t i = 0; i < bits; ++i) {
220  type const v = type(1) << i;
223  }
224 }
225 
226 TEST_F(ConstexprMathTest, constexpr_find_last_set_all_8_reference) {
227  using type = char;
228  for (size_t i = 0; i < 256u; ++i) {
229  auto const expected = folly::findLastSet(type(i));
231  }
232 }
233 
234 TEST_F(ConstexprMathTest, constexpr_find_first_set_examples) {
235  {
236  constexpr auto a = folly::constexpr_find_first_set(int64_t(0));
237  EXPECT_EQ(0, a);
238  }
239  {
240  constexpr auto a = folly::constexpr_find_first_set(int64_t(2));
241  EXPECT_EQ(2, a);
242  }
243  {
244  constexpr auto a = folly::constexpr_find_first_set(int64_t(4096 + 64));
245  EXPECT_EQ(7, a);
246  }
247 }
248 
249 TEST_F(ConstexprMathTest, constexpr_find_first_set_all_64_adjacent) {
250  using type = uint64_t;
251  constexpr auto const bits = std::numeric_limits<type>::digits;
253  for (size_t i = 0; i < bits; ++i) {
254  type const v = (type(1) << (bits - 1)) | (type(1) << i);
256  }
257 }
258 
259 TEST_F(ConstexprMathTest, constexpr_find_first_set_all_8_reference) {
260  using type = char;
261  for (size_t i = 0; i < 256u; ++i) {
262  auto const expected = folly::findFirstSet(type(i));
264  }
265 }
266 
273 
275  for (int a = kInt8Min; a <= kInt8Max; a++) {
276  for (int b = kInt8Min; b <= kInt8Max; b++) {
277  int c = folly::constexpr_clamp(a + b, int(kInt8Min), int(kInt8Max));
278  int8_t a1 = a;
279  int8_t b1 = b;
281  ASSERT_LE(c1, kInt8Max);
282  ASSERT_GE(c1, kInt8Min);
283  ASSERT_EQ(c1, c);
284  }
285  }
286 
287  for (int a = 0; a <= kUInt8Max; a++) {
288  for (int b = 0; b <= kUInt8Max; b++) {
289  int c = folly::constexpr_clamp(a + b, 0, int(kUInt8Max));
290  uint8_t a1 = a;
291  uint8_t b1 = b;
293  ASSERT_LE(c1, kUInt8Max);
294  ASSERT_GE(c1, 0);
295  ASSERT_EQ(c1, c);
296  }
297  }
298 
299  constexpr auto v1 =
301  EXPECT_EQ(kInt64Max, v1);
302 
303  constexpr auto v2 =
305  EXPECT_EQ(int64_t(35), v2);
306 
307  constexpr auto v3 =
309  EXPECT_EQ(int64_t(-11), v3);
310 
311  constexpr auto v4 =
313  EXPECT_EQ(int64_t(-35), v4);
314 
315  constexpr auto v5 =
317  EXPECT_EQ(kUInt64Max, v5);
318 }
319 
321  for (int a = kInt8Min; a <= kInt8Max; a++) {
322  for (int b = kInt8Min; b <= kInt8Max; b++) {
323  int c = folly::constexpr_clamp(a - b, int(kInt8Min), int(kInt8Max));
324  int8_t a1 = a;
325  int8_t b1 = b;
327  ASSERT_LE(c1, kInt8Max);
328  ASSERT_GE(c1, kInt8Min);
329  ASSERT_EQ(c1, c);
330  }
331  }
332 
333  for (int a = 0; a <= kUInt8Max; a++) {
334  for (int b = 0; b <= kUInt8Max; b++) {
335  int c = folly::constexpr_clamp(a - b, 0, int(kUInt8Max));
336  uint8_t a1 = a;
337  uint8_t b1 = b;
339  ASSERT_LE(c1, kUInt8Max);
340  ASSERT_GE(c1, 0);
341  ASSERT_EQ(c1, c);
342  }
343  }
344 
345  constexpr auto v1 =
347  EXPECT_EQ(int64_t(11), v1);
348 
349  constexpr auto v2 =
351  EXPECT_EQ(int64_t(-11), v2);
352 
353  constexpr auto v3 =
355  EXPECT_EQ(int64_t(35), v3);
356 
357  constexpr auto v4 =
359  EXPECT_EQ(kInt64Max, v4);
360 
361  constexpr auto v5 =
363  EXPECT_EQ(kInt64Max - 22, v5);
364 
365  constexpr auto v6 =
367  EXPECT_EQ(uint64_t(11), v6);
368 
369  constexpr auto v7 =
371  EXPECT_EQ(uint64_t(0), v7);
372 }
373 
374 template <class F, class... Args>
375 void for_each_argument(F&& f, Args&&... args) {
376  [](...) {}((f(std::forward<Args>(args)), 0)...);
377 }
378 
379 // float -> integral clamp cast
380 template <typename Src, typename Dst>
383  constexpr auto kQuietNaN = std::numeric_limits<Src>::quiet_NaN();
384  constexpr auto kSignalingNaN = std::numeric_limits<Src>::signaling_NaN();
385  constexpr auto kPositiveInf = std::numeric_limits<Src>::infinity();
386  constexpr auto kNegativeInf = -kPositiveInf;
387 
388  constexpr auto kDstMax = std::numeric_limits<Dst>::max();
389  constexpr auto kDstMin = std::numeric_limits<Dst>::min();
390 
391  // Check f != f trick for identifying NaN.
392  EXPECT_TRUE(kQuietNaN != kQuietNaN);
393  EXPECT_TRUE(kSignalingNaN != kSignalingNaN);
394  EXPECT_FALSE(kPositiveInf != kPositiveInf);
395  EXPECT_FALSE(kNegativeInf != kNegativeInf);
396 
397  // NaN -> 0
398  EXPECT_EQ(0, folly::constexpr_clamp_cast<Dst>(kQuietNaN));
399  EXPECT_EQ(0, folly::constexpr_clamp_cast<Dst>(kSignalingNaN));
400 
401  // Inf -> Max/Min
402  EXPECT_EQ(kDstMax, folly::constexpr_clamp_cast<Dst>(kPositiveInf));
403  EXPECT_EQ(kDstMin, folly::constexpr_clamp_cast<Dst>(kNegativeInf));
404 
405  // barely out of range -> Max/Min
406  EXPECT_EQ(kDstMax, folly::constexpr_clamp_cast<Dst>(Src(kDstMax) * 1.001));
407  EXPECT_EQ(kDstMin, folly::constexpr_clamp_cast<Dst>(Src(kDstMin) * 1.001));
408 
409  // value in range -> same value
410  EXPECT_EQ(Dst(0), folly::constexpr_clamp_cast<Dst>(Src(0)));
411  EXPECT_EQ(Dst(123), folly::constexpr_clamp_cast<Dst>(Src(123)));
412 }
413 
414 // integral -> integral clamp cast
415 template <typename Src, typename Dst>
418  constexpr auto kSrcMax = std::numeric_limits<Src>::max();
419  constexpr auto kSrcMin = std::numeric_limits<Src>::min();
420 
421  constexpr auto kDstMax = std::numeric_limits<Dst>::max();
422  constexpr auto kDstMin = std::numeric_limits<Dst>::min();
423 
424  // value in range -> same value
425  EXPECT_EQ(Dst(0), folly::constexpr_clamp_cast<Dst>(Src(0)));
426  EXPECT_EQ(Dst(123), folly::constexpr_clamp_cast<Dst>(Src(123)));
427 
428  // int -> uint
430  EXPECT_EQ(Dst(0), folly::constexpr_clamp_cast<Dst>(Src(-123)));
431  }
432 
433  if (sizeof(Src) > sizeof(Dst)) {
434  // range clamping
435  EXPECT_EQ(kDstMax, folly::constexpr_clamp_cast<Dst>(kSrcMax));
436 
437  // int -> int
439  EXPECT_EQ(kDstMin, folly::constexpr_clamp_cast<Dst>(kSrcMin));
440  }
441 
442  } else if (
444  sizeof(Src) == sizeof(Dst)) {
445  // uint -> int, same size
446  EXPECT_EQ(kDstMax, folly::constexpr_clamp_cast<Dst>(kSrcMax));
447  }
448 }
449 
450 TEST_F(ConstexprMathTest, constexpr_clamp_cast) {
452  [](auto dst) {
454  [&](auto src) { run_constexpr_clamp_cast_test(src, dst); },
455  // source types
456  float(),
457  double(),
458  (long double)(0),
459  int8_t(),
460  uint8_t(),
461  int16_t(),
462  uint16_t(),
463  int32_t(),
464  uint32_t(),
465  int64_t(),
466  uint64_t());
467  },
468  // dst types
469  int8_t(),
470  uint8_t(),
471  int16_t(),
472  uint16_t(),
473  int32_t(),
474  uint32_t(),
475  int64_t(),
476  uint64_t());
477 }
constexpr std::size_t constexpr_find_first_set(T t)
constexpr auto kUInt64Max
constexpr auto kUInt8Max
#define ASSERT_GE(val1, val2)
Definition: gtest.h:1972
Definition: InvokeTest.cpp:58
constexpr std::size_t constexpr_find_last_set(T const t)
void for_each_argument(F &&f, Args &&...args)
constexpr auto kInt8Min
constexpr T constexpr_add_overflow_clamped(T a, T b)
constexpr auto kInt64Min
auto f
constexpr auto kInt64Max
constexpr std::enable_if< std::is_integral< Src >::value, Dst >::type constexpr_clamp_cast(Src src)
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
char b
LogLevel max
Definition: LogLevel.cpp:31
BitIterator< BaseIter > findFirstSet(BitIterator< BaseIter >, BitIterator< BaseIter >)
Definition: BitIterator.h:170
TEST_F(TestInfoTest, Names)
constexpr To round(std::chrono::duration< Rep, Period > const &d)
Definition: Chrono.h:139
PskType type
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr T constexpr_min(T a)
Definition: ConstexprMath.h:79
static std::enable_if< std::is_floating_point< Src >::value, void >::type run_constexpr_clamp_cast_test(Src, Dst)
constexpr auto kInt8Max
#define ASSERT_LE(val1, val2)
Definition: gtest.h:1964
constexpr T constexpr_log2(T t)
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
constexpr T constexpr_max(T a)
Definition: ConstexprMath.h:68
constexpr auto constexpr_abs(T t) -> decltype(detail::constexpr_abs_helper< T >::go(t))
constexpr T constexpr_pow(T base, std::size_t exp)
LogLevel min
Definition: LogLevel.cpp:30
constexpr T constexpr_sub_overflow_clamped(T a, T b)
Definition: InvokeTest.cpp:72
constexpr unsigned int findLastSet(T const v)
Definition: Bits.h:105
char a
static const char *const value
Definition: Conv.cpp:50
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
constexpr T constexpr_log2_ceil(T t)
constexpr T const & constexpr_clamp(T const &v, T const &lo, T const &hi, Less less)
Definition: ConstexprMath.h:89
constexpr T constexpr_ceil(T t, T round)
Definition: InvokeTest.cpp:65
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
char c