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