The formatter specializations for _CharT* and const _CharT* typically write all elements in a loop. This format's internal functions are optimized for larger writes. Instead of writing one element at a time, convert the range to a basic_string_view and write that instead. For C string of 6 characters this is a bit slower, but for 60 characters it's faster. The improvements for back_inserter<std::list<_CharT>> are not as great as the others; it just gets as slow as basic_string_view<_CharT>. omparing libcxx/test/benchmarks/write_string_comparison.bench.out-before to libcxx/test/benchmarks/write_string_comparison.bench.out-after Benchmark Time CPU Time Old Time New CPU Old CPU New ----------------------------------------------------------------------------------------------------------------------------------------------------------------- BM_sprintf/C_string_len_6 -0.0015 +0.0013 5 5 5 5 BM_format/C_string_len_6 +0.0390 +0.0416 53 55 53 55 BM_format_to_back_inserter<std::string>/C_string_len_6 +0.0381 +0.0408 53 55 53 55 BM_format_to_back_inserter<std::vector<char>>/C_string_len_6 +0.0287 +0.0315 69 71 69 71 BM_format_to_back_inserter<std::deque<char>>/C_string_len_6 +0.0503 +0.0530 123 129 123 129 BM_format_to_back_inserter<std::list<char>>/C_string_len_6 -0.0241 -0.0213 133 130 133 130 BM_format_to_iterator/<std::array> C_string_len_6 -0.0075 -0.0049 45 45 45 45 BM_format_to_iterator/<std::string> C_string_len_6 +0.0311 +0.0340 44 46 44 46 BM_format_to_iterator/<std::vector> C_string_len_6 +0.0380 +0.0409 43 45 43 45 BM_format_to_iterator/<std::deque> C_string_len_6 +0.0366 +0.0392 48 50 48 50 BM_format/string_len_6 -0.0010 -0.0007 56 55 55 55 BM_format_to_back_inserter<std::string>/string_len_6 +0.0044 +0.0041 55 56 55 55 BM_format_to_back_inserter<std::vector<char>>/string_len_6 +0.0128 +0.0128 70 71 70 71 BM_format_to_back_inserter<std::deque<char>>/string_len_6 +0.0151 +0.0151 126 128 126 128 BM_format_to_back_inserter<std::list<char>>/string_len_6 -0.0719 -0.0718 140 130 139 129 BM_format_to_iterator/<std::array> string_len_6 -0.0323 -0.0324 47 46 47 46 BM_format_to_iterator/<std::string> string_len_6 -0.0011 -0.0010 45 44 44 44 BM_format_to_iterator/<std::vector> string_len_6 -0.0002 -0.0001 45 45 44 44 BM_format_to_iterator/<std::deque> string_len_6 +0.0046 +0.0047 51 51 51 51 BM_format/string_view_len_6 +0.0031 +0.0031 54 54 54 54 BM_format_to_back_inserter<std::string>/string_view_len_6 +0.0041 +0.0040 54 54 54 54 BM_format_to_back_inserter<std::vector<char>>/string_view_len_6 +0.0022 +0.0022 70 70 70 70 BM_format_to_back_inserter<std::deque<char>>/string_view_len_6 +0.0392 +0.0391 124 129 124 129 BM_format_to_back_inserter<std::list<char>>/string_view_len_6 -0.0680 -0.0680 139 129 138 129 BM_format_to_iterator/<std::array> string_view_len_6 -0.0321 -0.0320 47 46 47 46 BM_format_to_iterator/<std::string> string_view_len_6 -0.0013 -0.0011 45 44 44 44 BM_format_to_iterator/<std::vector> string_view_len_6 -0.0024 -0.0023 45 44 44 44 BM_format_to_iterator/<std::deque> string_view_len_6 +0.0057 +0.0057 51 51 51 51 BM_sprintf/C_string_len_60 -0.0035 -0.0035 4 4 4 4 BM_format/C_string_len_60 -0.5627 -0.5627 169 74 169 74 BM_format_to_back_inserter<std::string>/C_string_len_60 -0.5642 -0.5641 170 74 169 74 BM_format_to_back_inserter<std::vector<char>>/C_string_len_60 -0.5300 -0.5299 178 84 178 84 BM_format_to_back_inserter<std::deque<char>>/C_string_len_60 -0.2548 -0.2548 356 265 355 264 BM_format_to_back_inserter<std::list<char>>/C_string_len_60 -0.1013 -0.1013 1325 1191 1322 1188 BM_format_to_iterator/<std::array> C_string_len_60 -0.6790 -0.6791 141 45 141 45 BM_format_to_iterator/<std::string> C_string_len_60 -0.6738 -0.6740 143 47 142 46 BM_format_to_iterator/<std::vector> C_string_len_60 -0.6807 -0.6808 142 45 142 45 BM_format_to_iterator/<std::deque> C_string_len_60 -0.6488 -0.6486 144 51 144 51 BM_format/string_len_60 +0.0118 +0.0117 73 74 73 73 BM_format_to_back_inserter<std::string>/string_len_60 +0.0089 +0.0088 73 73 73 73 BM_format_to_back_inserter<std::vector<char>>/string_len_60 +0.0080 +0.0081 83 84 83 83 BM_format_to_back_inserter<std::deque<char>>/string_len_60 +0.0005 +0.0002 262 263 262 262 BM_format_to_back_inserter<std::list<char>>/string_len_60 -0.0384 -0.0380 1236 1188 1232 1186 BM_format_to_iterator/<std::array> string_len_60 -0.0288 -0.0288 47 46 47 46 BM_format_to_iterator/<std::string> string_len_60 +0.0213 +0.0210 44 45 44 45 BM_format_to_iterator/<std::vector> string_len_60 +0.0202 +0.0205 45 45 44 45 BM_format_to_iterator/<std::deque> string_len_60 +0.0124 +0.0124 50 51 50 51 BM_format/string_view_len_60 +0.0093 +0.0093 73 73 73 73 BM_format_to_back_inserter<std::string>/string_view_len_60 +0.0055 +0.0055 73 73 73 73 BM_format_to_back_inserter<std::vector<char>>/string_view_len_60 +0.0165 +0.0166 81 83 81 83 BM_format_to_back_inserter<std::deque<char>>/string_view_len_60 +0.0138 +0.0140 260 263 259 263 BM_format_to_back_inserter<std::list<char>>/string_view_len_60 -0.0334 -0.0335 1228 1187 1225 1184 BM_format_to_iterator/<std::array> string_view_len_60 -0.0257 -0.0259 48 46 47 46 BM_format_to_iterator/<std::string> string_view_len_60 +0.0324 +0.0323 45 46 44 46 BM_format_to_iterator/<std::vector> string_view_len_60 +0.0174 +0.0177 45 45 44 45 BM_format_to_iterator/<std::deque> string_view_len_60 +0.0076 +0.0076 50 51 50 51 BM_sprintf/C_string_len_6000 +0.4922 +0.4921 77 115 77 114 BM_format/C_string_len_6000 -0.9239 -0.9239 11780 897 11750 894 BM_format_to_back_inserter<std::string>/C_string_len_6000 -0.9239 -0.9239 11792 898 11763 895 BM_format_to_back_inserter<std::vector<char>>/C_string_len_6000 -0.9257 -0.9257 11709 870 11679 868 BM_format_to_back_inserter<std::deque<char>>/C_string_len_6000 -0.4057 -0.4057 25616 15225 25553 15187 BM_format_to_back_inserter<std::list<char>>/C_string_len_6000 -0.0832 -0.0833 127144 116569 126823 116265 BM_format_to_iterator/<std::array> C_string_len_6000 -0.9853 -0.9853 10869 160 10843 160 BM_format_to_iterator/<std::string> C_string_len_6000 -0.9864 -0.9864 10870 148 10841 148 BM_format_to_iterator/<std::vector> C_string_len_6000 -0.9863 -0.9863 10874 149 10846 148 BM_format_to_iterator/<std::deque> C_string_len_6000 -0.9629 -0.9629 11239 417 11212 416 BM_format/string_len_6000 -0.0012 -0.0013 846 845 844 842 BM_format_to_back_inserter<std::string>/string_len_6000 -0.0029 -0.0034 845 843 843 840 BM_format_to_back_inserter<std::vector<char>>/string_len_6000 -0.0129 -0.0125 832 821 830 819 BM_format_to_back_inserter<std::deque<char>>/string_len_6000 +0.0048 +0.0048 15042 15114 15004 15076 BM_format_to_back_inserter<std::list<char>>/string_len_6000 -0.0017 -0.0017 116266 116072 115967 115768 BM_format_to_iterator/<std::array> string_len_6000 -0.0257 -0.0256 120 117 120 117 BM_format_to_iterator/<std::string> string_len_6000 -0.0025 -0.0029 117 117 117 117 BM_format_to_iterator/<std::vector> string_len_6000 -0.0089 -0.0087 118 116 117 116 BM_format_to_iterator/<std::deque> string_len_6000 -0.0478 -0.0477 379 361 378 360 BM_format/string_view_len_6000 -0.0092 -0.0091 842 835 840 833 BM_format_to_back_inserter<std::string>/string_view_len_6000 -0.0081 -0.0083 841 835 839 832 BM_format_to_back_inserter<std::vector<char>>/string_view_len_6000 +0.0089 +0.0088 808 815 806 813 BM_format_to_back_inserter<std::deque<char>>/string_view_len_6000 +0.0068 +0.0068 15030 15131 14992 15093 BM_format_to_back_inserter<std::list<char>>/string_view_len_6000 +0.0012 +0.0010 116099 116243 115813 115934 BM_format_to_iterator/<std::array> string_view_len_6000 -0.0122 -0.0121 118 117 118 116 BM_format_to_iterator/<std::string> string_view_len_6000 +0.0010 +0.0010 106 107 106 106 BM_format_to_iterator/<std::vector> string_view_len_6000 -0.0008 -0.0006 106 106 106 106 BM_format_to_iterator/<std::deque> string_view_len_6000 -0.0549 -0.0548 370 349 369 349 OVERALL_GEOMEAN
158 lines
6.4 KiB
C++
158 lines
6.4 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP___FORMAT_FORMATTER_STRING_H
|
|
#define _LIBCPP___FORMAT_FORMATTER_STRING_H
|
|
|
|
#include <__config>
|
|
#include <__format/concepts.h>
|
|
#include <__format/format_parse_context.h>
|
|
#include <__format/formatter.h>
|
|
#include <__format/formatter_output.h>
|
|
#include <__format/parser_std_format_spec.h>
|
|
#include <__format/write_escaped.h>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
#if _LIBCPP_STD_VER >= 20
|
|
|
|
template <__fmt_char_type _CharT>
|
|
struct _LIBCPP_TEMPLATE_VIS __formatter_string {
|
|
public:
|
|
template <class _ParseContext>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
|
typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_string);
|
|
__format_spec::__process_display_type_string(__parser_.__type_);
|
|
return __result;
|
|
}
|
|
|
|
template <class _FormatContext>
|
|
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
|
format(basic_string_view<_CharT> __str, _FormatContext& __ctx) const {
|
|
# if _LIBCPP_STD_VER >= 23
|
|
if (__parser_.__type_ == __format_spec::__type::__debug)
|
|
return __formatter::__format_escaped_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
|
|
# endif
|
|
|
|
return __formatter::__write_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
|
|
}
|
|
|
|
# if _LIBCPP_STD_VER >= 23
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; }
|
|
# endif
|
|
|
|
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left};
|
|
};
|
|
|
|
// Formatter const char*.
|
|
template <__fmt_char_type _CharT>
|
|
struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT> : public __formatter_string<_CharT> {
|
|
using _Base = __formatter_string<_CharT>;
|
|
|
|
template <class _FormatContext>
|
|
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const {
|
|
_LIBCPP_ASSERT_INTERNAL(__str, "The basic_format_arg constructor should have prevented an invalid pointer.");
|
|
// Converting the input to a basic_string_view means the data is looped over twice;
|
|
// - once to determine the length, and
|
|
// - once to process the data.
|
|
//
|
|
// This sounds slower than writing the output directly. However internally
|
|
// the output algorithms have optimizations for "bulk" operations, which
|
|
// makes this faster than a single-pass character-by-character output.
|
|
return _Base::format(basic_string_view<_CharT>(__str), __ctx);
|
|
}
|
|
};
|
|
|
|
// Formatter char*.
|
|
template <__fmt_char_type _CharT>
|
|
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT> : public formatter<const _CharT*, _CharT> {
|
|
using _Base = formatter<const _CharT*, _CharT>;
|
|
|
|
template <class _FormatContext>
|
|
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT* __str, _FormatContext& __ctx) const {
|
|
return _Base::format(__str, __ctx);
|
|
}
|
|
};
|
|
|
|
// Formatter char[].
|
|
template <__fmt_char_type _CharT, size_t _Size>
|
|
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT[_Size], _CharT> : public __formatter_string<_CharT> {
|
|
using _Base = __formatter_string<_CharT>;
|
|
|
|
template <class _FormatContext>
|
|
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
|
format(const _CharT (&__str)[_Size], _FormatContext& __ctx) const {
|
|
return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx);
|
|
}
|
|
};
|
|
|
|
// Formatter std::string.
|
|
template <__fmt_char_type _CharT, class _Traits, class _Allocator>
|
|
struct _LIBCPP_TEMPLATE_VIS formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT>
|
|
: public __formatter_string<_CharT> {
|
|
using _Base = __formatter_string<_CharT>;
|
|
|
|
template <class _FormatContext>
|
|
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
|
format(const basic_string<_CharT, _Traits, _Allocator>& __str, _FormatContext& __ctx) const {
|
|
// Drop _Traits and _Allocator to have one std::basic_string formatter.
|
|
return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx);
|
|
}
|
|
};
|
|
|
|
// Formatter std::string_view.
|
|
template <__fmt_char_type _CharT, class _Traits>
|
|
struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT> : public __formatter_string<_CharT> {
|
|
using _Base = __formatter_string<_CharT>;
|
|
|
|
template <class _FormatContext>
|
|
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
|
format(basic_string_view<_CharT, _Traits> __str, _FormatContext& __ctx) const {
|
|
// Drop _Traits to have one std::basic_string_view formatter.
|
|
return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx);
|
|
}
|
|
};
|
|
|
|
# if _LIBCPP_STD_VER >= 23
|
|
template <>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<char*> = true;
|
|
template <>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<const char*> = true;
|
|
template <size_t _Size>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<char[_Size]> = true;
|
|
template <class _Traits, class _Allocator>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<basic_string<char, _Traits, _Allocator>> = true;
|
|
template <class _Traits>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<basic_string_view<char, _Traits>> = true;
|
|
|
|
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
|
template <>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<wchar_t*> = true;
|
|
template <>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<const wchar_t*> = true;
|
|
template <size_t _Size>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<wchar_t[_Size]> = true;
|
|
template <class _Traits, class _Allocator>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<basic_string<wchar_t, _Traits, _Allocator>> = true;
|
|
template <class _Traits>
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<basic_string_view<wchar_t, _Traits>> = true;
|
|
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
|
# endif // _LIBCPP_STD_VER >= 23
|
|
#endif // _LIBCPP_STD_VER >= 20
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // _LIBCPP___FORMAT_FORMATTER_STRING_H
|