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 10namespace benchmark { 11namespace internal { 12 13// Append the powers of 'mult' in the closed interval [lo, hi]. 14// Returns iterator to the start of the inserted range. 15template <typename T> 16typename 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 39template <typename T> 40void 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 59template <typename T> 60void 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