1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //===----------------------------------------------------------------------===//
15 #include "CartesianBenchmarks.h"
16 #include "benchmark/benchmark.h"
18 // *** Localization ***
19 enum class LocalizationE
{ False
, True
};
20 struct AllLocalizations
: EnumValuesAsTuple
<AllLocalizations
, LocalizationE
, 2> {
21 static constexpr const char* Names
[] = {"LocFalse", "LocTrue"};
24 template <LocalizationE E
>
25 struct Localization
{};
28 struct Localization
<LocalizationE::False
> {
29 static constexpr const char* fmt
= "";
33 struct Localization
<LocalizationE::True
> {
34 static constexpr const char* fmt
= "L";
38 enum class TypeE
{ Float
, Double
, LongDouble
};
39 // TODO FMT Set to 3 after to_chars has long double suport.
40 struct AllTypes
: EnumValuesAsTuple
<AllTypes
, TypeE
, 2> {
41 static constexpr const char* Names
[] = {"Float", "Double", "LongDouble"};
48 struct Type
<TypeE::Float
> {
53 struct Type
<TypeE::Double
> {
58 struct Type
<TypeE::LongDouble
> {
59 using type
= long double;
63 enum class ValueE
{ Inf
, Random
};
64 struct AllValues
: EnumValuesAsTuple
<AllValues
, ValueE
, 2> {
65 static constexpr const char* Names
[] = {"Inf", "Random"};
72 struct Value
<ValueE::Inf
> {
74 static std::array
<F
, 1000> make_data() {
75 std::array
<F
, 1000> result
;
76 std::fill(result
.begin(), result
.end(), -std::numeric_limits
<F
>::infinity());
82 struct Value
<ValueE::Random
> {
84 static std::array
<F
, 1000> make_data() {
85 std::random_device seed
;
86 std::mt19937
generator(seed());
87 std::uniform_int_distribution
<std::conditional_t
<sizeof(F
) == sizeof(uint32_t), uint32_t, uint64_t>> distribution
;
89 std::array
<F
, 1000> result
;
90 std::generate(result
.begin(), result
.end(), [&] {
92 auto result
= std::bit_cast
<F
>(distribution(generator
));
93 if (std::isfinite(result
))
101 // *** Display Type ***
102 enum class DisplayTypeE
{
109 struct AllDisplayTypes
: EnumValuesAsTuple
<AllDisplayTypes
, DisplayTypeE
, 5> {
110 static constexpr const char* Names
[] = {
111 "DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed", "DisplayGeneral"};
114 template <DisplayTypeE E
>
115 struct DisplayType
{};
118 struct DisplayType
<DisplayTypeE::Default
> {
119 static constexpr const char* fmt
= "";
123 struct DisplayType
<DisplayTypeE::Hex
> {
124 static constexpr const char* fmt
= "a";
128 struct DisplayType
<DisplayTypeE::Scientific
> {
129 static constexpr const char* fmt
= "e";
133 struct DisplayType
<DisplayTypeE::Fixed
> {
134 static constexpr const char* fmt
= "f";
138 struct DisplayType
<DisplayTypeE::General
> {
139 static constexpr const char* fmt
= "g";
143 enum class AlignmentE
{ None
, Left
, Center
, Right
, ZeroPadding
};
144 struct AllAlignments
: EnumValuesAsTuple
<AllAlignments
, AlignmentE
, 5> {
145 static constexpr const char* Names
[] = {
146 "AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};
149 template <AlignmentE E
>
153 struct Alignment
<AlignmentE::None
> {
154 static constexpr const char* fmt
= "";
158 struct Alignment
<AlignmentE::Left
> {
159 // Width > PrecisionE::Huge
160 static constexpr const char* fmt
= "0<17500";
164 struct Alignment
<AlignmentE::Center
> {
165 // Width > PrecisionE::Huge
166 static constexpr const char* fmt
= "0^17500";
170 struct Alignment
<AlignmentE::Right
> {
171 // Width > PrecisionE::Huge
172 static constexpr const char* fmt
= "0>17500";
176 struct Alignment
<AlignmentE::ZeroPadding
> {
177 // Width > PrecisionE::Huge
178 static constexpr const char* fmt
= "017500";
181 enum class PrecisionE
{ None
, Zero
, Small
, Huge
};
182 struct AllPrecisions
: EnumValuesAsTuple
<AllPrecisions
, PrecisionE
, 4> {
183 static constexpr const char* Names
[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"};
186 template <PrecisionE E
>
190 struct Precision
<PrecisionE::None
> {
191 static constexpr const char* fmt
= "";
195 struct Precision
<PrecisionE::Zero
> {
196 static constexpr const char* fmt
= ".0";
200 struct Precision
<PrecisionE::Small
> {
201 static constexpr const char* fmt
= ".10";
205 struct Precision
<PrecisionE::Huge
> {
206 // The maximum precision for a minimal sub normal long double is +/- 0x1p-16494.
207 // This value is always larger than that value forcing the trailing zero path
209 static constexpr const char* fmt
= ".17000";
212 template <class L
, class DT
, class T
, class V
, class A
, class P
>
213 struct FloatingPoint
{
214 using F
= typename Type
<T::value
>::type
;
216 void run(benchmark::State
& state
) const {
217 std::array
<F
, 1000> data
{Value
<V::value
>::template make_data
<F
>()};
218 std::array
<char, 20'000> output
;
220 while (state
.KeepRunningBatch(1000))
222 benchmark::DoNotOptimize(std::format_to(output
.begin(), std::string_view
{fmt
.data(), fmt
.size()}, value
));
225 std::string
name() const {
226 return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();
229 static constexpr std::string
make_fmt() {
230 return std::string("{:") + Alignment
<A::value
>::fmt
+ Precision
<P::value
>::fmt
+ Localization
<L::value
>::fmt
+
231 DisplayType
<DT::value
>::fmt
+ "}";
234 static constexpr auto fmt
= []() {
235 constexpr size_t s
= make_fmt().size();
236 std::array
<char, s
> r
;
237 std::ranges::copy(make_fmt(), r
.begin());
242 int main(int argc
, char** argv
) {
243 benchmark::Initialize(&argc
, argv
);
244 if (benchmark::ReportUnrecognizedArguments(argc
, argv
))
247 makeCartesianProductBenchmark
<FloatingPoint
,
255 benchmark::RunSpecifiedBenchmarks();