[libcxx-commits] [libcxx] 00798e5 - [libc++][format] Granularizes the format header.
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Sep 20 09:57:20 PDT 2022
Author: Mark de Wever
Date: 2022-09-20T18:57:10+02:00
New Revision: 00798e50064447abd1483ff8e68a4dcaef7469d7
URL: https://github.com/llvm/llvm-project/commit/00798e50064447abd1483ff8e68a4dcaef7469d7
DIFF: https://github.com/llvm/llvm-project/commit/00798e50064447abd1483ff8e68a4dcaef7469d7.diff
LOG: [libc++][format] Granularizes the format header.
Moves the last pieces of code to its own header.
Reviewed By: ldionne, #libc
Differential Revision: https://reviews.llvm.org/D133665
Added:
libcxx/include/__format/format_functions.h
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/format
libcxx/include/module.modulemap.in
libcxx/test/libcxx/private_headers.verify.cpp
Removed:
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 19a0fd5901778..5154b4b6d38ff 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -294,6 +294,7 @@ set(files
__format/format_args.h
__format/format_context.h
__format/format_error.h
+ __format/format_functions.h
__format/format_fwd.h
__format/format_parse_context.h
__format/format_string.h
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
new file mode 100644
index 0000000000000..a197e3c79cd93
--- /dev/null
+++ b/libcxx/include/__format/format_functions.h
@@ -0,0 +1,668 @@
+// -*- 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_FORMAT_FUNCTIONS
+#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS
+
+// TODO FMT This is added to fix Apple back-deployment.
+#include <version>
+#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
+
+#include <__algorithm/clamp.h>
+#include <__availability>
+#include <__concepts/convertible_to.h>
+#include <__concepts/same_as.h>
+#include <__config>
+#include <__debug>
+#include <__format/buffer.h>
+#include <__format/format_arg.h>
+#include <__format/format_arg_store.h>
+#include <__format/format_args.h>
+#include <__format/format_context.h>
+#include <__format/format_error.h>
+#include <__format/format_parse_context.h>
+#include <__format/format_string.h>
+#include <__format/format_to_n_result.h>
+#include <__format/formatter.h>
+#include <__format/formatter_bool.h>
+#include <__format/formatter_char.h>
+#include <__format/formatter_floating_point.h>
+#include <__format/formatter_integer.h>
+#include <__format/formatter_pointer.h>
+#include <__format/formatter_string.h>
+#include <__format/parser_std_format_spec.h>
+#include <__iterator/back_insert_iterator.h>
+#include <__iterator/incrementable_traits.h>
+#include <__variant/monostate.h>
+#include <array>
+#include <string>
+#include <string_view>
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+#include <locale>
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+// TODO FMT Evaluate which templates should be external templates. This
+// improves the efficiency of the header. However since the header is still
+// under heavy development and not all classes are stable it makes no sense
+// to do this optimization now.
+
+using format_args = basic_format_args<format_context>;
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+using wformat_args = basic_format_args<wformat_context>;
+#endif
+
+template <class _Context = format_context, class... _Args>
+_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
+ return _VSTD::__format_arg_store<_Context, _Args...>(__args...);
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&&... __args) {
+ return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...);
+}
+#endif
+
+namespace __format {
+
+/// Helper class parse and handle argument.
+///
+/// When parsing a handle which is not enabled the code is ill-formed.
+/// This helper uses the parser of the appropriate formatter for the stored type.
+template <class _CharT>
+class _LIBCPP_TEMPLATE_VIS __compile_time_handle {
+public:
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr void __parse(basic_format_parse_context<_CharT>& __parse_ctx) const { __parse_(__parse_ctx); }
+
+ template <class _Tp>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __enable() {
+ __parse_ = [](basic_format_parse_context<_CharT>& __parse_ctx) {
+ formatter<_Tp, _CharT> __f;
+ __parse_ctx.advance_to(__f.parse(__parse_ctx));
+ };
+ }
+
+ // Before calling __parse the proper handler needs to be set with __enable.
+ // The default handler isn't a core constant expression.
+ _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle()
+ : __parse_([](basic_format_parse_context<_CharT>&) { __throw_format_error("Not a handle"); }) {}
+
+private:
+ void (*__parse_)(basic_format_parse_context<_CharT>&);
+};
+
+// Dummy format_context only providing the parts used during constant
+// validation of the basic_format_string.
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context {
+public:
+ using char_type = _CharT;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context(
+ const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size)
+ : __args_(__args), __handles_(__handles), __size_(__size) {}
+
+ // During the compile-time validation nothing needs to be written.
+ // Therefore all operations of this iterator are a NOP.
+ struct iterator {
+ _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; }
+ _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; }
+ _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; }
+ };
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const {
+ if (__id >= __size_)
+ __throw_format_error("Argument index out of bounds");
+ return __args_[__id];
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const {
+ if (__id >= __size_)
+ __throw_format_error("Argument index out of bounds");
+ return __handles_[__id];
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; }
+ _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {}
+
+private:
+ const __arg_t* __args_;
+ const __compile_time_handle<_CharT>* __handles_;
+ size_t __size_;
+};
+
+_LIBCPP_HIDE_FROM_ABI
+constexpr void __compile_time_validate_integral(__arg_t __type) {
+ switch (__type) {
+ case __arg_t::__int:
+ case __arg_t::__long_long:
+ case __arg_t::__i128:
+ case __arg_t::__unsigned:
+ case __arg_t::__unsigned_long_long:
+ case __arg_t::__u128:
+ return;
+
+ default:
+ __throw_format_error("Argument isn't an integral type");
+ }
+}
+
+// _HasPrecision does the formatter have a precision?
+template <class _CharT, class _Tp, bool _HasPrecision = false>
+_LIBCPP_HIDE_FROM_ABI constexpr void
+__compile_time_validate_argument(basic_format_parse_context<_CharT>& __parse_ctx,
+ __compile_time_basic_format_context<_CharT>& __ctx) {
+ formatter<_Tp, _CharT> __formatter;
+ __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
+ // [format.string.std]/7
+ // ... If the corresponding formatting argument is not of integral type, or
+ // its value is negative for precision or non-positive for width, an
+ // exception of type format_error is thrown.
+ //
+ // Validate whether the arguments are integrals.
+ if (__formatter.__parser_.__width_as_arg_)
+ __format::__compile_time_validate_integral(__ctx.arg(__formatter.__parser_.__width_));
+
+ if constexpr (_HasPrecision)
+ if (__formatter.__parser_.__precision_as_arg_)
+ __format::__compile_time_validate_integral(__ctx.arg(__formatter.__parser_.__precision_));
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_format_parse_context<_CharT>& __parse_ctx,
+ __compile_time_basic_format_context<_CharT>& __ctx,
+ __arg_t __type) {
+ switch (__type) {
+ case __arg_t::__none:
+ __throw_format_error("Invalid argument");
+ case __arg_t::__boolean:
+ return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx);
+ case __arg_t::__char_type:
+ return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx);
+ case __arg_t::__int:
+ return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx);
+ case __arg_t::__long_long:
+ return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx);
+ case __arg_t::__i128:
+# ifndef _LIBCPP_HAS_NO_INT128
+ return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx);
+# else
+ __throw_format_error("Invalid argument");
+# endif
+ return;
+ case __arg_t::__unsigned:
+ return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx);
+ case __arg_t::__unsigned_long_long:
+ return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx);
+ case __arg_t::__u128:
+# ifndef _LIBCPP_HAS_NO_INT128
+ return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx);
+# else
+ __throw_format_error("Invalid argument");
+# endif
+ return;
+ case __arg_t::__float:
+ return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx);
+ case __arg_t::__double:
+ return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx);
+ case __arg_t::__long_double:
+ return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx);
+ case __arg_t::__const_char_type_ptr:
+ return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx);
+ case __arg_t::__string_view:
+ return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx);
+ case __arg_t::__ptr:
+ return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx);
+ case __arg_t::__handle:
+ __throw_format_error("Handle should use __compile_time_validate_handle_argument");
+ }
+ __throw_format_error("Invalid argument");
+}
+
+template <class _CharT, class _ParseCtx, class _Ctx>
+_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
+__handle_replacement_field(const _CharT* __begin, const _CharT* __end,
+ _ParseCtx& __parse_ctx, _Ctx& __ctx) {
+ __format::__parse_number_result __r =
+ __format::__parse_arg_id(__begin, __end, __parse_ctx);
+
+ bool __parse = *__r.__ptr == _CharT(':');
+ switch (*__r.__ptr) {
+ case _CharT(':'):
+ // The arg-id has a format-specifier, advance the input to the format-spec.
+ __parse_ctx.advance_to(__r.__ptr + 1);
+ break;
+ case _CharT('}'):
+ // The arg-id has no format-specifier.
+ __parse_ctx.advance_to(__r.__ptr);
+ break;
+ default:
+ __throw_format_error(
+ "The replacement field arg-id should terminate at a ':' or '}'");
+ }
+
+ if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) {
+ __arg_t __type = __ctx.arg(__r.__value);
+ if (__type == __arg_t::__handle)
+ __ctx.__handle(__r.__value).__parse(__parse_ctx);
+ else
+ __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type);
+ } else
+ _VSTD::visit_format_arg(
+ [&](auto __arg) {
+ if constexpr (same_as<decltype(__arg), monostate>)
+ __throw_format_error("Argument index out of bounds");
+ else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
+ __arg.format(__parse_ctx, __ctx);
+ else {
+ formatter<decltype(__arg), _CharT> __formatter;
+ if (__parse)
+ __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
+ __ctx.advance_to(__formatter.format(__arg, __ctx));
+ }
+ },
+ __ctx.arg(__r.__value));
+
+ __begin = __parse_ctx.begin();
+ if (__begin == __end || *__begin != _CharT('}'))
+ __throw_format_error("The replacement field misses a terminating '}'");
+
+ return ++__begin;
+}
+
+template <class _ParseCtx, class _Ctx>
+_LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator
+__vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
+ using _CharT = typename _ParseCtx::char_type;
+ static_assert(same_as<typename _Ctx::char_type, _CharT>);
+
+ const _CharT* __begin = __parse_ctx.begin();
+ const _CharT* __end = __parse_ctx.end();
+ typename _Ctx::iterator __out_it = __ctx.out();
+ while (__begin != __end) {
+ switch (*__begin) {
+ case _CharT('{'):
+ ++__begin;
+ if (__begin == __end)
+ __throw_format_error("The format string terminates at a '{'");
+
+ if (*__begin != _CharT('{')) [[likely]] {
+ __ctx.advance_to(_VSTD::move(__out_it));
+ __begin =
+ __handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
+ __out_it = __ctx.out();
+
+ // The output is written and __begin points to the next character. So
+ // start the next iteration.
+ continue;
+ }
+ // The string is an escape character.
+ break;
+
+ case _CharT('}'):
+ ++__begin;
+ if (__begin == __end || *__begin != _CharT('}'))
+ __throw_format_error(
+ "The format string contains an invalid escape sequence");
+
+ break;
+ }
+
+ // Copy the character to the output verbatim.
+ *__out_it++ = *__begin++;
+ }
+ return __out_it;
+}
+
+} // namespace __format
+
+template <class _CharT, class... _Args>
+struct _LIBCPP_TEMPLATE_VIS basic_format_string {
+ template <class _Tp>
+ requires convertible_to<const _Tp&, basic_string_view<_CharT>>
+ consteval basic_format_string(const _Tp& __str) : __str_{__str} {
+ __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)},
+ _Context{__types_.data(), __handles_.data(), sizeof...(_Args)});
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT constexpr basic_string_view<_CharT> get() const noexcept {
+ return __str_;
+ }
+
+private:
+ basic_string_view<_CharT> __str_;
+
+ using _Context = __format::__compile_time_basic_format_context<_CharT>;
+
+ static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{
+ __format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...};
+
+ // TODO FMT remove this work-around when the AIX ICE has been resolved.
+# if defined(_AIX) && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 1400
+ template <class _Tp>
+ static constexpr __format::__compile_time_handle<_CharT> __get_handle() {
+ __format::__compile_time_handle<_CharT> __handle;
+ if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
+ __handle.template __enable<_Tp>();
+
+ return __handle;
+ }
+
+ static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{
+ __get_handle<_Args>()...};
+# else
+ static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] {
+ using _Tp = remove_cvref_t<_Args>;
+ __format::__compile_time_handle<_CharT> __handle;
+ if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
+ __handle.template __enable<_Tp>();
+
+ return __handle;
+ }()...};
+# endif
+};
+
+template <class... _Args>
+using format_string = basic_format_string<char, type_identity_t<_Args>...>;
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;
+#endif
+
+template <class _OutIt, class _CharT, class _FormatOutIt>
+requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
+ __vformat_to(
+ _OutIt __out_it, basic_string_view<_CharT> __fmt,
+ basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
+ if constexpr (same_as<_OutIt, _FormatOutIt>)
+ return _VSTD::__format::__vformat_to(
+ basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(_VSTD::move(__out_it), __args));
+ else {
+ __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)};
+ _VSTD::__format::__vformat_to(
+ basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(__buffer.__make_output_iterator(),
+ __args));
+ return _VSTD::move(__buffer).__out_it();
+ }
+}
+
+// The function is _LIBCPP_ALWAYS_INLINE since the compiler is bad at inlining
+// https://reviews.llvm.org/D110499#inline-1180704
+// TODO FMT Evaluate whether we want to file a Clang bug report regarding this.
+template <output_iterator<const char&> _OutIt>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
+ return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <output_iterator<const wchar_t&> _OutIt>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
+ return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
+}
+#endif
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
+ _VSTD::make_format_args(__args...));
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
+ _VSTD::make_wformat_args(__args...));
+}
+#endif
+
+_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
+vformat(string_view __fmt, format_args __args) {
+ string __res;
+ _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
+ return __res;
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+vformat(wstring_view __fmt, wformat_args __args) {
+ wstring __res;
+ _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
+ return __res;
+}
+#endif
+
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(format_string<_Args...> __fmt,
+ _Args&&... __args) {
+ return _VSTD::vformat(__fmt.get(), _VSTD::make_format_args(__args...));
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+format(wformat_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::vformat(__fmt.get(), _VSTD::make_wformat_args(__args...));
+}
+#endif
+
+template <class _Context, class _OutIt, class _CharT>
+_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n,
+ basic_string_view<_CharT> __fmt,
+ basic_format_args<_Context> __args) {
+ __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n};
+ _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
+ return _VSTD::move(__buffer).__result();
+}
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_format_args(__args...));
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, wformat_string<_Args...> __fmt,
+ _Args&&... __args) {
+ return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_wformat_args(__args...));
+}
+#endif
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) {
+ __format::__formatted_size_buffer<_CharT> __buffer;
+ _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
+ return _VSTD::move(__buffer).__result();
+}
+
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
+}
+#endif
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+
+template <class _OutIt, class _CharT, class _FormatOutIt>
+requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
+ __vformat_to(
+ _OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
+ basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
+ if constexpr (same_as<_OutIt, _FormatOutIt>)
+ return _VSTD::__format::__vformat_to(
+ basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(_VSTD::move(__out_it), __args,
+ _VSTD::move(__loc)));
+ else {
+ __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)};
+ _VSTD::__format::__vformat_to(
+ basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(__buffer.__make_output_iterator(),
+ __args, _VSTD::move(__loc)));
+ return _VSTD::move(__buffer).__out_it();
+ }
+}
+
+template <output_iterator<const char&> _OutIt>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to(
+ _OutIt __out_it, locale __loc, string_view __fmt, format_args __args) {
+ return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
+ __args);
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <output_iterator<const wchar_t&> _OutIt>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to(
+ _OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) {
+ return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
+ __args);
+}
+#endif
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
+ _VSTD::make_format_args(__args...));
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
+format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
+ _VSTD::make_wformat_args(__args...));
+}
+#endif
+
+_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
+vformat(locale __loc, string_view __fmt, format_args __args) {
+ string __res;
+ _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
+ __args);
+ return __res;
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
+ wstring __res;
+ _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
+ __args);
+ return __res;
+}
+#endif
+
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(locale __loc,
+ format_string<_Args...> __fmt,
+ _Args&&... __args) {
+ return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
+ _VSTD::make_format_args(__args...));
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
+format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
+ _VSTD::make_wformat_args(__args...));
+}
+#endif
+
+template <class _Context, class _OutIt, class _CharT>
+_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n,
+ locale __loc, basic_string_view<_CharT> __fmt,
+ basic_format_args<_Context> __args) {
+ __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n};
+ _VSTD::__format::__vformat_to(
+ basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
+ return _VSTD::move(__buffer).__result();
+}
+
+template <output_iterator<const char&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt,
+ _Args&&... __args) {
+ return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
+ _VSTD::make_format_args(__args...));
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <output_iterator<const wchar_t&> _OutIt, class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
+format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt,
+ _Args&&... __args) {
+ return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
+ _VSTD::make_wformat_args(__args...));
+}
+#endif
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) {
+ __format::__formatted_size_buffer<_CharT> __buffer;
+ _VSTD::__format::__vformat_to(
+ basic_format_parse_context{__fmt, __args.__size()},
+ _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
+ return _VSTD::move(__buffer).__result();
+}
+
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
+}
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class... _Args>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
+formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
+ return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
+}
+#endif
+
+#endif // _LIBCPP_HAS_NO_LOCALIZATION
+
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
+
+#endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS
diff --git a/libcxx/include/format b/libcxx/include/format
index 6ec60ff4b36a0..8817dceb1e536 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -141,9 +141,7 @@ namespace std {
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
-#include <__algorithm/clamp.h>
#include <__config>
-#include <__debug>
#include <__format/buffer.h>
#include <__format/concepts.h>
#include <__format/enable_insertable.h>
@@ -152,6 +150,7 @@ namespace std {
#include <__format/format_args.h>
#include <__format/format_context.h>
#include <__format/format_error.h>
+#include <__format/format_functions.h>
#include <__format/format_fwd.h>
#include <__format/format_parse_context.h>
#include <__format/format_string.h>
@@ -165,635 +164,11 @@ namespace std {
#include <__format/formatter_string.h>
#include <__format/parser_std_format_spec.h>
#include <__format/unicode.h>
-#include <__iterator/back_insert_iterator.h>
-#include <__iterator/incrementable_traits.h>
-#include <__variant/monostate.h>
-#include <array>
-#include <concepts>
-#include <string>
-#include <string_view>
-#include <type_traits>
-
-#ifndef _LIBCPP_HAS_NO_LOCALIZATION
-#include <locale>
-#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-#if _LIBCPP_STD_VER > 17
-
-// TODO FMT Move the implementation in this file to its own granular headers.
-
-// TODO FMT Evaluate which templates should be external templates. This
-// improves the efficiency of the header. However since the header is still
-// under heavy development and not all classes are stable it makes no sense
-// to do this optimization now.
-
-using format_args = basic_format_args<format_context>;
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-using wformat_args = basic_format_args<wformat_context>;
-#endif
-
-template <class _Context = format_context, class... _Args>
-_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
- return _VSTD::__format_arg_store<_Context, _Args...>(__args...);
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <class... _Args>
-_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&&... __args) {
- return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...);
-}
-#endif
-
-namespace __format {
-
-/// Helper class parse and handle argument.
-///
-/// When parsing a handle which is not enabled the code is ill-formed.
-/// This helper uses the parser of the appropriate formatter for the stored type.
-template <class _CharT>
-class _LIBCPP_TEMPLATE_VIS __compile_time_handle {
-public:
- _LIBCPP_HIDE_FROM_ABI
- constexpr void __parse(basic_format_parse_context<_CharT>& __parse_ctx) const { __parse_(__parse_ctx); }
-
- template <class _Tp>
- _LIBCPP_HIDE_FROM_ABI constexpr void __enable() {
- __parse_ = [](basic_format_parse_context<_CharT>& __parse_ctx) {
- formatter<_Tp, _CharT> __f;
- __parse_ctx.advance_to(__f.parse(__parse_ctx));
- };
- }
-
- // Before calling __parse the proper handler needs to be set with __enable.
- // The default handler isn't a core constant expression.
- _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle()
- : __parse_([](basic_format_parse_context<_CharT>&) { __throw_format_error("Not a handle"); }) {}
-
-private:
- void (*__parse_)(basic_format_parse_context<_CharT>&);
-};
-
-// Dummy format_context only providing the parts used during constant
-// validation of the basic_format_string.
-template <class _CharT>
-struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context {
-public:
- using char_type = _CharT;
-
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context(
- const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size)
- : __args_(__args), __handles_(__handles), __size_(__size) {}
-
- // During the compile-time validation nothing needs to be written.
- // Therefore all operations of this iterator are a NOP.
- struct iterator {
- _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; }
- _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; }
- _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; }
- };
-
- _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const {
- if (__id >= __size_)
- __throw_format_error("Argument index out of bounds");
- return __args_[__id];
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const {
- if (__id >= __size_)
- __throw_format_error("Argument index out of bounds");
- return __handles_[__id];
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; }
- _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {}
-
-private:
- const __arg_t* __args_;
- const __compile_time_handle<_CharT>* __handles_;
- size_t __size_;
-};
-
-_LIBCPP_HIDE_FROM_ABI
-constexpr void __compile_time_validate_integral(__arg_t __type) {
- switch (__type) {
- case __arg_t::__int:
- case __arg_t::__long_long:
- case __arg_t::__i128:
- case __arg_t::__unsigned:
- case __arg_t::__unsigned_long_long:
- case __arg_t::__u128:
- return;
-
- default:
- __throw_format_error("Argument isn't an integral type");
- }
-}
-
-// _HasPrecision does the formatter have a precision?
-template <class _CharT, class _Tp, bool _HasPrecision = false>
-_LIBCPP_HIDE_FROM_ABI constexpr void
-__compile_time_validate_argument(basic_format_parse_context<_CharT>& __parse_ctx,
- __compile_time_basic_format_context<_CharT>& __ctx) {
- formatter<_Tp, _CharT> __formatter;
- __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
- // [format.string.std]/7
- // ... If the corresponding formatting argument is not of integral type, or
- // its value is negative for precision or non-positive for width, an
- // exception of type format_error is thrown.
- //
- // Validate whether the arguments are integrals.
- if (__formatter.__parser_.__width_as_arg_)
- __format::__compile_time_validate_integral(__ctx.arg(__formatter.__parser_.__width_));
-
- if constexpr (_HasPrecision)
- if (__formatter.__parser_.__precision_as_arg_)
- __format::__compile_time_validate_integral(__ctx.arg(__formatter.__parser_.__precision_));
-}
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_format_parse_context<_CharT>& __parse_ctx,
- __compile_time_basic_format_context<_CharT>& __ctx,
- __arg_t __type) {
- switch (__type) {
- case __arg_t::__none:
- __throw_format_error("Invalid argument");
- case __arg_t::__boolean:
- return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx);
- case __arg_t::__char_type:
- return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx);
- case __arg_t::__int:
- return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx);
- case __arg_t::__long_long:
- return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx);
- case __arg_t::__i128:
-# ifndef _LIBCPP_HAS_NO_INT128
- return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx);
-# else
- __throw_format_error("Invalid argument");
-# endif
- return;
- case __arg_t::__unsigned:
- return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx);
- case __arg_t::__unsigned_long_long:
- return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx);
- case __arg_t::__u128:
-# ifndef _LIBCPP_HAS_NO_INT128
- return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx);
-# else
- __throw_format_error("Invalid argument");
-# endif
- return;
- case __arg_t::__float:
- return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx);
- case __arg_t::__double:
- return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx);
- case __arg_t::__long_double:
- return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx);
- case __arg_t::__const_char_type_ptr:
- return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx);
- case __arg_t::__string_view:
- return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx);
- case __arg_t::__ptr:
- return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx);
- case __arg_t::__handle:
- __throw_format_error("Handle should use __compile_time_validate_handle_argument");
- }
- __throw_format_error("Invalid argument");
-}
-
-template <class _CharT, class _ParseCtx, class _Ctx>
-_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
-__handle_replacement_field(const _CharT* __begin, const _CharT* __end,
- _ParseCtx& __parse_ctx, _Ctx& __ctx) {
- __format::__parse_number_result __r =
- __format::__parse_arg_id(__begin, __end, __parse_ctx);
-
- bool __parse = *__r.__ptr == _CharT(':');
- switch (*__r.__ptr) {
- case _CharT(':'):
- // The arg-id has a format-specifier, advance the input to the format-spec.
- __parse_ctx.advance_to(__r.__ptr + 1);
- break;
- case _CharT('}'):
- // The arg-id has no format-specifier.
- __parse_ctx.advance_to(__r.__ptr);
- break;
- default:
- __throw_format_error(
- "The replacement field arg-id should terminate at a ':' or '}'");
- }
-
- if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) {
- __arg_t __type = __ctx.arg(__r.__value);
- if (__type == __arg_t::__handle)
- __ctx.__handle(__r.__value).__parse(__parse_ctx);
- else
- __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type);
- } else
- _VSTD::visit_format_arg(
- [&](auto __arg) {
- if constexpr (same_as<decltype(__arg), monostate>)
- __throw_format_error("Argument index out of bounds");
- else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
- __arg.format(__parse_ctx, __ctx);
- else {
- formatter<decltype(__arg), _CharT> __formatter;
- if (__parse)
- __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
- __ctx.advance_to(__formatter.format(__arg, __ctx));
- }
- },
- __ctx.arg(__r.__value));
-
- __begin = __parse_ctx.begin();
- if (__begin == __end || *__begin != _CharT('}'))
- __throw_format_error("The replacement field misses a terminating '}'");
-
- return ++__begin;
-}
-
-template <class _ParseCtx, class _Ctx>
-_LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator
-__vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
- using _CharT = typename _ParseCtx::char_type;
- static_assert(same_as<typename _Ctx::char_type, _CharT>);
-
- const _CharT* __begin = __parse_ctx.begin();
- const _CharT* __end = __parse_ctx.end();
- typename _Ctx::iterator __out_it = __ctx.out();
- while (__begin != __end) {
- switch (*__begin) {
- case _CharT('{'):
- ++__begin;
- if (__begin == __end)
- __throw_format_error("The format string terminates at a '{'");
-
- if (*__begin != _CharT('{')) [[likely]] {
- __ctx.advance_to(_VSTD::move(__out_it));
- __begin =
- __handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
- __out_it = __ctx.out();
-
- // The output is written and __begin points to the next character. So
- // start the next iteration.
- continue;
- }
- // The string is an escape character.
- break;
-
- case _CharT('}'):
- ++__begin;
- if (__begin == __end || *__begin != _CharT('}'))
- __throw_format_error(
- "The format string contains an invalid escape sequence");
-
- break;
- }
-
- // Copy the character to the output verbatim.
- *__out_it++ = *__begin++;
- }
- return __out_it;
-}
-
-} // namespace __format
-
-template <class _CharT, class... _Args>
-struct _LIBCPP_TEMPLATE_VIS basic_format_string {
- template <class _Tp>
- requires convertible_to<const _Tp&, basic_string_view<_CharT>>
- consteval basic_format_string(const _Tp& __str) : __str_{__str} {
- __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)},
- _Context{__types_.data(), __handles_.data(), sizeof...(_Args)});
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT constexpr basic_string_view<_CharT> get() const noexcept {
- return __str_;
- }
-
-private:
- basic_string_view<_CharT> __str_;
-
- using _Context = __format::__compile_time_basic_format_context<_CharT>;
-
- static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{
- __format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...};
-
- // TODO FMT remove this work-around when the AIX ICE has been resolved.
-# if defined(_AIX) && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 1400
- template <class _Tp>
- static constexpr __format::__compile_time_handle<_CharT> __get_handle() {
- __format::__compile_time_handle<_CharT> __handle;
- if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
- __handle.template __enable<_Tp>();
-
- return __handle;
- }
-
- static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{
- __get_handle<_Args>()...};
-# else
- static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] {
- using _Tp = remove_cvref_t<_Args>;
- __format::__compile_time_handle<_CharT> __handle;
- if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
- __handle.template __enable<_Tp>();
-
- return __handle;
- }()...};
-# endif
-};
-
-template <class... _Args>
-using format_string = basic_format_string<char, type_identity_t<_Args>...>;
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <class... _Args>
-using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;
-#endif
-
-template <class _OutIt, class _CharT, class _FormatOutIt>
-requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
- __vformat_to(
- _OutIt __out_it, basic_string_view<_CharT> __fmt,
- basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
- if constexpr (same_as<_OutIt, _FormatOutIt>)
- return _VSTD::__format::__vformat_to(
- basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(_VSTD::move(__out_it), __args));
- else {
- __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)};
- _VSTD::__format::__vformat_to(
- basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(__buffer.__make_output_iterator(),
- __args));
- return _VSTD::move(__buffer).__out_it();
- }
-}
-
-// The function is _LIBCPP_ALWAYS_INLINE since the compiler is bad at inlining
-// https://reviews.llvm.org/D110499#inline-1180704
-// TODO FMT Evaluate whether we want to file a Clang bug report regarding this.
-template <output_iterator<const char&> _OutIt>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
- return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <output_iterator<const wchar_t&> _OutIt>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
- return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
-}
-#endif
-
-template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
- _VSTD::make_format_args(__args...));
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
- _VSTD::make_wformat_args(__args...));
-}
-#endif
-
-_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
-vformat(string_view __fmt, format_args __args) {
- string __res;
- _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
- return __res;
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-vformat(wstring_view __fmt, wformat_args __args) {
- wstring __res;
- _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
- return __res;
-}
-#endif
-
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(format_string<_Args...> __fmt,
- _Args&&... __args) {
- return _VSTD::vformat(__fmt.get(), _VSTD::make_format_args(__args...));
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-format(wformat_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::vformat(__fmt.get(), _VSTD::make_wformat_args(__args...));
-}
-#endif
-
-template <class _Context, class _OutIt, class _CharT>
-_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n,
- basic_string_view<_CharT> __fmt,
- basic_format_args<_Context> __args) {
- __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n};
- _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
- return _VSTD::move(__buffer).__result();
-}
-
-template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_format_args(__args...));
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, wformat_string<_Args...> __fmt,
- _Args&&... __args) {
- return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_wformat_args(__args...));
-}
-#endif
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) {
- __format::__formatted_size_buffer<_CharT> __buffer;
- _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
- return _VSTD::move(__buffer).__result();
-}
-
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
-}
-#endif
-
-#ifndef _LIBCPP_HAS_NO_LOCALIZATION
-
-template <class _OutIt, class _CharT, class _FormatOutIt>
-requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
- __vformat_to(
- _OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
- basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
- if constexpr (same_as<_OutIt, _FormatOutIt>)
- return _VSTD::__format::__vformat_to(
- basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(_VSTD::move(__out_it), __args,
- _VSTD::move(__loc)));
- else {
- __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)};
- _VSTD::__format::__vformat_to(
- basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(__buffer.__make_output_iterator(),
- __args, _VSTD::move(__loc)));
- return _VSTD::move(__buffer).__out_it();
- }
-}
-
-template <output_iterator<const char&> _OutIt>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to(
- _OutIt __out_it, locale __loc, string_view __fmt, format_args __args) {
- return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
- __args);
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <output_iterator<const wchar_t&> _OutIt>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to(
- _OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) {
- return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
- __args);
-}
-#endif
-
-template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
- _VSTD::make_format_args(__args...));
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
-format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
- _VSTD::make_wformat_args(__args...));
-}
-#endif
-
-_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
-vformat(locale __loc, string_view __fmt, format_args __args) {
- string __res;
- _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
- __args);
- return __res;
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
- wstring __res;
- _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
- __args);
- return __res;
-}
-#endif
-
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string format(locale __loc,
- format_string<_Args...> __fmt,
- _Args&&... __args) {
- return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
- _VSTD::make_format_args(__args...));
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
-format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
- _VSTD::make_wformat_args(__args...));
-}
-#endif
-
-template <class _Context, class _OutIt, class _CharT>
-_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n,
- locale __loc, basic_string_view<_CharT> __fmt,
- basic_format_args<_Context> __args) {
- __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n};
- _VSTD::__format::__vformat_to(
- basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
- return _VSTD::move(__buffer).__result();
-}
-
-template <output_iterator<const char&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt,
- _Args&&... __args) {
- return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
- _VSTD::make_format_args(__args...));
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <output_iterator<const wchar_t&> _OutIt, class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
-format_to_n(_OutIt __out_it, iter_
diff erence_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt,
- _Args&&... __args) {
- return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
- _VSTD::make_wformat_args(__args...));
-}
-#endif
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) {
- __format::__formatted_size_buffer<_CharT> __buffer;
- _VSTD::__format::__vformat_to(
- basic_format_parse_context{__fmt, __args.__size()},
- _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
- return _VSTD::move(__buffer).__result();
-}
-
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
-}
-
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template <class... _Args>
-_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
-formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
- return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
-}
-#endif
-
-#endif // _LIBCPP_HAS_NO_LOCALIZATION
-
-#endif //_LIBCPP_STD_VER > 17
-
-_LIBCPP_END_NAMESPACE_STD
-
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
#endif // _LIBCPP_FORMAT
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 969b6b52c876c..b7f3380151161 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -661,10 +661,14 @@ module std [system] {
export locale
}
module format_error { private header "__format/format_error.h" }
+ module format_functions { private header "__format/format_functions.h" }
module format_fwd { private header "__format/format_fwd.h" }
module format_parse_context { private header "__format/format_parse_context.h" }
module format_string { private header "__format/format_string.h" }
- module format_to_n_result { private header "__format/format_to_n_result.h" }
+ module format_to_n_result {
+ private header "__format/format_to_n_result.h"
+ export iterator.__iterator.incrementable_traits
+ }
module formatter { private header "__format/formatter.h" }
module formatter_bool { private header "__format/formatter_bool.h" }
module formatter_char { private header "__format/formatter_char.h" }
diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index 58a7e40f666a4..409283fbca990 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -326,6 +326,7 @@ END-SCRIPT
#include <__format/format_args.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_args.h'}}
#include <__format/format_context.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_context.h'}}
#include <__format/format_error.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_error.h'}}
+#include <__format/format_functions.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_functions.h'}}
#include <__format/format_fwd.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_fwd.h'}}
#include <__format/format_parse_context.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_parse_context.h'}}
#include <__format/format_string.h> // expected-error@*:* {{use of private header from outside its module: '__format/format_string.h'}}
More information about the libcxx-commits
mailing list