// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstdint>
#include <random>
#include <string>
#include <type_traits>
#include <vector>

#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/numbers.h"

namespace {

template <typename T>
void BM_FastIntToBuffer(benchmark::State& state) {
  const int inc = state.range(0);
  char buf[absl::numbers_internal::kFastToBufferSize];
  // Use the unsigned type to increment to take advantage of well-defined
  // modular arithmetic.
  typename std::make_unsigned<T>::type x = 0;
  for (auto _ : state) {
    absl::numbers_internal::FastIntToBuffer(static_cast<T>(x), buf);
    x += inc;
  }
}
BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int32_t)->Range(0, 1 << 15);
BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int64_t)->Range(0, 1 << 30);

// Creates an integer that would be printed as `num_digits` repeated 7s in the
// given `base`. `base` must be greater than or equal to 8.
int64_t RepeatedSevens(int num_digits, int base) {
  ABSL_RAW_CHECK(base >= 8, "");
  int64_t num = 7;
  while (--num_digits) num = base * num + 7;
  return num;
}

void BM_safe_strto32_string(benchmark::State& state) {
  const int digits = state.range(0);
  const int base = state.range(1);
  std::string str(digits, '7');  // valid in octal, decimal and hex
  int32_t value = 0;
  for (auto _ : state) {
    benchmark::DoNotOptimize(
        absl::numbers_internal::safe_strto32_base(str, &value, base));
  }
  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
}
BENCHMARK(BM_safe_strto32_string)
    ->ArgPair(1, 8)
    ->ArgPair(1, 10)
    ->ArgPair(1, 16)
    ->ArgPair(2, 8)
    ->ArgPair(2, 10)
    ->ArgPair(2, 16)
    ->ArgPair(4, 8)
    ->ArgPair(4, 10)
    ->ArgPair(4, 16)
    ->ArgPair(8, 8)
    ->ArgPair(8, 10)
    ->ArgPair(8, 16)
    ->ArgPair(10, 8)
    ->ArgPair(9, 10);

void BM_safe_strto64_string(benchmark::State& state) {
  const int digits = state.range(0);
  const int base = state.range(1);
  std::string str(digits, '7');  // valid in octal, decimal and hex
  int64_t value = 0;
  for (auto _ : state) {
    benchmark::DoNotOptimize(
        absl::numbers_internal::safe_strto64_base(str, &value, base));
  }
  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
}
BENCHMARK(BM_safe_strto64_string)
    ->ArgPair(1, 8)
    ->ArgPair(1, 10)
    ->ArgPair(1, 16)
    ->ArgPair(2, 8)
    ->ArgPair(2, 10)
    ->ArgPair(2, 16)
    ->ArgPair(4, 8)
    ->ArgPair(4, 10)
    ->ArgPair(4, 16)
    ->ArgPair(8, 8)
    ->ArgPair(8, 10)
    ->ArgPair(8, 16)
    ->ArgPair(16, 8)
    ->ArgPair(16, 10)
    ->ArgPair(16, 16);

void BM_safe_strtou32_string(benchmark::State& state) {
  const int digits = state.range(0);
  const int base = state.range(1);
  std::string str(digits, '7');  // valid in octal, decimal and hex
  uint32_t value = 0;
  for (auto _ : state) {
    benchmark::DoNotOptimize(
        absl::numbers_internal::safe_strtou32_base(str, &value, base));
  }
  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
}
BENCHMARK(BM_safe_strtou32_string)
    ->ArgPair(1, 8)
    ->ArgPair(1, 10)
    ->ArgPair(1, 16)
    ->ArgPair(2, 8)
    ->ArgPair(2, 10)
    ->ArgPair(2, 16)
    ->ArgPair(4, 8)
    ->ArgPair(4, 10)
    ->ArgPair(4, 16)
    ->ArgPair(8, 8)
    ->ArgPair(8, 10)
    ->ArgPair(8, 16)
    ->ArgPair(10, 8)
    ->ArgPair(9, 10);

void BM_safe_strtou64_string(benchmark::State& state) {
  const int digits = state.range(0);
  const int base = state.range(1);
  std::string str(digits, '7');  // valid in octal, decimal and hex
  uint64_t value = 0;
  for (auto _ : state) {
    benchmark::DoNotOptimize(
        absl::numbers_internal::safe_strtou64_base(str, &value, base));
  }
  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
}
BENCHMARK(BM_safe_strtou64_string)
    ->ArgPair(1, 8)
    ->ArgPair(1, 10)
    ->ArgPair(1, 16)
    ->ArgPair(2, 8)
    ->ArgPair(2, 10)
    ->ArgPair(2, 16)
    ->ArgPair(4, 8)
    ->ArgPair(4, 10)
    ->ArgPair(4, 16)
    ->ArgPair(8, 8)
    ->ArgPair(8, 10)
    ->ArgPair(8, 16)
    ->ArgPair(16, 8)
    ->ArgPair(16, 10)
    ->ArgPair(16, 16);

// Returns a vector of `num_strings` strings. Each std::string represents a
// floating point number with `num_digits` digits before the decimal point and
// another `num_digits` digits after.
std::vector<std::string> MakeFloatStrings(int num_strings, int num_digits) {
  // For convenience, use a random number generator to generate the test data.
  // We don't actually need random properties, so use a fixed seed.
  std::minstd_rand0 rng(1);
  std::uniform_int_distribution<int> random_digit('0', '9');

  std::vector<std::string> float_strings(num_strings);
  for (std::string& s : float_strings) {
    s.reserve(2 * num_digits + 1);
    for (int i = 0; i < num_digits; ++i) {
      s.push_back(static_cast<char>(random_digit(rng)));
    }
    s.push_back('.');
    for (int i = 0; i < num_digits; ++i) {
      s.push_back(static_cast<char>(random_digit(rng)));
    }
  }
  return float_strings;
}

template <typename StringType>
StringType GetStringAs(const std::string& s) {
  return static_cast<StringType>(s);
}
template <>
const char* GetStringAs<const char*>(const std::string& s) {
  return s.c_str();
}

template <typename StringType>
std::vector<StringType> GetStringsAs(const std::vector<std::string>& strings) {
  std::vector<StringType> result;
  result.reserve(strings.size());
  for (const std::string& s : strings) {
    result.push_back(GetStringAs<StringType>(s));
  }
  return result;
}

template <typename T>
void BM_SimpleAtof(benchmark::State& state) {
  const int num_strings = state.range(0);
  const int num_digits = state.range(1);
  std::vector<std::string> backing_strings =
      MakeFloatStrings(num_strings, num_digits);
  std::vector<T> inputs = GetStringsAs<T>(backing_strings);
  float value;
  for (auto _ : state) {
    for (const T& input : inputs) {
      benchmark::DoNotOptimize(absl::SimpleAtof(input, &value));
    }
  }
}
BENCHMARK_TEMPLATE(BM_SimpleAtof, absl::string_view)
    ->ArgPair(10, 1)
    ->ArgPair(10, 2)
    ->ArgPair(10, 4)
    ->ArgPair(10, 8);
BENCHMARK_TEMPLATE(BM_SimpleAtof, const char*)
    ->ArgPair(10, 1)
    ->ArgPair(10, 2)
    ->ArgPair(10, 4)
    ->ArgPair(10, 8);
BENCHMARK_TEMPLATE(BM_SimpleAtof, std::string)
    ->ArgPair(10, 1)
    ->ArgPair(10, 2)
    ->ArgPair(10, 4)
    ->ArgPair(10, 8);

template <typename T>
void BM_SimpleAtod(benchmark::State& state) {
  const int num_strings = state.range(0);
  const int num_digits = state.range(1);
  std::vector<std::string> backing_strings =
      MakeFloatStrings(num_strings, num_digits);
  std::vector<T> inputs = GetStringsAs<T>(backing_strings);
  double value;
  for (auto _ : state) {
    for (const T& input : inputs) {
      benchmark::DoNotOptimize(absl::SimpleAtod(input, &value));
    }
  }
}
BENCHMARK_TEMPLATE(BM_SimpleAtod, absl::string_view)
    ->ArgPair(10, 1)
    ->ArgPair(10, 2)
    ->ArgPair(10, 4)
    ->ArgPair(10, 8);
BENCHMARK_TEMPLATE(BM_SimpleAtod, const char*)
    ->ArgPair(10, 1)
    ->ArgPair(10, 2)
    ->ArgPair(10, 4)
    ->ArgPair(10, 8);
BENCHMARK_TEMPLATE(BM_SimpleAtod, std::string)
    ->ArgPair(10, 1)
    ->ArgPair(10, 2)
    ->ArgPair(10, 4)
    ->ArgPair(10, 8);

}  // namespace
