aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/libcxx/include/__format/formatter_output.h
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-09-02 21:17:18 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-12-08 17:34:50 +0000
commit06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch)
tree62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/libcxx/include/__format/formatter_output.h
parentcf037972ea8863e2bab7461d77345367d2c1e054 (diff)
parent7fa27ce4a07f19b07799a767fc29416f3b625afb (diff)
Diffstat (limited to 'contrib/llvm-project/libcxx/include/__format/formatter_output.h')
-rw-r--r--contrib/llvm-project/libcxx/include/__format/formatter_output.h366
1 files changed, 58 insertions, 308 deletions
diff --git a/contrib/llvm-project/libcxx/include/__format/formatter_output.h b/contrib/llvm-project/libcxx/include/__format/formatter_output.h
index 467692559ce9..072305b6dbca 100644
--- a/contrib/llvm-project/libcxx/include/__format/formatter_output.h
+++ b/contrib/llvm-project/libcxx/include/__format/formatter_output.h
@@ -13,22 +13,21 @@
#include <__algorithm/ranges_copy.h>
#include <__algorithm/ranges_fill_n.h>
#include <__algorithm/ranges_transform.h>
-#include <__chrono/statically_widen.h>
+#include <__bit/countl.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__format/buffer.h>
#include <__format/concepts.h>
-#include <__format/escaped_output_table.h>
#include <__format/formatter.h>
#include <__format/parser_std_format_spec.h>
#include <__format/unicode.h>
#include <__iterator/back_insert_iterator.h>
-#include <__type_traits/make_unsigned.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h> // iter_value_t
+#include <__memory/addressof.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
-#include <charconv>
#include <cstddef>
-#include <string>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -37,7 +36,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-#if _LIBCPP_STD_VER > 17
+#if _LIBCPP_STD_VER >= 20
namespace __formatter {
@@ -59,15 +58,15 @@ _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) {
return __c;
}
-struct _LIBCPP_TYPE_VIS __padding_size_result {
+struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result {
size_t __before_;
size_t __after_;
};
_LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
__padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) {
- _LIBCPP_ASSERT(__width > __size, "don't call this function when no padding is required");
- _LIBCPP_ASSERT(
+ _LIBCPP_ASSERT_UNCATEGORIZED(__width > __size, "don't call this function when no padding is required");
+ _LIBCPP_ASSERT_UNCATEGORIZED(
__align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding");
size_t __fill = __width - __size;
@@ -161,69 +160,45 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value)
}
}
-template <class _OutIt, class _CharT>
-_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first,
- const char* __last, string&& __grouping, _CharT __sep,
- __format_spec::__parsed_specifications<_CharT> __specs) {
- int __size = (__first - __begin) + // [sign][prefix]
- (__last - __first) + // data
- (__grouping.size() - 1); // number of separator characters
-
- __padding_size_result __padding = {0, 0};
- if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) {
- // Write [sign][prefix].
- __out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
-
- if (__specs.__width_ > __size) {
- // Write zero padding.
- __padding.__before_ = __specs.__width_ - __size;
- __out_it = __formatter::__fill(_VSTD::move(__out_it), __specs.__width_ - __size, _CharT('0'));
- }
- } else {
- if (__specs.__width_ > __size) {
- // Determine padding and write padding.
- __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
-
- __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
- }
- // Write [sign][prefix].
- __out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
- }
+# ifndef _LIBCPP_HAS_NO_UNICODE
+template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
+ requires(same_as<_CharT, char>)
+_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
+ std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0]));
+ if (__bytes == 0)
+ return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
+
+ for (size_t __i = 0; __i < __n; ++__i)
+ __out_it = __formatter::__copy(
+ std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it));
+ return __out_it;
+}
- auto __r = __grouping.rbegin();
- auto __e = __grouping.rend() - 1;
- _LIBCPP_ASSERT(__r != __e, "The slow grouping formatting is used while "
- "there will be no separators written.");
- // The output is divided in small groups of numbers to write:
- // - A group before the first separator.
- // - A separator and a group, repeated for the number of separators.
- // - A group after the last separator.
- // This loop achieves that process by testing the termination condition
- // midway in the loop.
- //
- // TODO FMT This loop evaluates the loop invariant `__parser.__type !=
- // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
- // happens in the __write call.) Benchmark whether making two loops and
- // hoisting the invariant is worth the effort.
- while (true) {
- if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) {
- __last = __first + *__r;
- __out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __hex_to_upper);
- __first = __last;
- } else {
- __out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it));
- __first += *__r;
- }
-
- if (__r == __e)
- break;
-
- ++__r;
- *__out_it++ = __sep;
- }
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
+ requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2)
+_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
+ if (!__unicode::__is_high_surrogate(__value.__data[0]))
+ return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
+
+ for (size_t __i = 0; __i < __n; ++__i)
+ __out_it = __formatter::__copy(
+ std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it));
+ return __out_it;
+}
- return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
+template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
+ requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4)
+_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
+ return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
}
+# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+# else // _LIBCPP_HAS_NO_UNICODE
+template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
+_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
+ return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
+}
+# endif // _LIBCPP_HAS_NO_UNICODE
/// Writes the input to the output with the required padding.
///
@@ -261,27 +236,27 @@ __write(basic_string_view<_CharT> __str,
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
}
-template <class _CharT, class _ParserCharT>
+template <contiguous_iterator _Iterator, class _ParserCharT>
_LIBCPP_HIDE_FROM_ABI auto
-__write(const _CharT* __first,
- const _CharT* __last,
- output_iterator<const _CharT&> auto __out_it,
+__write(_Iterator __first,
+ _Iterator __last,
+ output_iterator<const iter_value_t<_Iterator>&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
ptrdiff_t __size) -> decltype(__out_it) {
- _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range");
return __formatter::__write(basic_string_view{__first, __last}, _VSTD::move(__out_it), __specs, __size);
}
/// \overload
///
/// Calls the function above where \a __size = \a __last - \a __first.
-template <class _CharT, class _ParserCharT>
+template <contiguous_iterator _Iterator, class _ParserCharT>
_LIBCPP_HIDE_FROM_ABI auto
-__write(const _CharT* __first,
- const _CharT* __last,
- output_iterator<const _CharT&> auto __out_it,
+__write(_Iterator __first,
+ _Iterator __last,
+ output_iterator<const iter_value_t<_Iterator>&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) {
- _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range");
return __formatter::__write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first);
}
@@ -290,7 +265,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _Cha
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
_UnaryOperation __op) -> decltype(__out_it) {
- _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range");
ptrdiff_t __size = __last - __first;
if (__size >= __specs.__width_)
@@ -302,35 +277,6 @@ _LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _Cha
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
}
-/// Writes additional zero's for the precision before the exponent.
-/// This is used when the precision requested in the format string is larger
-/// than the maximum precision of the floating-point type. These precision
-/// digits are always 0.
-///
-/// \param __exponent The location of the exponent character.
-/// \param __num_trailing_zeros The number of 0's to write before the exponent
-/// character.
-template <class _CharT, class _ParserCharT>
-_LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros(
- const _CharT* __first,
- const _CharT* __last,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_ParserCharT> __specs,
- size_t __size,
- const _CharT* __exponent,
- size_t __num_trailing_zeros) -> decltype(__out_it) {
- _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
- _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
-
- __padding_size_result __padding =
- __formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_);
- __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
- __out_it = __formatter::__copy(__first, __exponent, _VSTD::move(__out_it));
- __out_it = __formatter::__fill(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0'));
- __out_it = __formatter::__copy(__exponent, __last, _VSTD::move(__out_it));
- return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
-}
-
/// Writes a string using format's width estimation algorithm.
///
/// \pre !__specs.__has_precision()
@@ -342,7 +288,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
basic_string_view<_CharT> __str,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
- _LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_string");
+ _LIBCPP_ASSERT_UNCATEGORIZED(!__specs.__has_precision(), "use __write_string");
// No padding -> copy the string
if (!__specs.__has_width())
@@ -359,211 +305,15 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) {
- __format_spec::__column_width_result<_CharT> __result =
+ __format_spec::__column_width_result __result =
__format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down);
__str = basic_string_view<_CharT>{__str.begin(), __result.__last_};
return __result.__width_;
}
-/// Writes a string using format's width estimation algorithm.
-///
-/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
-/// input is ASCII.
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI auto __write_string(
- basic_string_view<_CharT> __str,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
- if (!__specs.__has_precision())
- return __formatter::__write_string_no_precision(__str, _VSTD::move(__out_it), __specs);
-
- int __size = __formatter::__truncate(__str, __specs.__precision_);
-
- return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size);
-}
-
-# if _LIBCPP_STD_VER > 20
-
-struct __nul_terminator {};
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) {
- return *__cstr == _CharT('\0');
-}
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI void
-__write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) {
- back_insert_iterator __out_it{__str};
- std::ranges::copy(__prefix, __nul_terminator{}, __out_it);
-
- char __buffer[8];
- to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16);
- _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
- std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it);
-
- __str += _CharT('}');
-}
-
-// [format.string.escaped]/2.2.1.2
-// ...
-// then the sequence \u{hex-digit-sequence} is appended to E, where
-// hex-digit-sequence is the shortest hexadecimal representation of C using
-// lower-case hexadecimal digits.
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) {
- __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{"));
-}
-
-// [format.string.escaped]/2.2.3
-// Otherwise (X is a sequence of ill-formed code units), each code unit U is
-// appended to E in order as the sequence \x{hex-digit-sequence}, where
-// hex-digit-sequence is the shortest hexadecimal representation of U using
-// lower-case hexadecimal digits.
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) {
- __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{"));
-}
-
-template <class _CharT>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value) {
-# ifdef _LIBCPP_HAS_NO_UNICODE
- // For ASCII assume everything above 127 is printable.
- if (__value > 127)
- return false;
-# endif
-
- if (!__escaped_output_table::__needs_escape(__value))
- return false;
-
- __formatter::__write_well_formed_escaped_code_unit(__str, __value);
- return true;
-}
-
-template <class _CharT>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) {
- return static_cast<make_unsigned_t<_CharT>>(__value);
-}
-
-enum class _LIBCPP_ENUM_VIS __escape_quotation_mark { __apostrophe, __double_quote };
-
-// [format.string.escaped]/2
-template <class _CharT>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
-__is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value, __escape_quotation_mark __mark) {
- // 2.2.1.1 - Mapped character in [tab:format.escape.sequences]
- switch (__value) {
- case _CharT('\t'):
- __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t");
- return true;
- case _CharT('\n'):
- __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n");
- return true;
- case _CharT('\r'):
- __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r");
- return true;
- case _CharT('\''):
- if (__mark == __escape_quotation_mark::__apostrophe)
- __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')");
- else
- __str += __value;
- return true;
- case _CharT('"'):
- if (__mark == __escape_quotation_mark::__double_quote)
- __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")");
- else
- __str += __value;
- return true;
- case _CharT('\\'):
- __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)");
- return true;
-
- // 2.2.1.2 - Space
- case _CharT(' '):
- __str += __value;
- return true;
- }
-
- // 2.2.2
- // Otherwise, if X is a shift sequence, the effect on E and further
- // decoding of S is unspecified.
- // For now shift sequences are ignored and treated as Unicode. Other parts
- // of the format library do the same. It's unknown how ostream treats them.
- // TODO FMT determine what to do with shift sequences.
-
- // 2.2.1.2.1 and 2.2.1.2.2 - Escape
- return __formatter::__is_escaped_sequence_written(__str, __formatter::__to_char32(__value));
-}
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI void
-__escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) {
- __unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()};
-
- while (!__view.__at_end()) {
- const _CharT* __first = __view.__position();
- typename __unicode::__consume_p2286_result __result = __view.__consume_p2286();
- if (__result.__ill_formed_size == 0) {
- if (!__formatter::__is_escaped_sequence_written(__str, __result.__value, __mark))
- // 2.2.1.3 - Add the character
- ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str));
-
- } else {
- // 2.2.3 sequence of ill-formed code units
- // The number of code-units in __result.__value depends on the character type being used.
- if constexpr (sizeof(_CharT) == 1) {
- _LIBCPP_ASSERT(__result.__ill_formed_size == 1 || __result.__ill_formed_size == 4,
- "illegal number of invalid code units.");
- if (__result.__ill_formed_size == 1) // ill-formed, one code unit
- __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value & 0xff);
- else { // out of valid range, four code units
- // The code point was properly encoded, decode the value.
- __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value >> 18 | 0xf0);
- __formatter::__write_escape_ill_formed_code_unit(__str, (__result.__value >> 12 & 0x3f) | 0x80);
- __formatter::__write_escape_ill_formed_code_unit(__str, (__result.__value >> 6 & 0x3f) | 0x80);
- __formatter::__write_escape_ill_formed_code_unit(__str, (__result.__value & 0x3f) | 0x80);
- }
- } else if constexpr (sizeof(_CharT) == 2) {
- _LIBCPP_ASSERT(__result.__ill_formed_size == 1, "for UTF-16 at most one invalid code unit");
- __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value & 0xffff);
- } else {
- static_assert(sizeof(_CharT) == 4, "unsupported character width");
- _LIBCPP_ASSERT(__result.__ill_formed_size == 1, "for UTF-32 one code unit is one code point");
- __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value);
- }
- }
- }
-}
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI auto
-__format_escaped_char(_CharT __value,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
- basic_string<_CharT> __str;
- __str += _CharT('\'');
- __formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe);
- __str += _CharT('\'');
- return __formatter::__write(__str.data(), __str.data() + __str.size(), _VSTD::move(__out_it), __specs, __str.size());
-}
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI auto
-__format_escaped_string(basic_string_view<_CharT> __values,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
- basic_string<_CharT> __str;
- __str += _CharT('"');
- __formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote);
- __str += _CharT('"');
- return __formatter::__write_string(basic_string_view{__str}, _VSTD::move(__out_it), __specs);
-}
-
-# endif // _LIBCPP_STD_VER > 20
-
} // namespace __formatter
-#endif //_LIBCPP_STD_VER > 17
+#endif //_LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD