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