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