1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17
10
11#include <array>
12#include <format>
13#include <random>
14
15#include "../CartesianBenchmarks.h"
16#include "benchmark/benchmark.h"
17#include "test_macros.h"
18
19// Tests the full range of the value.
20template <class T>
21static std::array<T, 1000> generate(std::uniform_int_distribution<T> distribution = std::uniform_int_distribution<T>{
22 std::numeric_limits<T>::min(), std::numeric_limits<T>::max()}) {
23 std::mt19937 generator;
24 std::array<T, 1000> result;
25 std::generate_n(result.begin(), result.size(), [&] { return distribution(generator); });
26 return result;
27}
28
29template <class T>
30static void BM_Basic(benchmark::State& state) {
31 std::array data{generate<T>()};
32 std::array<char, 100> output;
33
34 while (state.KeepRunningBatch(n: data.size()))
35 for (auto value : data)
36 benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
37}
38BENCHMARK(BM_Basic<uint32_t>);
39BENCHMARK(BM_Basic<int32_t>);
40BENCHMARK(BM_Basic<uint64_t>);
41BENCHMARK(BM_Basic<int64_t>);
42
43// Ideally the low values of a 128-bit value are all dispatched to a 64-bit routine.
44#ifndef TEST_HAS_NO_INT128
45template <class T>
46static void BM_BasicLow(benchmark::State& state) {
47 using U = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
48 std::array data{
49 generate<T>(std::uniform_int_distribution<T>{std::numeric_limits<U>::min(), std::numeric_limits<U>::max()})};
50 std::array<char, 100> output;
51
52 while (state.KeepRunningBatch(n: data.size()))
53 for (auto value : data)
54 benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
55}
56BENCHMARK(BM_BasicLow<__uint128_t>);
57BENCHMARK(BM_BasicLow<__int128_t>);
58
59BENCHMARK(BM_Basic<__uint128_t>);
60BENCHMARK(BM_Basic<__int128_t>);
61#endif
62
63// *** Localization ***
64enum class LocalizationE { False, True };
65struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
66 static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
67};
68
69template <LocalizationE E>
70struct Localization {};
71
72template <>
73struct Localization<LocalizationE::False> {
74 static constexpr const char* fmt = "";
75};
76
77template <>
78struct Localization<LocalizationE::True> {
79 static constexpr const char* fmt = "L";
80};
81
82// *** Base ***
83enum class BaseE {
84 Binary,
85 Octal,
86 Decimal,
87 Hex,
88 HexUpper,
89};
90struct AllBases : EnumValuesAsTuple<AllBases, BaseE, 5> {
91 static constexpr const char* Names[] = {"BaseBin", "BaseOct", "BaseDec", "BaseHex", "BaseHexUpper"};
92};
93
94template <BaseE E>
95struct Base {};
96
97template <>
98struct Base<BaseE::Binary> {
99 static constexpr const char* fmt = "b";
100};
101
102template <>
103struct Base<BaseE::Octal> {
104 static constexpr const char* fmt = "o";
105};
106
107template <>
108struct Base<BaseE::Decimal> {
109 static constexpr const char* fmt = "d";
110};
111
112template <>
113struct Base<BaseE::Hex> {
114 static constexpr const char* fmt = "x";
115};
116
117template <>
118struct Base<BaseE::HexUpper> {
119 static constexpr const char* fmt = "X";
120};
121
122// *** Types ***
123enum class TypeE { Int64, Uint64 };
124struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
125 static constexpr const char* Names[] = {"Int64", "Uint64"};
126};
127
128template <TypeE E>
129struct Type {};
130
131template <>
132struct Type<TypeE::Int64> {
133 using type = int64_t;
134
135 static std::array<type, 1000> make_data() { return generate<type>(); }
136};
137
138template <>
139struct Type<TypeE::Uint64> {
140 using type = uint64_t;
141
142 static std::array<type, 1000> make_data() { return generate<type>(); }
143};
144
145// *** Alignment ***
146enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
147struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
148 static constexpr const char* Names[] = {
149 "AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};
150};
151
152template <AlignmentE E>
153struct Alignment {};
154
155template <>
156struct Alignment<AlignmentE::None> {
157 static constexpr const char* fmt = "";
158};
159
160template <>
161struct Alignment<AlignmentE::Left> {
162 static constexpr const char* fmt = "0<512";
163};
164
165template <>
166struct Alignment<AlignmentE::Center> {
167 static constexpr const char* fmt = "0^512";
168};
169
170template <>
171struct Alignment<AlignmentE::Right> {
172 static constexpr const char* fmt = "0>512";
173};
174
175template <>
176struct Alignment<AlignmentE::ZeroPadding> {
177 static constexpr const char* fmt = "0512";
178};
179
180template <class L, class B, class T, class A>
181struct Integral {
182 void run(benchmark::State& state) const {
183 std::array data{Type<T::value>::make_data()};
184 std::array<char, 512> output;
185
186 while (state.KeepRunningBatch(n: data.size()))
187 for (auto value : data)
188 benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
189 }
190
191 std::string name() const { return "Integral" + L::name() + B::name() + A::name() + T::name(); }
192
193 static constexpr std::string make_fmt() {
194 return std::string("{:") + Alignment<A::value>::fmt + Localization<L::value>::fmt + Base<B::value>::fmt + "}";
195 }
196
197 static constexpr auto fmt = []() {
198 constexpr size_t s = make_fmt().size();
199 std::array<char, s> r;
200 std::ranges::copy(make_fmt(), r.begin());
201 return r;
202 }();
203};
204
205int main(int argc, char** argv) {
206 benchmark::Initialize(argc: &argc, argv);
207 if (benchmark::ReportUnrecognizedArguments(argc, argv))
208 return 1;
209
210 makeCartesianProductBenchmark<Integral, AllLocalizations, AllBases, AllTypes, AllAlignments>();
211
212 benchmark::RunSpecifiedBenchmarks();
213}
214

source code of libcxx/test/benchmarks/format/formatter_int.bench.cpp