// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <array>
#include <benchmark/benchmark.h>
#include <bit>
#include <bitset>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <random>

using namespace std;

namespace {
    template <size_t Elems>
    auto random_bits_init() {
        mt19937_64 rnd{};
        array<uint64_t, Elems> arr;
        for (auto& d : arr) {
            d = rnd();
        }
        return arr;
    }

    template <size_t Elems = 32>
    const auto random_bits = random_bits_init<Elems>();

    template <size_t N, class charT>
    void BM_bitset_to_string(benchmark::State& state) {
        static_assert(N <= 64);

        for (auto _ : state) {
            for (const auto& bits : random_bits<>) {
                benchmark::DoNotOptimize(bits);
                bitset<N> bs{bits};
                benchmark::DoNotOptimize(bs.to_string<charT>());
            }
        }
    }

    template <size_t N, class charT>
    void BM_bitset_to_string_large_single(benchmark::State& state) {
        static_assert(N % 64 == 0 && N >= 64);
        const auto& bitset_data = random_bits<N / 64>;

        const auto large_bitset = bit_cast<bitset<N>>(bitset_data);
        for (auto _ : state) {
            benchmark::DoNotOptimize(large_bitset);
            benchmark::DoNotOptimize(large_bitset.to_string<charT>());
        }
    }
} // namespace

BENCHMARK(BM_bitset_to_string<15, char>);
BENCHMARK(BM_bitset_to_string<64, char>);
BENCHMARK(BM_bitset_to_string_large_single<512, char>);
BENCHMARK(BM_bitset_to_string_large_single<2048, char>);
BENCHMARK(BM_bitset_to_string<7, wchar_t>);
BENCHMARK(BM_bitset_to_string<64, wchar_t>);
BENCHMARK(BM_bitset_to_string_large_single<512, wchar_t>);
BENCHMARK(BM_bitset_to_string_large_single<2048, wchar_t>);

BENCHMARK_MAIN();
