1 #ifndef BENCHMARK_REGISTER_H
2 #define BENCHMARK_REGISTER_H
3 
4 #include <limits>
5 #include <vector>
6 
7 #include "check.h"
8 
9 namespace benchmark {
10 namespace internal {
11 
12 // Append the powers of 'mult' in the closed interval [lo, hi].
13 // Returns iterator to the start of the inserted range.
14 template <typename T>
15 typename std::vector<T>::iterator
AddPowers(std::vector<T> * dst,T lo,T hi,int mult)16 AddPowers(std::vector<T>* dst, T lo, T hi, int mult) {
17   CHECK_GE(lo, 0);
18   CHECK_GE(hi, lo);
19   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 = 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 
38 template <typename T>
AddNegatedPowers(std::vector<T> * dst,T lo,T hi,int mult)39 void 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   CHECK_GT(lo, std::numeric_limits<T>::min());
42   CHECK_GT(hi, std::numeric_limits<T>::min());
43   CHECK_GE(hi, lo);
44   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 
58 template <typename T>
AddRange(std::vector<T> * dst,T lo,T hi,int mult)59 void 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   CHECK_GE(hi, lo);
64   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