1#ifndef BENCHMARK_REGISTER_H
2#define BENCHMARK_REGISTER_H
3
4#include <limits>
5#include <vector>
6
7#include "check.h"
8
9namespace benchmark {
10namespace internal {
11
12// Append the powers of 'mult' in the closed interval [lo, hi].
13// Returns iterator to the start of the inserted range.
14template <typename T>
15typename std::vector<T>::iterator AddPowers(std::vector<T>* dst, T lo, T hi,
16 int mult) {
17 BM_CHECK_GE(lo, 0);
18 BM_CHECK_GE(hi, lo);
19 BM_CHECK_GE(mult, 2);
20
21 const size_t start_offset = dst->size();
22
23 static const T kmax = std::numeric_limits<T>::max();
24
25 // Space out the values in multiples of "mult"
26 for (T i = static_cast<T>(1); i <= hi; i *= mult) {
27 if (i >= lo) {
28 dst->push_back(i);
29 }
30 // Break the loop here since multiplying by
31 // 'mult' would move outside of the range of T
32 if (i > kmax / mult) break;
33 }
34
35 return dst->begin() + start_offset;
36}
37
38template <typename T>
39void AddNegatedPowers(std::vector<T>* dst, T lo, T hi, int mult) {
40 // We negate lo and hi so we require that they cannot be equal to 'min'.
41 BM_CHECK_GT(lo, std::numeric_limits<T>::min());
42 BM_CHECK_GT(hi, std::numeric_limits<T>::min());
43 BM_CHECK_GE(hi, lo);
44 BM_CHECK_LE(hi, 0);
45
46 // Add positive powers, then negate and reverse.
47 // Casts necessary since small integers get promoted
48 // to 'int' when negating.
49 const auto lo_complement = static_cast<T>(-lo);
50 const auto hi_complement = static_cast<T>(-hi);
51
52 const auto it = AddPowers(dst, hi_complement, lo_complement, mult);
53
54 std::for_each(it, dst->end(), [](T& t) { t *= -1; });
55 std::reverse(it, dst->end());
56}
57
58template <typename T>
59void AddRange(std::vector<T>* dst, T lo, T hi, int mult) {
60 static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
61 "Args type must be a signed integer");
62
63 BM_CHECK_GE(hi, lo);
64 BM_CHECK_GE(mult, 2);
65
66 // Add "lo"
67 dst->push_back(lo);
68
69 // Handle lo == hi as a special case, so we then know
70 // lo < hi and so it is safe to add 1 to lo and subtract 1
71 // from hi without falling outside of the range of T.
72 if (lo == hi) return;
73
74 // Ensure that lo_inner <= hi_inner below.
75 if (lo + 1 == hi) {
76 dst->push_back(hi);
77 return;
78 }
79
80 // Add all powers of 'mult' in the range [lo+1, hi-1] (inclusive).
81 const auto lo_inner = static_cast<T>(lo + 1);
82 const auto hi_inner = static_cast<T>(hi - 1);
83
84 // Insert negative values
85 if (lo_inner < 0) {
86 AddNegatedPowers(dst, lo_inner, std::min(hi_inner, T{-1}), mult);
87 }
88
89 // Treat 0 as a special case (see discussion on #762).
90 if (lo < 0 && hi >= 0) {
91 dst->push_back(0);
92 }
93
94 // Insert positive values
95 if (hi_inner > 0) {
96 AddPowers(dst, std::max(lo_inner, T{1}), hi_inner, mult);
97 }
98
99 // Add "hi" (if different from last value).
100 if (hi != dst->back()) {
101 dst->push_back(hi);
102 }
103}
104
105} // namespace internal
106} // namespace benchmark
107
108#endif // BENCHMARK_REGISTER_H
109