Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement P3107R5 optimized <print> #4821

Merged
merged 58 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
915b275
Add enable_nonlocking_formatter_optimization customization point and …
blackninja9939 Jul 7, 2024
17ba44c
Reduce duplication of vformat_to.
blackninja9939 Jul 7, 2024
42efe6d
Make fmt flush behaviour customizable for optimizations.
blackninja9939 Jul 8, 2024
3c53aa0
Print to stream and unicode console without extra string buffer when …
blackninja9939 Jul 8, 2024
0872f1e
Use an initial inline buffer for transcoding, will not require growin…
blackninja9939 Jul 8, 2024
6e56a61
Add print benchmarks.
blackninja9939 Jul 8, 2024
60f3630
Update feature test macro.
blackninja9939 Jul 8, 2024
bd072d5
Fix formatting.
blackninja9939 Jul 8, 2024
62a9834
Be slightly more language correct and use the unique_ptr destructor.
blackninja9939 Jul 8, 2024
211c8d9
No unicode in source files.
blackninja9939 Jul 8, 2024
1f33e66
Add more const
blackninja9939 Jul 8, 2024
15b7e37
Add comment explaining function name.
blackninja9939 Jul 8, 2024
ac1bc82
Add more const
blackninja9939 Jul 8, 2024
5ca4c1e
Update test macro usage
blackninja9939 Jul 8, 2024
d18688f
Add missing inline
blackninja9939 Jul 8, 2024
9f8f9fa
Fix trailing newline print.
blackninja9939 Jul 8, 2024
f01f04b
Fix nodsicard and noexcept
blackninja9939 Jul 9, 2024
8a83b06
Update expected_results.txt
blackninja9939 Jul 9, 2024
dbc0281
Update for print implementation
blackninja9939 Jul 9, 2024
dea2f8c
malloc fails via nullptr so this is also noexcept
blackninja9939 Jul 9, 2024
4bc8927
Drop inline, not required on template vars and unobservable differenc…
blackninja9939 Jul 10, 2024
c870a52
Optimize and improve _Allocated_string
blackninja9939 Aug 29, 2024
4cee26e
Add paper comments
blackninja9939 Aug 29, 2024
58deae6
Order tests alphabetically
blackninja9939 Aug 29, 2024
b781613
Give more specific name to benchmark file
blackninja9939 Aug 29, 2024
3143b1c
Consistent naming
blackninja9939 Aug 29, 2024
140cd7d
Remove unecessary _STD qualifiers
blackninja9939 Aug 29, 2024
757d849
Add explicit includes
blackninja9939 Aug 29, 2024
24fc31e
Delete copy functions (and therefore move) for RAII type
blackninja9939 Aug 29, 2024
1cf3191
Don't reuse names is constructors
blackninja9939 Aug 29, 2024
55cd1e0
Remove redundant comments
blackninja9939 Aug 29, 2024
594bc15
Fix formatting
blackninja9939 Aug 29, 2024
c400675
Fix brace error and comment
blackninja9939 Aug 29, 2024
bc5e9ee
Teach `std::copy` to handle move-only output iterators
CaseyCarter Aug 30, 2024
39a5922
Remove unnecessary `e_n_f_o` specialization for `input_range`s
CaseyCarter Aug 30, 2024
069dbb8
Removed bodies of "fake" iterator member functions
CaseyCarter Aug 30, 2024
3bcb0a1
Minimally initialize `_Allocated_string:_Buffer`
CaseyCarter Aug 30, 2024
05dc4c6
Add missing `e_n_f_o` specializations
CaseyCarter Aug 30, 2024
bb52149
Indicate partial implementation of P3235R3
CaseyCarter Aug 30, 2024
96f861b
Remove extraneous `inline` from variable template
CaseyCarter Aug 30, 2024
6b520c2
Fix `chrono` `e_n_f_o` tests
CaseyCarter Aug 30, 2024
1059e5c
Add license banner.
StephanTLavavej Aug 30, 2024
b83bd12
Add newline.
StephanTLavavej Aug 30, 2024
a94e21f
format should be a const member function.
StephanTLavavej Aug 30, 2024
d20ec48
Verify that unoptimized is formattable.
StephanTLavavej Aug 30, 2024
7af3028
Include cstddef for size_t.
StephanTLavavej Aug 30, 2024
3d69e3c
Test chrono::local-time-format-t.
StephanTLavavej Aug 30, 2024
f2cecfd
Fix comment: 202406L is actually for P3235R3.
StephanTLavavej Aug 30, 2024
1380ac8
Recategorize libcxx failure.
StephanTLavavej Aug 30, 2024
fe434ac
Drop inline for variable templates.
StephanTLavavej Aug 30, 2024
8dad282
Avoid emitting an unnecessary semicolon.
StephanTLavavej Aug 30, 2024
1b2d79b
Mark `_Allocated_string::_Using_heap` as nodiscard.
StephanTLavavej Aug 30, 2024
3951d44
Drop ignored top-level const for value parameters.
StephanTLavavej Aug 30, 2024
48c1b19
Avoid parameter/data member shadowing.
StephanTLavavej Aug 30, 2024
a10240c
Add comma to comment for clarity.
StephanTLavavej Aug 30, 2024
48b6897
Add missing "to" and rewrap.
StephanTLavavej Aug 30, 2024
e013b2c
Add a comment about the `--benchmark_out` options.
StephanTLavavej Aug 30, 2024
83596d2
Add comment about other chrono types that depend on duration.
CaseyCarter Aug 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
#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());
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
}
}
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;
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved

_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