| #ifndef BENCHMARK_REGISTER_H | |
| #define BENCHMARK_REGISTER_H | |
| #include <algorithm> | |
| #include <limits> | |
| #include <type_traits> | |
| #include <vector> | |
| #include "check.h" | |
| namespace benchmark { | |
| namespace internal { | |
| // Append the powers of 'mult' in the closed interval [lo, hi]. | |
| // Returns iterator to the start of the inserted range. | |
| template <typename T> | |
| typename std::vector<T>::iterator AddPowers(std::vector<T>* dst, T lo, T hi, | |
| int mult) { | |
| BM_CHECK_GE(lo, 0); | |
| BM_CHECK_GE(hi, lo); | |
| BM_CHECK_GE(mult, 2); | |
| const size_t start_offset = dst->size(); | |
| static const T kmax = std::numeric_limits<T>::max(); | |
| // Space out the values in multiples of "mult" | |
| for (T i = static_cast<T>(1); i <= hi; i = static_cast<T>(i * mult)) { | |
| if (i >= lo) { | |
| dst->push_back(i); | |
| } | |
| // Break the loop here since multiplying by | |
| // 'mult' would move outside of the range of T | |
| if (i > kmax / mult) break; | |
| } | |
| return dst->begin() + static_cast<int>(start_offset); | |
| } | |
| template <typename T> | |
| void AddNegatedPowers(std::vector<T>* dst, T lo, T hi, int mult) { | |
| // We negate lo and hi so we require that they cannot be equal to 'min'. | |
| BM_CHECK_GT(lo, std::numeric_limits<T>::min()); | |
| BM_CHECK_GT(hi, std::numeric_limits<T>::min()); | |
| BM_CHECK_GE(hi, lo); | |
| BM_CHECK_LE(hi, 0); | |
| // Add positive powers, then negate and reverse. | |
| // Casts necessary since small integers get promoted | |
| // to 'int' when negating. | |
| const auto lo_complement = static_cast<T>(-lo); | |
| const auto hi_complement = static_cast<T>(-hi); | |
| const auto it = AddPowers(dst, hi_complement, lo_complement, mult); | |
| std::for_each(it, dst->end(), [](T& t) { t = static_cast<T>(t * -1); }); | |
| std::reverse(it, dst->end()); | |
| } | |
| template <typename T> | |
| void AddRange(std::vector<T>* dst, T lo, T hi, int mult) { | |
| static_assert(std::is_integral<T>::value && std::is_signed<T>::value, | |
| "Args type must be a signed integer"); | |
| BM_CHECK_GE(hi, lo); | |
| BM_CHECK_GE(mult, 2); | |
| // Add "lo" | |
| dst->push_back(lo); | |
| // Handle lo == hi as a special case, so we then know | |
| // lo < hi and so it is safe to add 1 to lo and subtract 1 | |
| // from hi without falling outside of the range of T. | |
| if (lo == hi) return; | |
| // Ensure that lo_inner <= hi_inner below. | |
| if (lo + 1 == hi) { | |
| dst->push_back(hi); | |
| return; | |
| } | |
| // Add all powers of 'mult' in the range [lo+1, hi-1] (inclusive). | |
| const auto lo_inner = static_cast<T>(lo + 1); | |
| const auto hi_inner = static_cast<T>(hi - 1); | |
| // Insert negative values | |
| if (lo_inner < 0) { | |
| AddNegatedPowers(dst, lo_inner, std::min(hi_inner, T{-1}), mult); | |
| } | |
| // Treat 0 as a special case (see discussion on #762). | |
| if (lo < 0 && hi >= 0) { | |
| dst->push_back(0); | |
| } | |
| // Insert positive values | |
| if (hi_inner > 0) { | |
| AddPowers(dst, std::max(lo_inner, T{1}), hi_inner, mult); | |
| } | |
| // Add "hi" (if different from last value). | |
| if (hi != dst->back()) { | |
| dst->push_back(hi); | |
| } | |
| } | |
| } // namespace internal | |
| } // namespace benchmark | |
| #endif // BENCHMARK_REGISTER_H |