Skip to content

Commit

Permalink
Implement P3107R5 optimized <print> (#4821)
Browse files Browse the repository at this point in the history
Co-authored-by: Casey Carter <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
3 people authored Sep 4, 2024
1 parent 77b31f7 commit a36ece0
Show file tree
Hide file tree
Showing 17 changed files with 674 additions and 123 deletions.
1 change: 1 addition & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ function(add_benchmark name)
endfunction()

add_benchmark(bitset_to_string src/bitset_to_string.cpp)
add_benchmark(efficient_nonlocking_print src/efficient_nonlocking_print.cpp)
add_benchmark(find_and_count src/find_and_count.cpp)
add_benchmark(find_first_of src/find_first_of.cpp)
add_benchmark(iota src/iota.cpp)
Expand Down
44 changes: 44 additions & 0 deletions benchmarks/src/efficient_nonlocking_print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// This benchmark inherently prints many lines to stdout. To view its results, run it with these options:
// --benchmark_out=efficient_nonlocking_print.log --benchmark_out_format=console

#include <benchmark/benchmark.h>
#include <cstdio>
#include <format>
#include <print>
#include <string>
#include <string_view>
#include <utility>

namespace {
using PrintType = void (*)(FILE*, std::string_view, std::format_args);

template <PrintType PrintFunction>
void BM_vprint(benchmark::State& state) {
for (auto _ : state) {
PrintFunction(stdout, "Hello cool I am going to print as unicode\n", std::make_format_args());
}
}
BENCHMARK(BM_vprint<&std::vprint_unicode>);
BENCHMARK(BM_vprint<&std::vprint_unicode_buffered>);

template <PrintType PrintFunction>
void BM_vprint_complex(benchmark::State& state) {
const int i = 42;
const std::string str = "Hello world!!!!!!!!!!!!!!!!!!!!!!!!";
const double f = -902.16283758;
const std::pair<int, double> p{16, 2.073f};
for (auto _ : state) {
PrintFunction(stdout,
"Hello cool I am going to print as unicode!! {:X}, {}, {:a}, "
"I am a big string, lots of words, multiple {} formats\n",
std::make_format_args(i, str, f, p));
}
}
BENCHMARK(BM_vprint_complex<&std::vprint_unicode>);
BENCHMARK(BM_vprint_complex<&std::vprint_unicode_buffered>);
} // namespace

BENCHMARK_MAIN();
39 changes: 39 additions & 0 deletions stl/inc/__msvc_formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ enum class _Basic_format_arg_type : uint8_t {
static_assert(static_cast<int>(_Basic_format_arg_type::_Custom_type) < 16, "must fit in 4-bit bitfield");

#if _HAS_CXX23
_EXPORT_STD template <class _Ty>
constexpr bool enable_nonlocking_formatter_optimization = false;

_NODISCARD consteval bool _Is_debug_enabled_fmt_type(_Basic_format_arg_type _Ty) {
return _Ty == _Basic_format_arg_type::_Char_type || _Ty == _Basic_format_arg_type::_CString_type
|| _Ty == _Basic_format_arg_type::_String_type;
Expand Down Expand Up @@ -170,7 +173,16 @@ struct _Formatter_base {
};
_FMT_P2286_END

#if _HAS_CXX23
#define _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) \
template <> \
inline constexpr bool enable_nonlocking_formatter_optimization<_Type> = true;
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
#define _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type)
#endif // ^^^ !_HAS_CXX23 ^^^

#define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \
_FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) \
template <_Format_supported_charT _CharT> \
struct formatter<_Type, _CharT> : _Formatter_base<_Type, _CharT, _ArgType> {}

Expand All @@ -193,6 +205,7 @@ _FORMAT_SPECIALIZE_FOR(signed char, _Basic_format_arg_type::_Int_type);
_FORMAT_SPECIALIZE_FOR(unsigned char, _Basic_format_arg_type::_UInt_type);

#undef _FORMAT_SPECIALIZE_FOR
#undef _FORMAT_SPECIALIZE_NONLOCKING_FOR

// not using the macro because we'd like to add 'set_debug_format' member function in C++23 mode
template <_Format_supported_charT _CharT>
Expand Down Expand Up @@ -361,6 +374,32 @@ struct formatter<pair<_Ty1, _Ty2>, _CharT>;

template <_Format_supported_charT _CharT, class... _Types>
struct formatter<tuple<_Types...>, _CharT>;

template <_Format_supported_charT _CharT>
constexpr bool enable_nonlocking_formatter_optimization<_CharT> = true;

template <_Format_supported_charT _CharT>
constexpr bool enable_nonlocking_formatter_optimization<_CharT*> = true;

template <_Format_supported_charT _CharT>
constexpr bool enable_nonlocking_formatter_optimization<const _CharT*> = true;

template <_Format_supported_charT _CharT, size_t _Nx>
constexpr bool enable_nonlocking_formatter_optimization<_CharT[_Nx]> = true;

template <_Format_supported_charT _CharT, class _Traits, class _Allocator>
constexpr bool enable_nonlocking_formatter_optimization<basic_string<_CharT, _Traits, _Allocator>> = true;

template <_Format_supported_charT _CharT, class _Traits>
constexpr bool enable_nonlocking_formatter_optimization<basic_string_view<_CharT, _Traits>> = true;

template <class _Ty1, class _Ty2>
constexpr bool enable_nonlocking_formatter_optimization<pair<_Ty1, _Ty2>> =
enable_nonlocking_formatter_optimization<_Ty1> && enable_nonlocking_formatter_optimization<_Ty2>;

template <class... _Ts>
constexpr bool enable_nonlocking_formatter_optimization<tuple<_Ts...>> =
(enable_nonlocking_formatter_optimization<_Ts> && ...);
#endif // _HAS_CXX23
_STD_END

Expand Down
136 changes: 136 additions & 0 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -5805,62 +5805,158 @@ template <class _Rep, class _Period, _Format_supported_charT _CharT>
struct formatter<_CHRONO duration<_Rep, _Period>, _CharT>
: _Fill_tm_formatter<_CHRONO duration<_Rep, _Period>, _CharT> {};

#if _HAS_CXX23
template <class _Rep, class _Period>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO duration<_Rep, _Period>> =
enable_nonlocking_formatter_optimization<_Rep>;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO day, _CharT> : _Fill_tm_formatter<_CHRONO day, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO day> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO month, _CharT> : _Fill_tm_formatter<_CHRONO month, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO month> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO year, _CharT> : _Fill_tm_formatter<_CHRONO year, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO year> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO weekday, _CharT> : _Fill_tm_formatter<_CHRONO weekday, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO weekday> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO weekday_indexed, _CharT> : _Fill_tm_formatter<_CHRONO weekday_indexed, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO weekday_indexed> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO weekday_last, _CharT> : _Fill_tm_formatter<_CHRONO weekday_last, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO weekday_last> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO month_day, _CharT> : _Fill_tm_formatter<_CHRONO month_day, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO month_day> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO month_day_last, _CharT> : _Fill_tm_formatter<_CHRONO month_day_last, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO month_day_last> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO month_weekday, _CharT> : _Fill_tm_formatter<_CHRONO month_weekday, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO month_weekday> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO month_weekday_last, _CharT> : _Fill_tm_formatter<_CHRONO month_weekday_last, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO month_weekday_last> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO year_month, _CharT> : _Fill_tm_formatter<_CHRONO year_month, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO year_month> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO year_month_day, _CharT> : _Fill_tm_formatter<_CHRONO year_month_day, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO year_month_day> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO year_month_day_last, _CharT> : _Fill_tm_formatter<_CHRONO year_month_day_last, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO year_month_day_last> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO year_month_weekday, _CharT> : _Fill_tm_formatter<_CHRONO year_month_weekday, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO year_month_weekday> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO year_month_weekday_last, _CharT>
: _Fill_tm_formatter<_CHRONO year_month_weekday_last, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO year_month_weekday_last> = true;
#endif // _HAS_CXX23

template <class _Rep, class _Period, _Format_supported_charT _CharT>
struct formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT>
: _Fill_tm_formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT> {};

#if _HAS_CXX23
template <class _Rep, class _Period>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO sys_info, _CharT> : _Fill_tm_formatter<_CHRONO sys_info, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO sys_info> = true;
#endif // _HAS_CXX23

template <_Format_supported_charT _CharT>
struct formatter<_CHRONO local_info, _CharT> : _Fill_tm_formatter<_CHRONO local_info, _CharT> {};

#if _HAS_CXX23
template <>
inline constexpr bool enable_nonlocking_formatter_optimization<_CHRONO local_info> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO sys_time<_Duration>, _CharT> {
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
Expand All @@ -5876,6 +5972,11 @@ private:
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")};
};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO sys_time<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO utc_time<_Duration>, _CharT> {
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
Expand All @@ -5892,6 +5993,11 @@ private:
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")};
};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO utc_time<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO tai_time<_Duration>, _CharT> {
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
Expand All @@ -5911,6 +6017,11 @@ private:
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "TAI")};
};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO tai_time<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO gps_time<_Duration>, _CharT> {
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
Expand All @@ -5930,6 +6041,11 @@ private:
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "GPS")};
};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO gps_time<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO file_time<_Duration>, _CharT> {
constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
Expand All @@ -5947,13 +6063,28 @@ private:
_CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")};
};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO file_time<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO local_time<_Duration>, _CharT> : _Fill_tm_formatter<_CHRONO local_time<_Duration>, _CharT> {};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO local_time<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, _Format_supported_charT _CharT>
struct formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT>
: _Fill_tm_formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> {};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO _Local_time_format_t<_Duration>> = true;
#endif // _HAS_CXX23

template <class _Duration, class _TimeZonePtr, _Format_supported_charT _CharT>
struct formatter<_CHRONO zoned_time<_Duration, _TimeZonePtr>, _CharT>
: formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> {
Expand All @@ -5966,6 +6097,11 @@ struct formatter<_CHRONO zoned_time<_Duration, _TimeZonePtr>, _CharT>
}
};

#if _HAS_CXX23
template <class _Duration>
constexpr bool enable_nonlocking_formatter_optimization<_CHRONO zoned_time<_Duration, const _CHRONO time_zone*>> = true;
#endif // _HAS_CXX23

namespace chrono {
template <class _Duration>
_NODISCARD string nonexistent_local_time::_Make_string(const local_time<_Duration>& _Tp, const local_info& _Info) {
Expand Down
Loading

0 comments on commit a36ece0

Please sign in to comment.