diff options
Diffstat (limited to 'contrib/llvm-project/libcxx/include/__format/formatter_tuple.h')
| -rw-r--r-- | contrib/llvm-project/libcxx/include/__format/formatter_tuple.h | 122 | 
1 files changed, 47 insertions, 75 deletions
diff --git a/contrib/llvm-project/libcxx/include/__format/formatter_tuple.h b/contrib/llvm-project/libcxx/include/__format/formatter_tuple.h index 82f5ada6e012..030097a8797d 100644 --- a/contrib/llvm-project/libcxx/include/__format/formatter_tuple.h +++ b/contrib/llvm-project/libcxx/include/__format/formatter_tuple.h @@ -11,18 +11,16 @@  #define _LIBCPP___FORMAT_FORMATTER_TUPLE_H  #include <__algorithm/ranges_copy.h> -#include <__availability>  #include <__chrono/statically_widen.h>  #include <__config> +#include <__format/buffer.h>  #include <__format/concepts.h> -#include <__format/format_args.h>  #include <__format/format_context.h>  #include <__format/format_error.h>  #include <__format/format_parse_context.h>  #include <__format/formatter.h>  #include <__format/formatter_output.h>  #include <__format/parser_std_format_spec.h> -#include <__iterator/back_insert_iterator.h>  #include <__type_traits/remove_cvref.h>  #include <__utility/integer_sequence.h>  #include <__utility/pair.h> @@ -35,49 +33,52 @@  _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER > 20 +#if _LIBCPP_STD_VER >= 23  template <__fmt_char_type _CharT, class _Tuple, formattable<_CharT>... _Args> -struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __formatter_tuple { -  _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) { +struct _LIBCPP_TEMPLATE_VIS __formatter_tuple { +  _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept {      __separator_ = __separator;    }    _LIBCPP_HIDE_FROM_ABI constexpr void -  set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) { +  set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept {      __opening_bracket_ = __opening_bracket;      __closing_bracket_ = __closing_bracket;    }    template <class _ParseContext> -  _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __parse_ctx) { -    const _CharT* __begin = __parser_.__parse(__parse_ctx, __format_spec::__fields_tuple); +  _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { +    auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple); -    // [format.tuple]/7 -    //   ... For each element e in underlying_, if e.set_debug_format() -    //   is a valid expression, calls e.set_debug_format(). -    // TODO FMT this can be removed when P2733 is accepted. -    std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> { -      std::__set_debug_format(std::get<_Index>(__underlying_)); -    }); - -    const _CharT* __end = __parse_ctx.end(); -    if (__begin == __end) -      return __begin; - -    if (*__begin == _CharT('m')) { +    auto __end = __ctx.end(); +    // Note 'n' is part of the type here +    if (__parser_.__clear_brackets_) +      set_brackets({}, {}); +    else if (__begin != __end && *__begin == _CharT('m')) {        if constexpr (sizeof...(_Args) == 2) {          set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));          set_brackets({}, {});          ++__begin;        } else -        std::__throw_format_error("The format specifier m requires a pair or a two-element tuple"); -    } else if (*__begin == _CharT('n')) { -      set_brackets({}, {}); -      ++__begin; +        std::__throw_format_error("Type m requires a pair or a tuple with two elements");      }      if (__begin != __end && *__begin != _CharT('}')) -      std::__throw_format_error("The format-spec should consume the input or end with a '}'"); +      std::__throw_format_error("The format specifier should consume the input or end with a '}'"); + +    __ctx.advance_to(__begin); + +    // [format.tuple]/7 +    //   ... For each element e in underlying_, if e.set_debug_format() +    //   is a valid expression, calls e.set_debug_format(). +    std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> { +      auto& __formatter = std::get<_Index>(__underlying_); +      __formatter.parse(__ctx); +      // Unlike the range_formatter we don't guard against evil parsers. Since +      // this format-spec never has a format-spec for the underlying type +      // adding the test would give additional overhead. +      std::__set_debug_format(__formatter); +    });      return __begin;    } @@ -91,26 +92,25 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __formatter_tuple {      if (!__specs.__has_width())        return __format_tuple(__tuple, __ctx); -    basic_string<_CharT> __str; - -    // Since the output is written to a different iterator a new context is -    // created. Since the underlying formatter uses the default formatting it -    // doesn't need a locale or the formatting arguments. So creating a new -    // context works. -    // -    // This solution works for this formatter, but it will not work for the -    // range_formatter. In that patch a generic solution is work in progress. -    // Once that is finished it can be used here. (The range_formatter will use -    // these features so it's easier to add it there and then port it.) -    // -    // TODO FMT Use formatting wrapping used in the range_formatter. -    basic_format_context __c = std::__format_context_create( -        back_insert_iterator{__str}, -        basic_format_args<basic_format_context<back_insert_iterator<basic_string<_CharT>>, _CharT>>{}); +    // The size of the buffer needed is: +    // - open bracket characters +    // - close bracket character +    // - n elements where every element may have a different size +    // - (n -1) separators +    // The size of the element is hard to predict, knowing the type helps but +    // it depends on the format-spec. As an initial estimate we guess 6 +    // characters. +    // Typically both brackets are 1 character and the separator is 2 +    // characters. Which means there will be +    //   (n - 1) * 2 + 1 + 1 = n * 2 character +    // So estimate 8 times the range size as buffer. +    __format::__retarget_buffer<_CharT> __buffer{8 * tuple_size_v<_Tuple>}; +    basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{ +        __buffer.__make_output_iterator(), __ctx};      __format_tuple(__tuple, __c); -    return __formatter::__write_string_no_precision(basic_string_view{__str}, __ctx.out(), __specs); +    return __formatter::__write_string_no_precision(basic_string_view{__buffer.__view()}, __ctx.out(), __specs);    }    template <class _FormatContext> @@ -120,35 +120,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __formatter_tuple {      std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> {        if constexpr (_Index)          __ctx.advance_to(std::ranges::copy(__separator_, __ctx.out()).out); - -        // During review Victor suggested to make the exposition only -        // __underlying_ member a local variable. Currently the Standard -        // requires nested debug-enabled formatter specializations not to -        // output escaped output. P2733 fixes that bug, once accepted the -        // code below can be used. -        // (Note when a paper allows parsing a tuple-underlying-spec the -        // exposition only member needs to be a class member. Earlier -        // revisions of P2286 proposed that, but this was not pursued, -        // due to time constrains and complexity of the matter.) -        // TODO FMT This can be updated after P2733 is accepted. -#  if 0 -      // P2286 uses an exposition only member in the formatter -      //   tuple<formatter<remove_cvref_t<_Args>, _CharT>...> __underlying_; -      // This was used in earlier versions of the paper since -      // __underlying_.parse(...) was called. This is no longer the case -      // so we can reduce the scope of the formatter. -      // -      // It does require the underlying's parse effect to be moved here too. -      using _Arg = tuple_element<_Index, decltype(__tuple)>; -      formatter<remove_cvref_t<_Args>, _CharT> __underlying; - -      // [format.tuple]/7 -      //   ... For each element e in underlying_, if e.set_debug_format() -      //   is a valid expression, calls e.set_debug_format(). -      std::__set_debug_format(__underlying); -#  else        __ctx.advance_to(std::get<_Index>(__underlying_).format(std::get<_Index>(__tuple), __ctx)); -#  endif      });      return std::ranges::copy(__closing_bracket_, __ctx.out()).out; @@ -164,14 +136,14 @@ private:  };  template <__fmt_char_type _CharT, formattable<_CharT>... _Args> -struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<pair<_Args...>, _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter<pair<_Args...>, _CharT>      : public __formatter_tuple<_CharT, pair<_Args...>, _Args...> {};  template <__fmt_char_type _CharT, formattable<_CharT>... _Args> -struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<tuple<_Args...>, _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter<tuple<_Args...>, _CharT>      : public __formatter_tuple<_CharT, tuple<_Args...>, _Args...> {}; -#endif //_LIBCPP_STD_VER > 20 +#endif //_LIBCPP_STD_VER >= 23  _LIBCPP_END_NAMESPACE_STD  | 
