aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/std
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include/std')
-rw-r--r--libstdc++-v3/include/std/format1387
-rw-r--r--libstdc++-v3/include/std/future66
-rw-r--r--libstdc++-v3/include/std/generator10
-rw-r--r--libstdc++-v3/include/std/latch12
-rw-r--r--libstdc++-v3/include/std/numeric8
-rw-r--r--libstdc++-v3/include/std/queue80
-rw-r--r--libstdc++-v3/include/std/ranges1
-rw-r--r--libstdc++-v3/include/std/stack48
-rw-r--r--libstdc++-v3/include/std/thread45
9 files changed, 1286 insertions, 371 deletions
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 23f0097..69d8d18 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -56,7 +56,7 @@
#include <bits/ranges_base.h> // input_range, range_reference_t
#include <bits/ranges_util.h> // subrange
#include <bits/ranges_algobase.h> // ranges::copy
-#include <bits/stl_iterator.h> // back_insert_iterator
+#include <bits/stl_iterator.h> // back_insert_iterator, counted_iterator
#include <bits/stl_pair.h> // __is_pair
#include <bits/unicode.h> // __is_scalar_value, _Utf_view, etc.
#include <bits/utility.h> // tuple_size_v
@@ -97,22 +97,24 @@ namespace __format
#define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
#define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S)
+ // Size for stack located buffer
+ template<typename _CharT>
+ constexpr size_t __stackbuf_size = 32 * sizeof(void*) / sizeof(_CharT);
+
// Type-erased character sinks.
template<typename _CharT> class _Sink;
template<typename _CharT> class _Fixedbuf_sink;
- template<typename _Seq> class _Seq_sink;
-
- template<typename _CharT, typename _Alloc = allocator<_CharT>>
- using _Str_sink
- = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
-
- // template<typename _CharT, typename _Alloc = allocator<_CharT>>
- // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>;
+ template<typename _Out, typename _CharT> class _Padding_sink;
// Output iterator that writes to a type-erase character sink.
template<typename _CharT>
class _Sink_iter;
+ // An unspecified output iterator type used in the `formattable` concept.
+ template<typename _CharT>
+ struct _Iter_for
+ { using type = back_insert_iterator<basic_string<_CharT>>; };
+
template<typename _CharT>
using __format_context = basic_format_context<_Sink_iter<_CharT>, _CharT>;
@@ -131,6 +133,7 @@ namespace __format
template<typename, typename...> friend struct std::basic_format_string;
};
+
} // namespace __format
/// @endcond
@@ -475,16 +478,10 @@ namespace __format
_Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c,
// Presentation types for floating-point types.
_Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G,
- _Pres_p = 0, _Pres_P, // For pointers.
- _Pres_s = 0, // For strings and bool.
- _Pres_esc = 0xf, // For strings and charT.
- };
-
- enum _Align {
- _Align_default,
- _Align_left,
- _Align_right,
- _Align_centre,
+ _Pres_p = 0, _Pres_P, // For pointers.
+ _Pres_s = 0, // For strings, bool
+ _Pres_seq = 0, _Pres_str, // For ranges
+ _Pres_esc = 0xf, // For strings, charT and ranges
};
enum _Sign {
@@ -544,42 +541,48 @@ namespace __format
// pre: __first != __last
constexpr iterator
_M_parse_fill_and_align(iterator __first, iterator __last) noexcept
+ { return _M_parse_fill_and_align(__first, __last, "{"); }
+
+ // pre: __first != __last
+ constexpr iterator
+ _M_parse_fill_and_align(iterator __first, iterator __last, string_view __not_fill) noexcept
{
- if (*__first != '{')
+ for (char __c : __not_fill)
+ if (*__first == static_cast<_CharT>(__c))
+ return __first;
+
+ using namespace __unicode;
+ if constexpr (__literal_encoding_is_unicode<_CharT>())
{
- using namespace __unicode;
- if constexpr (__literal_encoding_is_unicode<_CharT>())
- {
- // Accept any UCS scalar value as fill character.
- _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last});
- if (!__uv.empty())
- {
- auto __beg = __uv.begin();
- char32_t __c = *__beg++;
- if (__is_scalar_value(__c))
- if (auto __next = __beg.base(); __next != __last)
- if (_Align __align = _S_align(*__next))
- {
- _M_fill = __c;
- _M_align = __align;
- return ++__next;
- }
- }
- }
- else if (__last - __first >= 2)
- if (_Align __align = _S_align(__first[1]))
- {
- _M_fill = *__first;
- _M_align = __align;
- return __first + 2;
- }
+ // Accept any UCS scalar value as fill character.
+ _Utf32_view<ranges::subrange<iterator>> __uv({__first, __last});
+ if (!__uv.empty())
+ {
+ auto __beg = __uv.begin();
+ char32_t __c = *__beg++;
+ if (__is_scalar_value(__c))
+ if (auto __next = __beg.base(); __next != __last)
+ if (_Align __align = _S_align(*__next))
+ {
+ _M_fill = __c;
+ _M_align = __align;
+ return ++__next;
+ }
+ }
+ }
+ else if (__last - __first >= 2)
+ if (_Align __align = _S_align(__first[1]))
+ {
+ _M_fill = *__first;
+ _M_align = __align;
+ return __first + 2;
+ }
- if (_Align __align = _S_align(__first[0]))
- {
- _M_fill = ' ';
- _M_align = __align;
- return __first + 1;
- }
+ if (_Align __align = _S_align(__first[0]))
+ {
+ _M_fill = ' ';
+ _M_align = __align;
+ return __first + 1;
}
return __first;
}
@@ -875,6 +878,25 @@ namespace __format
__spec._M_fill);
}
+ template<typename _CharT>
+ size_t
+ __truncate(basic_string_view<_CharT>& __s, size_t __prec)
+ {
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ {
+ if (__prec != (size_t)-1)
+ return __unicode::__truncate(__s, __prec);
+ else
+ return __unicode::__field_width(__s);
+ }
+ else
+ {
+ __s = __s.substr(0, __prec);
+ return __s.size();
+ }
+ }
+
+
// Values are indices into _Escapes::all.
enum class _Term_char : unsigned char {
_Tc_quote = 12,
@@ -934,11 +956,27 @@ namespace __format
static consteval
_Str_view _S_all()
- { return _GLIBCXX_WIDEN("{}"); }
+ { return _GLIBCXX_WIDEN("[]{}(), : "); }
static consteval
- _Str_view _S_braces()
+ _Str_view _S_squares()
{ return _S_all().substr(0, 2); }
+
+ static consteval
+ _Str_view _S_braces()
+ { return _S_all().substr(2, 2); }
+
+ static consteval
+ _Str_view _S_parens()
+ { return _S_all().substr(4, 2); }
+
+ static consteval
+ _Str_view _S_comma()
+ { return _S_all().substr(6, 2); }
+
+ static consteval
+ _Str_view _S_colon()
+ { return _S_all().substr(8, 2); }
};
template<typename _CharT>
@@ -1231,6 +1269,13 @@ namespace __format
template<__char _CharT>
struct __formatter_str
{
+ __formatter_str() = default;
+
+ constexpr
+ __formatter_str(_Spec<_CharT> __spec) noexcept
+ : _M_spec(__spec)
+ { }
+
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
{
@@ -1287,71 +1332,119 @@ namespace __format
format(basic_string_view<_CharT> __s,
basic_format_context<_Out, _CharT>& __fc) const
{
- constexpr auto __term = __format::_Term_char::_Tc_quote;
- const auto __write_direct = [&]
- {
- if (_M_spec._M_type == _Pres_esc)
- return __format::__write_escaped(__fc.out(), __s, __term);
- else
- return __format::__write(__fc.out(), __s);
- };
+ if (_M_spec._M_type == _Pres_esc)
+ return _M_format_escaped(__s, __fc);
if (_M_spec._M_width_kind == _WP_none
&& _M_spec._M_prec_kind == _WP_none)
- return __write_direct();
+ return __format::__write(__fc.out(), __s);
+
+ const size_t __maxwidth = _M_spec._M_get_precision(__fc);
+ const size_t __width = __format::__truncate(__s, __maxwidth);
+ return __format::__write_padded_as_spec(__s, __width, __fc, _M_spec);
+ }
- const size_t __prec =
- _M_spec._M_prec_kind != _WP_none
- ? _M_spec._M_get_precision(__fc)
- : basic_string_view<_CharT>::npos;
+ template<typename _Out>
+ _Out
+ _M_format_escaped(basic_string_view<_CharT> __s,
+ basic_format_context<_Out, _CharT>& __fc) const
+ {
+ constexpr auto __term = __format::_Term_char::_Tc_quote;
+ const size_t __padwidth = _M_spec._M_get_width(__fc);
+ if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none)
+ return __format::__write_escaped(__fc.out(), __s, __term);
- const size_t __estimated_width = _S_trunc(__s, __prec);
+ const size_t __maxwidth = _M_spec._M_get_precision(__fc);
+ const size_t __width = __truncate(__s, __maxwidth);
// N.B. Escaping only increases width
- if (_M_spec._M_get_width(__fc) <= __estimated_width
- && _M_spec._M_prec_kind == _WP_none)
- return __write_direct();
-
- if (_M_spec._M_type != _Pres_esc)
- return __format::__write_padded_as_spec(__s, __estimated_width,
- __fc, _M_spec);
-
- __format::_Str_sink<_CharT> __sink;
- __format::_Sink_iter<_CharT> __out(__sink);
- __format::__write_escaped(__out, __s, __term);
- basic_string_view<_CharT> __escaped(__sink.view().data(),
- __sink.view().size());
- const size_t __escaped_width = _S_trunc(__escaped, __prec);
+ if (__padwidth <= __width && _M_spec._M_prec_kind == _WP_none)
+ return __format::__write_escaped(__fc.out(), __s, __term);
+
// N.B. [tab:format.type.string] defines '?' as
// Copies the escaped string ([format.string.escaped]) to the output,
// so precision seem to appy to escaped string.
- return __format::__write_padded_as_spec(__escaped, __escaped_width,
- __fc, _M_spec);
+ _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth, __maxwidth);
+ __format::__write_escaped(__sink.out(), __s, __term);
+ return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
}
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
+ template<ranges::input_range _Rg, typename _Out>
+ requires same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _CharT>
+ _Out
+ _M_format_range(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
+ {
+ using _Range = remove_reference_t<_Rg>;
+ using _String = basic_string<_CharT>;
+ using _String_view = basic_string_view<_CharT>;
+ if constexpr (!is_lvalue_reference_v<_Rg>)
+ return _M_format_range<_Range&>(__rg, __fc);
+ else if constexpr (!is_const_v<_Range>
+ && __simply_formattable_range<_Range, _CharT>)
+ return _M_format_range<const _Range&>(__rg, __fc);
+ else if constexpr (ranges::contiguous_range<_Rg>)
+ {
+ _String_view __str(ranges::data(__rg),
+ size_t(ranges::distance(__rg)));
+ return format(__str, __fc);
+ }
+ else if (_M_spec._M_type != _Pres_esc)
+ {
+ const size_t __padwidth = _M_spec._M_get_width(__fc);
+ if (__padwidth == 0 && _M_spec._M_prec_kind == _WP_none)
+ return ranges::copy(__rg, __fc.out()).out;
+
+ _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth,
+ _M_spec._M_get_precision(__fc));
+ ranges::copy(__rg, __sink.out());
+ return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
+ }
+ else if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const size_t __n(ranges::distance(__rg));
+ size_t __w = __n;
+ if constexpr (!__unicode::__literal_encoding_is_unicode<_CharT>())
+ if (size_t __max = _M_spec._M_get_precision(__fc); __n > __max)
+ __w == __max;
+
+ if (__w <= __format::__stackbuf_size<_CharT>)
+ {
+ _CharT __buf[__format::__stackbuf_size<_CharT>];
+ ranges::copy_n(ranges::begin(__rg), __w, __buf);
+ return _M_format_escaped(_String_view(__buf, __n), __fc);
+ }
+ else if constexpr (ranges::random_access_range<_Rg>)
+ {
+ ranges::iterator_t<_Rg> __first = ranges::begin(__rg);
+ ranges::subrange __sub(__first, __first + __w);
+ return _M_format_escaped(_String(from_range, __sub), __fc);
+ }
+ else if (__w <= __n)
+ {
+ ranges::subrange __sub(
+ counted_iterator(ranges::begin(__rg), __w),
+ default_sentinel);
+ return _M_format_escaped(_String(from_range, __sub), __fc);
+ }
+ else if constexpr (ranges::sized_range<_Rg>)
+ return _M_format_escaped(_String(from_range, __rg), __fc);
+ else
+ {
+ // N.B. preserve the computed size
+ ranges::subrange __sub(__rg, __n);
+ return _M_format_escaped(_String(from_range, __sub), __fc);
+ }
+ }
+ else
+ return _M_format_escaped(_String(from_range, __rg), __fc);
+ }
+
constexpr void
set_debug_format() noexcept
{ _M_spec._M_type = _Pres_esc; }
#endif
private:
- static size_t
- _S_trunc(basic_string_view<_CharT>& __s, size_t __prec)
- {
- if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
- {
- if (__prec != basic_string_view<_CharT>::npos)
- return __unicode::__truncate(__s, __prec);
- else
- return __unicode::__field_width(__s);
- }
- else
- {
- __s = __s.substr(0, __prec);
- return __s.size();
- }
- }
-
_Spec<_CharT> _M_spec{};
};
@@ -1364,6 +1457,13 @@ namespace __format
static constexpr _Pres_type _AsBool = _Pres_s;
static constexpr _Pres_type _AsChar = _Pres_c;
+ __formatter_int() = default;
+
+ constexpr
+ __formatter_int(_Spec<_CharT> __spec) noexcept
+ : _M_spec(__spec)
+ { }
+
constexpr typename basic_format_parse_context<_CharT>::iterator
_M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type)
{
@@ -1627,7 +1727,7 @@ namespace __format
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
_M_format_character_escaped(_CharT __c,
- basic_format_context<_Out, _CharT>& __fc) const
+ basic_format_context<_Out, _CharT>& __fc) const
{
using _Esc = _Escapes<_CharT>;
constexpr auto __term = __format::_Term_char::_Tc_apos;
@@ -1637,8 +1737,7 @@ namespace __format
_CharT __buf[12];
__format::_Fixedbuf_sink<_CharT> __sink(__buf);
- __format::_Sink_iter<_CharT> __out(__sink);
- __format::__write_escaped(__out, __in, __term);
+ __format::__write_escaped(__sink.out(), __in, __term);
const basic_string_view<_CharT> __escaped = __sink.view();
size_t __estimated_width;
@@ -2312,6 +2411,134 @@ namespace __format
_Spec<_CharT> _M_spec{};
};
+ template<__format::__char _CharT>
+ struct __formatter_ptr
+ {
+ __formatter_ptr() = default;
+
+ constexpr
+ __formatter_ptr(_Spec<_CharT> __spec) noexcept
+ : _M_spec(__spec)
+ { }
+
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ {
+ __format::_Spec<_CharT> __spec{};
+ const auto __last = __pc.end();
+ auto __first = __pc.begin();
+
+ auto __finalize = [this, &__spec] {
+ _M_spec = __spec;
+ };
+
+ auto __finished = [&] {
+ if (__first == __last || *__first == '}')
+ {
+ __finalize();
+ return true;
+ }
+ return false;
+ };
+
+ if (__finished())
+ return __first;
+
+ __first = __spec._M_parse_fill_and_align(__first, __last);
+ if (__finished())
+ return __first;
+
+// _GLIBCXX_RESOLVE_LIB_DEFECTS
+// P2510R3 Formatting pointers
+#if __glibcxx_format >= 202304L
+ __first = __spec._M_parse_zero_fill(__first, __last);
+ if (__finished())
+ return __first;
+#endif
+
+ __first = __spec._M_parse_width(__first, __last, __pc);
+
+ if (__first != __last)
+ {
+ if (*__first == 'p')
+ ++__first;
+#if __glibcxx_format >= 202304L
+ else if (*__first == 'P')
+ {
+ __spec._M_type = __format::_Pres_P;
+ ++__first;
+ }
+#endif
+ }
+
+ if (__finished())
+ return __first;
+
+ __format::__failed_to_parse_format_spec();
+ }
+
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
+ {
+ auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
+ char __buf[2 + sizeof(__v) * 2];
+ auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
+ __u, 16);
+ int __n = __ptr - __buf;
+ __buf[0] = '0';
+ __buf[1] = 'x';
+#if __glibcxx_format >= 202304L
+ if (_M_spec._M_type == __format::_Pres_P)
+ {
+ __buf[1] = 'X';
+ for (auto __p = __buf + 2; __p != __ptr; ++__p)
+#if __has_builtin(__builtin_toupper)
+ *__p = __builtin_toupper(*__p);
+#else
+ *__p = std::toupper(*__p);
+#endif
+ }
+#endif
+
+ basic_string_view<_CharT> __str;
+ if constexpr (is_same_v<_CharT, char>)
+ __str = string_view(__buf, __n);
+#ifdef _GLIBCXX_USE_WCHAR_T
+ else
+ {
+ auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
+ std::__to_wstring_numeric(__buf, __n, __p);
+ __str = wstring_view(__p, __n);
+ }
+#endif
+
+#if __glibcxx_format >= 202304L
+ if (_M_spec._M_zero_fill)
+ {
+ size_t __width = _M_spec._M_get_width(__fc);
+ if (__width <= __str.size())
+ return __format::__write(__fc.out(), __str);
+
+ auto __out = __fc.out();
+ // Write "0x" or "0X" prefix before zero-filling.
+ __out = __format::__write(std::move(__out), __str.substr(0, 2));
+ __str.remove_prefix(2);
+ size_t __nfill = __width - __n;
+ return __format::__write_padded(std::move(__out), __str,
+ __format::_Align_right,
+ __nfill, _CharT('0'));
+ }
+#endif
+
+ return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
+ __format::_Align_right);
+ }
+
+ private:
+ __format::_Spec<_CharT> _M_spec{};
+ };
+
} // namespace __format
/// @endcond
@@ -2776,120 +3003,15 @@ namespace __format
constexpr typename basic_format_parse_context<_CharT>::iterator
parse(basic_format_parse_context<_CharT>& __pc)
- {
- __format::_Spec<_CharT> __spec{};
- const auto __last = __pc.end();
- auto __first = __pc.begin();
-
- auto __finalize = [this, &__spec] {
- _M_spec = __spec;
- };
-
- auto __finished = [&] {
- if (__first == __last || *__first == '}')
- {
- __finalize();
- return true;
- }
- return false;
- };
-
- if (__finished())
- return __first;
-
- __first = __spec._M_parse_fill_and_align(__first, __last);
- if (__finished())
- return __first;
-
-// _GLIBCXX_RESOLVE_LIB_DEFECTS
-// P2510R3 Formatting pointers
-#if __glibcxx_format >= 202304L
- __first = __spec._M_parse_zero_fill(__first, __last);
- if (__finished())
- return __first;
-#endif
-
- __first = __spec._M_parse_width(__first, __last, __pc);
-
- if (__first != __last)
- {
- if (*__first == 'p')
- ++__first;
-#if __glibcxx_format >= 202304L
- else if (*__first == 'P')
- {
- __spec._M_type = __format::_Pres_P;
- ++__first;
- }
-#endif
- }
-
- if (__finished())
- return __first;
-
- __format::__failed_to_parse_format_spec();
- }
+ { return _M_f.parse(__pc); }
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
- {
- auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
- char __buf[2 + sizeof(__v) * 2];
- auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
- __u, 16);
- int __n = __ptr - __buf;
- __buf[0] = '0';
- __buf[1] = 'x';
-#if __glibcxx_format >= 202304L
- if (_M_spec._M_type == __format::_Pres_P)
- {
- __buf[1] = 'X';
- for (auto __p = __buf + 2; __p != __ptr; ++__p)
-#if __has_builtin(__builtin_toupper)
- *__p = __builtin_toupper(*__p);
-#else
- *__p = std::toupper(*__p);
-#endif
- }
-#endif
-
- basic_string_view<_CharT> __str;
- if constexpr (is_same_v<_CharT, char>)
- __str = string_view(__buf, __n);
-#ifdef _GLIBCXX_USE_WCHAR_T
- else
- {
- auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
- std::__to_wstring_numeric(__buf, __n, __p);
- __str = wstring_view(__p, __n);
- }
-#endif
-
-#if __glibcxx_format >= 202304L
- if (_M_spec._M_zero_fill)
- {
- size_t __width = _M_spec._M_get_width(__fc);
- if (__width <= __str.size())
- return __format::__write(__fc.out(), __str);
-
- auto __out = __fc.out();
- // Write "0x" or "0X" prefix before zero-filling.
- __out = __format::__write(std::move(__out), __str.substr(0, 2));
- __str.remove_prefix(2);
- size_t __nfill = __width - __n;
- return __format::__write_padded(std::move(__out), __str,
- __format::_Align_right,
- __nfill, _CharT('0'));
- }
-#endif
-
- return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
- __format::_Align_right);
- }
+ { return _M_f.format(__v, __fc); }
private:
- __format::_Spec<_CharT> _M_spec{};
+ __format::__formatter_ptr<_CharT> _M_f;
};
template<__format::__char _CharT>
@@ -2908,7 +3030,7 @@ namespace __format
{ return _M_f.format(__v, __fc); }
private:
- formatter<const void*, _CharT> _M_f;
+ __format::__formatter_ptr<_CharT> _M_f;
};
template<__format::__char _CharT>
@@ -2927,11 +3049,11 @@ namespace __format
{ return _M_f.format(nullptr, __fc); }
private:
- formatter<const void*, _CharT> _M_f;
+ __format::__formatter_ptr<_CharT> _M_f;
};
/// @}
-#if defined _GLIBCXX_USE_WCHAR_T && __cpp_lib_format_ranges
+#if defined _GLIBCXX_USE_WCHAR_T && __glibcxx_format_ranges
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3944. Formatters converting sequences of char to sequences of wchar_t
@@ -2955,70 +3077,6 @@ namespace __format
: private formatter<__format::__disabled, wchar_t> { };
#endif
-/// @cond undocumented
-namespace __format
-{
- template<typename _Tp, typename _Context,
- typename _Formatter
- = typename _Context::template formatter_type<remove_const_t<_Tp>>,
- typename _ParseContext
- = basic_format_parse_context<typename _Context::char_type>>
- concept __parsable_with
- = semiregular<_Formatter>
- && requires (_Formatter __f, _ParseContext __pc)
- {
- { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>;
- };
-
- template<typename _Tp, typename _Context,
- typename _Formatter
- = typename _Context::template formatter_type<remove_const_t<_Tp>>,
- typename _ParseContext
- = basic_format_parse_context<typename _Context::char_type>>
- concept __formattable_with
- = semiregular<_Formatter>
- && requires (const _Formatter __cf, _Tp&& __t, _Context __fc)
- {
- { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
- };
-
- // An unspecified output iterator type used in the `formattable` concept.
- template<typename _CharT>
- using _Iter_for = back_insert_iterator<basic_string<_CharT>>;
-
- template<typename _Tp, typename _CharT,
- typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>>
- concept __formattable_impl
- = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>;
-
-} // namespace __format
-/// @endcond
-
-// Concept std::formattable was introduced by P2286R8 "Formatting Ranges",
-// but we can't guard it with __cpp_lib_format_ranges until we define that!
-#if __cplusplus > 202002L
- // [format.formattable], concept formattable
- template<typename _Tp, typename _CharT>
- concept formattable
- = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>;
-#endif
-
-#if __cpp_lib_format_ranges
- /// @cond undocumented
-namespace __format
-{
- template<typename _Rg, typename _CharT>
- concept __const_formattable_range
- = ranges::input_range<const _Rg>
- && formattable<ranges::range_reference_t<const _Rg>, _CharT>;
-
- template<typename _Rg, typename _CharT>
- using __maybe_const_range
- = conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>;
-} // namespace __format
- /// @endcond
-#endif // format_ranges
-
/// An iterator after the last character written, and the number of
/// characters that would have been written.
template<typename _Out>
@@ -3246,7 +3304,7 @@ namespace __format
class _Buf_sink : public _Sink<_CharT>
{
protected:
- _CharT _M_buf[32 * sizeof(void*) / sizeof(_CharT)];
+ _CharT _M_buf[__stackbuf_size<_CharT>];
[[__gnu__::__always_inline__]]
constexpr
@@ -3260,12 +3318,12 @@ namespace __format
// A sink that fills a sequence (e.g. std::string, std::vector, std::deque).
// Writes to a buffer then appends that to the sequence when it fills up.
template<typename _Seq>
- class _Seq_sink final : public _Buf_sink<typename _Seq::value_type>
+ class _Seq_sink : public _Buf_sink<typename _Seq::value_type>
{
using _CharT = typename _Seq::value_type;
_Seq _M_seq;
-
+ protected:
// Transfer buffer contents to the sequence, so buffer can be refilled.
void
_M_overflow() override
@@ -3337,6 +3395,17 @@ namespace __format
}
}
+ void _M_trim(span<const _CharT> __s)
+ requires __is_specialization_of<_Seq, basic_string>
+ {
+ _GLIBCXX_DEBUG_ASSERT(__s.data() == this->_M_buf
+ || __s.data() == _M_seq.data());
+ if (__s.data() == _M_seq.data())
+ _M_seq.resize(__s.size());
+ else
+ this->_M_reset(this->_M_buf, __s.size());
+ }
+
public:
// TODO: for SSO string, use SSO buffer as initial span, then switch
// to _M_buf if it overflows? Or even do that for all unused capacity?
@@ -3362,7 +3431,7 @@ namespace __format
// A writable span that views everything written to the sink.
// Will be either a view over _M_seq or the used part of _M_buf.
span<_CharT>
- view()
+ _M_span()
{
auto __s = this->_M_used();
if (_M_seq.size())
@@ -3373,9 +3442,21 @@ namespace __format
}
return __s;
}
+
+ basic_string_view<_CharT>
+ view()
+ {
+ auto __span = _M_span();
+ return basic_string_view<_CharT>(__span.data(), __span.size());
+ }
};
- // A sink that writes to an output iterator.
+ template<typename _CharT, typename _Alloc = allocator<_CharT>>
+ using _Str_sink
+ = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
+
+ // template<typename _CharT, typename _Alloc = allocator<_CharT>>
+ // using _Vec_sink = _Seq_sink<vector<_CharTthis-> sink that writes to an output iterator.
// Writes to a fixed-size buffer and then flushes to the output iterator
// when the buffer fills up.
template<typename _CharT, typename _OutIter>
@@ -3543,6 +3624,173 @@ namespace __format
}
};
+ // A sink for handling the padded outputs (_M_padwidth) or truncated
+ // (_M_maxwidth). The handling is done by writting to buffer (_Str_strink)
+ // until sufficient number of characters is written. After that if sequence
+ // is longer than _M_padwidth it's written to _M_out, and further writes are
+ // either:
+ // * buffered and forwarded to _M_out, if below _M_maxwidth,
+ // * ignored otherwise
+ // If field width of written sequence is no greater than _M_padwidth, the
+ // sequence is written during _M_finish call.
+ template<typename _Out, typename _CharT>
+ class _Padding_sink : public _Str_sink<_CharT>
+ {
+ const size_t _M_padwidth;
+ const size_t _M_maxwidth;
+ _Out _M_out;
+ size_t _M_printwidth;
+
+ [[__gnu__::__always_inline__]]
+ bool
+ _M_ignoring() const
+ {
+ return _M_printwidth >= _M_maxwidth;
+ }
+
+ [[__gnu__::__always_inline__]]
+ bool
+ _M_buffering() const
+ {
+ if (_M_printwidth < _M_padwidth)
+ return true;
+ if (_M_maxwidth != (size_t)-1)
+ return _M_printwidth < _M_maxwidth;
+ return false;
+ }
+
+ void
+ _M_flush()
+ {
+ span<_CharT> __new = this->_M_used();
+ basic_string_view<_CharT> __str(__new.data(), __new.size());
+ _M_out = __format::__write(std::move(_M_out), __str);
+ this->_M_rewind();
+ }
+
+ bool
+ _M_force_update()
+ {
+ auto __str = this->view();
+ // Compute actual field width, possibly truncated.
+ _M_printwidth = __format::__truncate(__str, _M_maxwidth);
+ if (_M_ignoring())
+ this->_M_trim(__str);
+ if (_M_buffering())
+ return true;
+
+ // We have more characters than padidng, no padding is needed,
+ // write direclty to _M_out.
+ if (_M_printwidth >= _M_padwidth)
+ _M_out = __format::__write(std::move(_M_out), __str);
+ // We reached _M_maxwidth that is smaller than _M_padwidth.
+ // Store the prefix sequence in _M_seq, and free _M_buf.
+ else
+ _Str_sink<_CharT>::_M_overflow();
+
+ // Use internal buffer for writes to _M_out.
+ this->_M_reset(this->_M_buf);
+ return false;
+ }
+
+ bool
+ _M_update(size_t __new)
+ {
+ _M_printwidth += __new;
+ if (_M_buffering())
+ return true;
+ return _M_force_update();
+ }
+
+ void
+ _M_overflow() override
+ {
+ // Ignore characters in buffer, and override it.
+ if (_M_ignoring())
+ this->_M_rewind();
+ // Write buffer to _M_out, and override it.
+ else if (!_M_buffering())
+ _M_flush();
+ // Update written count, and if input still should be buffered,
+ // flush the to _M_seq.
+ else if (_M_update(this->_M_used().size()))
+ _Str_sink<_CharT>::_M_overflow();
+ }
+
+ typename _Sink<_CharT>::_Reservation
+ _M_reserve(size_t __n) override
+ {
+ // Ignore characters in buffer, if any.
+ if (_M_ignoring())
+ this->_M_rewind();
+ else if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
+ if (!_M_buffering())
+ {
+ // Write pending characters if any
+ if (!this->_M_used().empty())
+ _M_flush();
+ // Try to reserve from _M_out sink.
+ if (auto __reserved = _M_out._M_reserve(__n))
+ return __reserved;
+ }
+ return _Sink<_CharT>::_M_reserve(__n);
+ }
+
+ void
+ _M_bump(size_t __n) override
+ {
+ // Ignore the written characters.
+ if (_M_ignoring())
+ return;
+ // If reservation was made directy sink associated _M_out,
+ // _M_bump will be called on that sink.
+ _Sink<_CharT>::_M_bump(__n);
+ if (_M_buffering())
+ _M_update(__n);
+ }
+
+ public:
+ [[__gnu__::__always_inline__]]
+ explicit _Padding_sink(_Out __out, size_t __padwidth)
+ : _M_padwidth(__padwidth), _M_maxwidth(-1),
+ _M_out(std::move(__out)), _M_printwidth(0)
+ { }
+
+ [[__gnu__::__always_inline__]]
+ explicit _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth)
+ : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth),
+ _M_out(std::move(__out)), _M_printwidth(0)
+ { }
+
+ _Out
+ _M_finish(_Align __align, char32_t __fill_char)
+ {
+ // Handle any characters in the buffer.
+ if (auto __rem = this->_M_used().size())
+ {
+ if (_M_ignoring())
+ this->_M_rewind();
+ else if (!_M_buffering())
+ _M_flush();
+ else
+ _M_update(__rem);
+ }
+
+ if (!_M_buffering() || !_M_force_update())
+ // Characters were already written to _M_out.
+ if (_M_printwidth >= _M_padwidth)
+ return std::move(_M_out);
+
+ const auto __str = this->view();
+ if (_M_printwidth >= _M_padwidth)
+ return __format::__write(std::move(_M_out), __str);
+
+ const size_t __nfill = _M_padwidth - _M_printwidth;
+ return __format::__write_padded(std::move(_M_out), __str,
+ __align, __nfill, __fill_char);
+ }
+ };
+
enum _Arg_t : unsigned char {
_Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
_Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
@@ -5088,7 +5336,7 @@ namespace __format
}
#endif
-#if __cpp_lib_format_ranges
+#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
// [format.range], formatting of ranges
// [format.range.fmtkind], variable template format_kind
enum class range_format {
@@ -5102,7 +5350,10 @@ namespace __format
/// @cond undocumented
template<typename _Rg>
- constexpr auto format_kind = not defined(format_kind<_Rg>);
+ constexpr auto format_kind =
+ __primary_template_not_defined(
+ format_kind<_Rg> // you can specialize this for non-const input ranges
+ );
template<typename _Tp>
consteval range_format
@@ -5133,28 +5384,570 @@ namespace __format
template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>>
constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>();
- // [format.range.formatter], class template range_formatter
- template<typename _Tp, typename _CharT = char>
- requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
- class range_formatter; // TODO
-
/// @cond undocumented
namespace __format
{
- // [format.range.fmtdef], class template range-default-formatter
- template<range_format _Kind, ranges::input_range _Rg, typename _CharT>
- struct __range_default_formatter; // TODO
+ template<typename _CharT, typename _Out, typename _Callback>
+ typename basic_format_context<_Out, _CharT>::iterator
+ __format_padded(basic_format_context<_Out, _CharT>& __fc,
+ const _Spec<_CharT>& __spec,
+ _Callback&& __call)
+ {
+ // This is required to implement formatting with padding,
+ // as we need to format to temporary buffer, using the same iterator.
+ static_assert(is_same_v<_Out, __format::_Sink_iter<_CharT>>);
+
+ const size_t __padwidth = __spec._M_get_width(__fc);
+ if (__padwidth == 0)
+ return __call(__fc);
+
+ struct _Restore_out
+ {
+ _Restore_out(basic_format_context<_Sink_iter<_CharT>, _CharT>& __fc)
+ : _M_ctx(std::addressof(__fc)), _M_out(__fc.out())
+ { }
+
+ void
+ _M_disarm()
+ { _M_ctx = nullptr; }
+
+ ~_Restore_out()
+ {
+ if (_M_ctx)
+ _M_ctx->advance_to(_M_out);
+ }
+
+ private:
+ basic_format_context<_Sink_iter<_CharT>, _CharT>* _M_ctx;
+ _Sink_iter<_CharT> _M_out;
+ };
+
+ _Restore_out __restore(__fc);
+ _Padding_sink<_Sink_iter<_CharT>, _CharT> __sink(__fc.out(), __padwidth);
+ __fc.advance_to(__sink.out());
+ __call(__fc);
+ __fc.advance_to(__sink._M_finish(__spec._M_align, __spec._M_fill));
+ __restore._M_disarm();
+ return __fc.out();
+ }
+
+ template<size_t _Pos, typename _Tp, typename _CharT>
+ struct __indexed_formatter_storage
+ {
+ constexpr void
+ _M_parse()
+ {
+ basic_format_parse_context<_CharT> __pc({});
+ if (_M_formatter.parse(__pc) != __pc.end())
+ __format::__failed_to_parse_format_spec();
+ }
+
+ template<typename _Out>
+ void
+ _M_format(__maybe_const<_Tp, _CharT>& __elem,
+ basic_format_context<_Out, _CharT>& __fc,
+ basic_string_view<_CharT> __sep) const
+ {
+ if constexpr (_Pos != 0)
+ __fc.advance_to(__format::__write(__fc.out(), __sep));
+ __fc.advance_to(_M_formatter.format(__elem, __fc));
+ }
+
+ [[__gnu__::__always_inline__]]
+ constexpr void
+ set_debug_format()
+ {
+ if constexpr (__has_debug_format<formatter<_Tp, _CharT>>)
+ _M_formatter.set_debug_format();
+ }
+
+ private:
+ formatter<_Tp, _CharT> _M_formatter;
+ };
+
+ template<typename _CharT, typename... _Tps>
+ class __tuple_formatter
+ {
+ using _String_view = basic_string_view<_CharT>;
+ using _Seps = __format::_Separators<_CharT>;
+
+ public:
+ constexpr void
+ set_separator(basic_string_view<_CharT> __sep) noexcept
+ { _M_sep = __sep; }
+
+ constexpr void
+ set_brackets(basic_string_view<_CharT> __open,
+ basic_string_view<_CharT> __close) noexcept
+ {
+ _M_open = __open;
+ _M_close = __close;
+ }
+
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained ParseContext type, which seems unimplementable.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ {
+ auto __first = __pc.begin();
+ const auto __last = __pc.end();
+ __format::_Spec<_CharT> __spec{};
+
+ auto __finished = [&]
+ {
+ if (__first != __last && *__first != '}')
+ return false;
+
+ _M_spec = __spec;
+ _M_felems._M_parse();
+ _M_felems.set_debug_format();
+ return true;
+ };
+
+ if (__finished())
+ return __first;
+
+ __first = __spec._M_parse_fill_and_align(__first, __last, "{:");
+ if (__finished())
+ return __first;
+
+ __first = __spec._M_parse_width(__first, __last, __pc);
+ if (__finished())
+ return __first;
+
+ if (*__first == 'n')
+ {
+ ++__first;
+ _M_open = _M_close = _String_view();
+ }
+ else if (*__first == 'm')
+ {
+ ++__first;
+ if constexpr (sizeof...(_Tps) == 2)
+ {
+ _M_sep = _Seps::_S_colon();
+ _M_open = _M_close = _String_view();
+ }
+ else
+ __throw_format_error("format error: 'm' specifier requires range"
+ " of pair or tuple of two elements");
+ }
+
+ if (__finished())
+ return __first;
+
+ __format::__failed_to_parse_format_spec();
+ }
+
+ protected:
+ template<typename _Tuple, typename _Out, size_t... _Ids>
+ typename basic_format_context<_Out, _CharT>::iterator
+ _M_format(_Tuple& __tuple, index_sequence<_Ids...>,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_format_elems(std::get<_Ids>(__tuple)..., __fc); }
+
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ _M_format_elems(__maybe_const<_Tps, _CharT>&... __elems,
+ basic_format_context<_Out, _CharT>& __fc) const
+ {
+ return __format::__format_padded(
+ __fc, _M_spec,
+ [this, &__elems...](basic_format_context<_Out, _CharT>& __nfc)
+ {
+ __nfc.advance_to(__format::__write(__nfc.out(), _M_open));
+ _M_felems._M_format(__elems..., __nfc, _M_sep);
+ return __format::__write(__nfc.out(), _M_close);
+ });
+ }
+
+ private:
+ template<size_t... _Ids>
+ struct __formatters_storage
+ : __indexed_formatter_storage<_Ids, _Tps, _CharT>...
+ {
+ template<size_t _Id, typename _Up>
+ using _Base = __indexed_formatter_storage<_Id, _Up, _CharT>;
+
+ constexpr void
+ _M_parse()
+ {
+ (_Base<_Ids, _Tps>::_M_parse(), ...);
+ }
+
+ template<typename _Out>
+ void
+ _M_format(__maybe_const<_Tps, _CharT>&... __elems,
+ basic_format_context<_Out, _CharT>& __fc,
+ _String_view __sep) const
+ {
+ (_Base<_Ids, _Tps>::_M_format(__elems, __fc, __sep), ...);
+ }
+
+ constexpr void
+ set_debug_format()
+ {
+ (_Base<_Ids, _Tps>::set_debug_format(), ...);
+ }
+ };
+
+ template<size_t... _Ids>
+ static auto
+ _S_create_storage(index_sequence<_Ids...>)
+ -> __formatters_storage<_Ids...>;
+ using _Formatters
+ = decltype(_S_create_storage(index_sequence_for<_Tps...>()));
+
+ _Spec<_CharT> _M_spec{};
+ _String_view _M_open = _Seps::_S_parens().substr(0, 1);
+ _String_view _M_close = _Seps::_S_parens().substr(1, 1);
+ _String_view _M_sep = _Seps::_S_comma();
+ _Formatters _M_felems;
+ };
+
+ template<typename _Tp>
+ concept __is_map_formattable
+ = __is_pair<_Tp> || (__is_tuple_v<_Tp> && tuple_size_v<_Tp> == 2);
+
} // namespace __format
/// @endcond
+ // [format.tuple] Tuple formatter
+ template<__format::__char _CharT, formattable<_CharT> _Fp,
+ formattable<_CharT> _Sp>
+ struct formatter<pair<_Fp, _Sp>, _CharT>
+ : __format::__tuple_formatter<_CharT, remove_cvref_t<_Fp>,
+ remove_cvref_t<_Sp>>
+ {
+ private:
+ using __maybe_const_pair
+ = __conditional_t<formattable<const _Fp, _CharT>
+ && formattable<const _Sp, _CharT>,
+ const pair<_Fp, _Sp>, pair<_Fp, _Sp>>;
+ public:
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained FormatContext type, which seems unimplementable.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_pair& __p,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return this->_M_format_elems(__p.first, __p.second, __fc); }
+ };
+
+ template<__format::__char _CharT, formattable<_CharT>... _Tps>
+ struct formatter<tuple<_Tps...>, _CharT>
+ : __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...>
+ {
+ private:
+ using __maybe_const_tuple
+ = __conditional_t<(formattable<const _Tps, _CharT> && ...),
+ const tuple<_Tps...>, tuple<_Tps...>>;
+ public:
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained FormatContext type, which seems unimplementable.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_tuple& __t,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return this->_M_format(__t, index_sequence_for<_Tps...>(), __fc); }
+ };
+
+ // [format.range.formatter], class template range_formatter
+ template<typename _Tp, __format::__char _CharT>
+ requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
+ class range_formatter
+ {
+ using _String_view = basic_string_view<_CharT>;
+ using _Seps = __format::_Separators<_CharT>;
+
+ public:
+ constexpr void
+ set_separator(basic_string_view<_CharT> __sep) noexcept
+ { _M_sep = __sep; }
+
+ constexpr void
+ set_brackets(basic_string_view<_CharT> __open,
+ basic_string_view<_CharT> __close) noexcept
+ {
+ _M_open = __open;
+ _M_close = __close;
+ }
+
+ constexpr formatter<_Tp, _CharT>&
+ underlying() noexcept
+ { return _M_fval; }
+
+ constexpr const formatter<_Tp, _CharT>&
+ underlying() const noexcept
+ { return _M_fval; }
+
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained ParseContext type, which seems unimplementable.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ {
+ auto __first = __pc.begin();
+ const auto __last = __pc.end();
+ __format::_Spec<_CharT> __spec{};
+ bool __no_brace = false;
+
+ auto __finished = [&]
+ { return __first == __last || *__first == '}'; };
+
+ auto __finalize = [&]
+ {
+ _M_spec = __spec;
+ return __first;
+ };
+
+ auto __parse_val = [&](_String_view __nfs = _String_view())
+ {
+ basic_format_parse_context<_CharT> __npc(__nfs);
+ if (_M_fval.parse(__npc) != __npc.end())
+ __format::__failed_to_parse_format_spec();
+ if constexpr (__format::__has_debug_format<formatter<_Tp, _CharT>>)
+ _M_fval.set_debug_format();
+ return __finalize();
+ };
+
+ if (__finished())
+ return __parse_val();
+
+ __first = __spec._M_parse_fill_and_align(__first, __last, "{:");
+ if (__finished())
+ return __parse_val();
+
+ __first = __spec._M_parse_width(__first, __last, __pc);
+ if (__finished())
+ return __parse_val();
+
+ if (*__first == '?')
+ {
+ ++__first;
+ __spec._M_type = __format::_Pres_esc;
+ if (__finished() || *__first != 's')
+ __throw_format_error("format error: '?' is allowed only in"
+ " combination with 's'");
+ }
+
+ if (*__first == 's')
+ {
+ ++__first;
+ if constexpr (same_as<_Tp, _CharT>)
+ {
+ if (__spec._M_type != __format::_Pres_esc)
+ __spec._M_type = __format::_Pres_str;
+ if (__finished())
+ return __finalize();
+ __throw_format_error("format error: element format specifier"
+ " cannot be provided when 's' specifier is used");
+ }
+ else
+ __throw_format_error("format error: 's' specifier requires"
+ " range of character types");
+ }
+
+ if (__finished())
+ return __parse_val();
+
+ if (*__first == 'n')
+ {
+ ++__first;
+ _M_open = _M_close = _String_view();
+ __no_brace = true;
+ }
+
+ if (__finished())
+ return __parse_val();
+
+ if (*__first == 'm')
+ {
+ _String_view __m(__first, 1);
+ ++__first;
+ if constexpr (__format::__is_map_formattable<_Tp>)
+ {
+ _M_sep = _Seps::_S_comma();
+ if (!__no_brace)
+ {
+ _M_open = _Seps::_S_braces().substr(0, 1);
+ _M_close = _Seps::_S_braces().substr(1, 1);
+ }
+ if (__finished())
+ return __parse_val(__m);
+ __throw_format_error("format error: element format specifier"
+ " cannot be provided when 'm' specifier is used");
+ }
+ else
+ __throw_format_error("format error: 'm' specifier requires"
+ " range of pairs or tuples of two elements");
+ }
+
+ if (__finished())
+ return __parse_val();
+
+ if (*__first == ':')
+ {
+ __pc.advance_to(++__first);
+ __first = _M_fval.parse(__pc);
+ }
+
+ if (__finished())
+ return __finalize();
+
+ __format::__failed_to_parse_format_spec();
+ }
+
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained FormatContext type, which seems unimplementable.
+ template<ranges::input_range _Rg, typename _Out>
+ requires formattable<ranges::range_reference_t<_Rg>, _CharT> &&
+ same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, _Tp>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(_Rg&& __rg, basic_format_context<_Out, _CharT>& __fc) const
+ {
+ using _Range = remove_reference_t<_Rg>;
+ if constexpr (__format::__simply_formattable_range<_Range, _CharT>)
+ return _M_format<const _Range>(__rg, __fc);
+ else
+ return _M_format(__rg, __fc);
+ }
+
+ private:
+ template<ranges::input_range _Rg, typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ _M_format(_Rg& __rg, basic_format_context<_Out, _CharT>& __fc) const
+ {
+ if constexpr (same_as<_Tp, _CharT>)
+ if (_M_spec._M_type == __format::_Pres_str
+ || _M_spec._M_type == __format::_Pres_esc)
+ {
+ __format::__formatter_str __fstr(_M_spec);
+ return __fstr._M_format_range(__rg, __fc);
+ }
+ return __format::__format_padded(
+ __fc, _M_spec,
+ [this, &__rg](basic_format_context<_Out, _CharT>& __nfc)
+ { return _M_format_elems(__rg, __nfc); });
+ }
+
+
+ template<ranges::input_range _Rg, typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ _M_format_elems(_Rg& __rg,
+ basic_format_context<_Out, _CharT>& __fc) const
+ {
+ auto __out = __format::__write(__fc.out(), _M_open);
+
+ auto __first = ranges::begin(__rg);
+ auto const __last = ranges::end(__rg);
+ if (__first == __last)
+ return __format::__write(__out, _M_close);
+
+ __fc.advance_to(__out);
+ __out = _M_fval.format(*__first, __fc);
+ for (++__first; __first != __last; ++__first)
+ {
+ __out = __format::__write(__out, _M_sep);
+ __fc.advance_to(__out);
+ __out = _M_fval.format(*__first, __fc);
+ }
+
+ return __format::__write(__out, _M_close);
+ }
+
+ __format::_Spec<_CharT> _M_spec{};
+ _String_view _M_open = _Seps::_S_squares().substr(0, 1);
+ _String_view _M_close = _Seps::_S_squares().substr(1, 1);
+ _String_view _M_sep = _Seps::_S_comma();
+ formatter<_Tp, _CharT> _M_fval;
+ };
+
+ // In standard this is shown as inheriting from specialization of
+ // exposition only specialization for range-default-formatter for
+ // each range_format. We opt for simpler implementation.
// [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr],
// specializations for maps, sets, and strings
- template<ranges::input_range _Rg, typename _CharT>
+ template<ranges::input_range _Rg, __format::__char _CharT>
requires (format_kind<_Rg> != range_format::disabled)
&& formattable<ranges::range_reference_t<_Rg>, _CharT>
struct formatter<_Rg, _CharT>
- : __format::__range_default_formatter<format_kind<_Rg>, _Rg, _CharT>
- { };
+ {
+ private:
+ static const bool _S_range_format_is_string =
+ (format_kind<_Rg> == range_format::string)
+ || (format_kind<_Rg> == range_format::debug_string);
+ using _Vt = remove_cvref_t<
+ ranges::range_reference_t<
+ __format::__maybe_const_range<_Rg, _CharT>>>;
+
+ static consteval bool _S_is_correct()
+ {
+ if constexpr (_S_range_format_is_string)
+ static_assert(same_as<_Vt, _CharT>);
+ return true;
+ }
+
+ static_assert(_S_is_correct());
+
+ public:
+ constexpr formatter() noexcept
+ {
+ using _Seps = __format::_Separators<_CharT>;
+ if constexpr (format_kind<_Rg> == range_format::map)
+ {
+ static_assert(__format::__is_map_formattable<_Vt>);
+ _M_under.set_brackets(_Seps::_S_braces().substr(0, 1),
+ _Seps::_S_braces().substr(1, 1));
+ _M_under.underlying().set_brackets({}, {});
+ _M_under.underlying().set_separator(_Seps::_S_colon());
+ }
+ else if constexpr (format_kind<_Rg> == range_format::set)
+ _M_under.set_brackets(_Seps::_S_braces().substr(0, 1),
+ _Seps::_S_braces().substr(1, 1));
+ }
+
+ constexpr void
+ set_separator(basic_string_view<_CharT> __sep) noexcept
+ requires (!_S_range_format_is_string)
+ { _M_under.set_separator(__sep); }
+
+ constexpr void
+ set_brackets(basic_string_view<_CharT> __open,
+ basic_string_view<_CharT> __close) noexcept
+ requires (!_S_range_format_is_string)
+ { _M_under.set_brackets(__open, __close); }
+
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained ParseContext type, which seems unimplementable.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ {
+ auto __res = _M_under.parse(__pc);
+ if constexpr (format_kind<_Rg> == range_format::debug_string)
+ _M_under.set_debug_format();
+ return __res;
+ }
+
+ // We deviate from standard, that declares this as template accepting
+ // unconstrained FormatContext type, which seems unimplementable.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__format::__maybe_const_range<_Rg, _CharT>& __rg,
+ basic_format_context<_Out, _CharT>& __fc) const
+ {
+ if constexpr (_S_range_format_is_string)
+ return _M_under._M_format_range(__rg, __fc);
+ else
+ return _M_under.format(__rg, __fc);
+ }
+
+ private:
+ using _Formatter_under
+ = __conditional_t<_S_range_format_is_string,
+ __format::__formatter_str<_CharT>,
+ range_formatter<_Vt, _CharT>>;
+ _Formatter_under _M_under;
+ };
#endif // C++23 formatting ranges
#undef _GLIBCXX_WIDEN
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index b7ab233..0806900 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -1486,12 +1486,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)> final
: __future_base::_Task_state_base<_Res(_Args...)>
{
+#ifdef __cpp_lib_is_invocable // C++ >= 17
+ static_assert(is_invocable_r_v<_Res, _Fn&, _Args...>);
+#else
+ static_assert(__is_invocable<_Fn&, _Args...>::value,
+ "_Fn& is invocable with _Args...");
+#endif
+
template<typename _Fn2>
_Task_state(_Fn2&& __fn, const _Alloc& __a)
: _Task_state_base<_Res(_Args...)>(__a),
_M_impl(std::forward<_Fn2>(__fn), __a)
{ }
+ template<typename _Fn2>
+ static shared_ptr<_Task_state_base<_Res(_Args...)>>
+ _S_create(_Fn2&& __fn, const _Alloc& __a)
+ {
+ return std::allocate_shared<_Task_state>(__a,
+ std::forward<_Fn2>(__fn),
+ __a);
+ }
+
private:
virtual void
_M_run(_Args&&... __args)
@@ -1515,7 +1531,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
virtual shared_ptr<_Task_state_base<_Res(_Args...)>>
- _M_reset();
+ _M_reset()
+ { return _S_create(std::move(_M_impl._M_fn), _M_impl); }
struct _Impl : _Alloc
{
@@ -1525,38 +1542,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Fn _M_fn;
} _M_impl;
};
-
- template<typename _Signature, typename _Fn,
- typename _Alloc = std::allocator<int>>
- shared_ptr<__future_base::_Task_state_base<_Signature>>
- __create_task_state(_Fn&& __fn, const _Alloc& __a = _Alloc())
- {
- typedef typename decay<_Fn>::type _Fn2;
- typedef __future_base::_Task_state<_Fn2, _Alloc, _Signature> _State;
- return std::allocate_shared<_State>(__a, std::forward<_Fn>(__fn), __a);
- }
-
- template<typename _Fn, typename _Alloc, typename _Res, typename... _Args>
- shared_ptr<__future_base::_Task_state_base<_Res(_Args...)>>
- __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)>::_M_reset()
- {
- return __create_task_state<_Res(_Args...)>(std::move(_M_impl._M_fn),
- static_cast<_Alloc&>(_M_impl));
- }
/// @endcond
/// packaged_task
template<typename _Res, typename... _ArgTypes>
class packaged_task<_Res(_ArgTypes...)>
{
- typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type;
+ using _State_type = __future_base::_Task_state_base<_Res(_ArgTypes...)>;
shared_ptr<_State_type> _M_state;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3039. Unnecessary decay in thread and packaged_task
template<typename _Fn, typename _Fn2 = __remove_cvref_t<_Fn>>
- using __not_same
- = typename enable_if<!is_same<packaged_task, _Fn2>::value>::type;
+ using __not_same = __enable_if_t<!is_same<packaged_task, _Fn2>::value>;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4154. The Mandates for std::packaged_task's constructor
+ // from a callable entity should consider decaying.
+ template<typename _Fn, typename _Alloc = std::allocator<int>>
+ using _Task_state
+ = __future_base::_Task_state<__decay_t<_Fn>, _Alloc,
+ _Res(_ArgTypes...)>;
public:
// Construction and destruction
@@ -1565,16 +1571,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Fn, typename = __not_same<_Fn>>
explicit
packaged_task(_Fn&& __fn)
- : _M_state(
- __create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn)))
- {
-#ifdef __cpp_lib_is_invocable // C++ >= 17
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 4154. The Mandates for std::packaged_task's constructor
- // from a callable entity should consider decaying
- static_assert(is_invocable_r_v<_Res, decay_t<_Fn>&, _ArgTypes...>);
-#endif
- }
+ : _M_state(_Task_state<_Fn>::_S_create(std::forward<_Fn>(__fn), {}))
+ { }
#if __cplusplus < 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1583,8 +1581,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// 2921. packaged_task and type-erased allocators
template<typename _Fn, typename _Alloc, typename = __not_same<_Fn>>
packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn)
- : _M_state(__create_task_state<_Res(_ArgTypes...)>(
- std::forward<_Fn>(__fn), __a))
+ : _M_state(_Task_state<_Fn, _Alloc>::_S_create(std::forward<_Fn>(__fn),
+ __a))
{ }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
diff --git a/libstdc++-v3/include/std/generator b/libstdc++-v3/include/std/generator
index 3f781f1..7ab2c9e 100644
--- a/libstdc++-v3/include/std/generator
+++ b/libstdc++-v3/include/std/generator
@@ -153,6 +153,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept
{ return _Recursive_awaiter { std::move(__r.range) }; }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3899. co_yielding elements of an lvalue generator is
+ // unnecessarily inefficient
+ template<typename _R2, typename _V2, typename _A2, typename _U2>
+ requires std::same_as<_Yield2_t<_R2, _V2>, _Yielded>
+ auto
+ yield_value(ranges::elements_of<generator<_R2, _V2, _A2>&, _U2> __r)
+ noexcept
+ { return _Recursive_awaiter { std::move(__r.range) }; }
+
template<ranges::input_range _R, typename _Alloc>
requires convertible_to<ranges::range_reference_t<_R>, _Yielded>
auto
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch
index cf64854..dc147c2 100644
--- a/libstdc++-v3/include/std/latch
+++ b/libstdc++-v3/include/std/latch
@@ -62,7 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr explicit
latch(ptrdiff_t __expected) noexcept
- : _M_a(__expected)
+ : _M_counter(__expected)
{ __glibcxx_assert(__expected >= 0 && __expected <= max()); }
~latch() = default;
@@ -74,23 +74,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
count_down(ptrdiff_t __update = 1)
{
__glibcxx_assert(__update >= 0 && __update <= max());
- auto const __old = __atomic_impl::fetch_sub(&_M_a, __update,
+ auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update,
memory_order::release);
if (std::cmp_equal(__old, __update))
- __atomic_impl::notify_all(&_M_a);
+ __atomic_impl::notify_all(&_M_counter);
else
__glibcxx_assert(std::cmp_less(__update, __old));
}
_GLIBCXX_ALWAYS_INLINE bool
try_wait() const noexcept
- { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; }
+ { return __atomic_impl::load(&_M_counter, memory_order::acquire) == 0; }
_GLIBCXX_ALWAYS_INLINE void
wait() const noexcept
{
auto const __pred = [this] { return this->try_wait(); };
- std::__atomic_wait_address(&_M_a, __pred);
+ std::__atomic_wait_address(&_M_counter, __pred);
}
_GLIBCXX_ALWAYS_INLINE void
@@ -102,7 +102,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
alignas(__detail::__platform_wait_alignment)
- __detail::__platform_wait_t _M_a;
+ __detail::__platform_wait_t _M_counter;
};
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index 4d36fcd..490963e 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -732,12 +732,11 @@ namespace __detail
/// @} group numeric_ops
#endif // C++17
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
namespace ranges
{
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
template<typename _Out, typename _Tp>
- using iota_result = out_value_result<_Out, _Tp>;
+ using iota_result = out_value_result<_Out, _Tp>;
struct __iota_fn
{
@@ -762,9 +761,8 @@ namespace ranges
};
inline constexpr __iota_fn iota{};
-
-#endif // __glibcxx_ranges_iota
} // namespace ranges
+#endif // __glibcxx_ranges_iota
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue
index 74b6c07..9052589 100644
--- a/libstdc++-v3/include/std/queue
+++ b/libstdc++-v3/include/std/queue
@@ -61,14 +61,88 @@
#include <bits/requires_hosted.h> // containers
+#define __glibcxx_want_adaptor_iterator_pair_constructor
+#define __glibcxx_want_containers_ranges
+#include <bits/version.h>
+
#include <deque>
#include <vector>
#include <bits/stl_heap.h>
#include <bits/stl_function.h>
#include <bits/stl_queue.h>
-#define __glibcxx_want_adaptor_iterator_pair_constructor
-#define __glibcxx_want_containers_ranges
-#include <bits/version.h>
+#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED
+#include <bits/formatfwd.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ // Standard does not constrain accepted _CharT, we do so we can
+ // befriend specializations.
+ template<__format::__char _CharT, typename _Tp,
+ formattable<_CharT> _Container>
+ struct formatter<queue<_Tp, _Container>, _CharT>
+ {
+ private:
+ using __maybe_const_adaptor
+ = __conditional_t<
+ __format::__const_formattable_range<_Container, _CharT>,
+ const queue<_Tp, _Container>, queue<_Tp, _Container>>;
+
+ public:
+ // Standard declares this as template accepting unconstrained
+ // ParseContext type.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ // Standard declares this as template accepting unconstrained
+ // FormatContext type.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_adaptor& __a,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format(__a.c, __fc); }
+
+ private:
+ // Standard uses formatter<ref_view<_Container>, _CharT>.
+ range_formatter<_Tp, _CharT> _M_f;
+ };
+
+ template<__format::__char _CharT, typename _Tp,
+ formattable<_CharT> _Container, typename _Compare>
+ struct formatter<priority_queue<_Tp, _Container, _Compare>, _CharT>
+ {
+ private:
+ using __maybe_const_adaptor
+ = __conditional_t<
+ __format::__const_formattable_range<_Container, _CharT>,
+ const priority_queue<_Tp, _Container, _Compare>,
+ priority_queue<_Tp, _Container, _Compare>>;
+
+ public:
+ // Standard declares this as template accepting unconstrained
+ // ParseContext type.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ // Standard declares this as template accepting unconstrained
+ // FormatContext type.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_adaptor& __a,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format(__a.c, __fc); }
+
+ private:
+ // Standard uses formatter<ref_view<_Container>, _CharT>.
+ range_formatter<_Tp, _CharT> _M_f;
+ };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __glibcxx_format_ranges
+
#endif /* _GLIBCXX_QUEUE */
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 7a339c5..9300c36 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -64,7 +64,6 @@
#define __glibcxx_want_ranges_chunk
#define __glibcxx_want_ranges_chunk_by
#define __glibcxx_want_ranges_enumerate
-#define __glibcxx_want_ranges_iota
#define __glibcxx_want_ranges_join_with
#define __glibcxx_want_ranges_repeat
#define __glibcxx_want_ranges_slide
diff --git a/libstdc++-v3/include/std/stack b/libstdc++-v3/include/std/stack
index 5cea476..a57a5a0 100644
--- a/libstdc++-v3/include/std/stack
+++ b/libstdc++-v3/include/std/stack
@@ -61,11 +61,53 @@
#include <bits/requires_hosted.h> // containers
-#include <deque>
-#include <bits/stl_stack.h>
-
#define __glibcxx_want_adaptor_iterator_pair_constructor
#define __glibcxx_want_containers_ranges
#include <bits/version.h>
+#include <deque>
+#include <bits/stl_stack.h>
+
+#ifdef __glibcxx_format_ranges // C++ >= 23 && HOSTED
+#include <bits/formatfwd.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ // Standard does not constrain accepted _CharT, we do so we can
+ // befriend specializations.
+ template<__format::__char _CharT, typename _Tp,
+ formattable<_CharT> _Container>
+ struct formatter<stack<_Tp, _Container>, _CharT>
+ {
+ private:
+ using __maybe_const_adaptor
+ = __conditional_t<
+ __format::__const_formattable_range<_Container, _CharT>,
+ const stack<_Tp, _Container>, stack<_Tp, _Container>>;
+
+ public:
+ // Standard declares this as template accepting unconstrained
+ // ParseContext type.
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ // Standard declares this as template accepting unconstrained
+ // FormatContext type.
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__maybe_const_adaptor& __a,
+ basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format(__a.c, __fc); }
+
+ private:
+ // Standard uses formatter<ref_view<_Container>, _CharT>.
+ range_formatter<_Tp, _CharT> _M_f;
+ };
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __glibcxx_format_ranges
+
+
#endif /* _GLIBCXX_STACK */
diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread
index d2f91ad..0de08c0 100644
--- a/libstdc++-v3/include/std/thread
+++ b/libstdc++-v3/include/std/thread
@@ -297,7 +297,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif // __cpp_lib_jthread
#ifdef __cpp_lib_formatters // C++ >= 23
- template<typename _CharT>
+ // We deviate from the standard, that does not put requirements
+ // on _CharT here.
+ template<__format::__char _CharT>
requires is_pointer_v<thread::native_handle_type>
|| is_integral_v<thread::native_handle_type>
class formatter<thread::id, _CharT>
@@ -307,6 +309,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
parse(basic_format_parse_context<_CharT>& __pc)
{
__format::_Spec<_CharT> __spec{};
+ __spec._M_align = __format::_Align_right;
const auto __last = __pc.end();
auto __first = __pc.begin();
@@ -334,36 +337,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__finished())
return __first;
- __throw_format_error("format error: invalid format-spec for "
- "std::thread::id");
+ std::__throw_format_error("format error: invalid format-spec for "
+ "std::thread::id");
}
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(thread::id __id, basic_format_context<_Out, _CharT>& __fc) const
{
- basic_string_view<_CharT> __sv;
- if constexpr (is_same_v<_CharT, char>)
- __sv = "{}thread::id of a non-executing thread";
- else
- __sv = L"{}thread::id of a non-executing thread";
- basic_string<_CharT> __str;
+
if (__id == thread::id())
- __sv.remove_prefix(2);
- else
{
- using _FmtStr = __format::_Runtime_format_string<_CharT>;
- // Convert non-void pointers to const void* for formatted output.
- using __output_type
- = __conditional_t<is_pointer_v<thread::native_handle_type>,
- const void*,
- thread::native_handle_type>;
- auto __o = static_cast<__output_type>(__id._M_thread);
- __sv = __str = std::format(_FmtStr(__sv.substr(0, 2)), __o);
+ const _CharT* __msg;
+ if constexpr (is_same_v<_CharT, char>)
+ __msg = "thread::id of a non-executing thread";
+ else
+ __msg = L"thread::id of a non-executing thread";
+
+ __format::__formatter_str<_CharT> __formatter(_M_spec);
+ return __formatter.format(__msg, __fc);
}
- return __format::__write_padded_as_spec(__sv, __sv.size(),
- __fc, _M_spec,
- __format::_Align_right);
+
+ using _HandleFormatter
+ = __conditional_t<is_pointer_v<thread::native_handle_type>,
+ __format::__formatter_ptr<_CharT>,
+ __format::__formatter_int<_CharT>>;
+
+ _HandleFormatter __formatter(_M_spec);
+ return __formatter.format(__id._M_thread, __fc);
}
private: