Mark de Wever d7444d9f41 [libc++][format] Implement formatters.
This implements the initial version of the `std::formatter` class and its specializations. It also implements the following formatting functions:
- `format`
- `vformat`
- `format_to`
- `vformat_to`
- `format_to_n`
- `formatted_size`

All functions have a `char` and `wchar_t` version. Parsing the format-spec and
using the parsed format-spec hasn't been implemented. The code isn't optimized,
neither for speed, nor for size.

The goal is to have the rudimentary basics working, which can be used as a
basis to improve upon. The formatters used in this commit are simple stubs that
will be replaced by real formatters in later commits.

The formatters that are slated to be replaced in this patch series don't have
an availability macro to avoid merge conflicts.

Note the formatter for `bool` uses `0` and `1` instead of "false" and
"true". This will be fixed when the stub is replaced with a real
formatter.

Implements parts of:
- P0645 Text Formatting

Completes:
- LWG3539 format_to must not copy models of output_iterator<const charT&>

Reviewed By: ldionne, #libc, vitaut

Differential Revision: https://reviews.llvm.org/D96664
2021-09-04 11:41:08 +02:00

939 lines
35 KiB
C++

// -*- C++ -*-
//===--------------------------- format -----------------------------------===//
//
// 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
#define _LIBCPP_FORMAT
/*
namespace std {
// [format.context], class template basic_format_context
template<class Out, class charT>
class basic_format_context {
basic_format_args<basic_format_context> args_; // exposition only
Out out_; // exposition only
public:
using iterator = Out;
using char_type = charT;
template<class T> using formatter_type = formatter<T, charT>;
basic_format_arg<basic_format_context> arg(size_t id) const;
std::locale locale();
iterator out();
void advance_to(iterator it);
};
using format_context = basic_format_context<unspecified, char>;
using wformat_context = basic_format_context<unspecified, wchar_t>;
// [format.args], class template basic_format_args
template<class Context>
class basic_format_args {
size_t size_; // exposition only
const basic_format_arg<Context>* data_; // exposition only
public:
basic_format_args() noexcept;
template<class... Args>
basic_format_args(const format-arg-store<Context, Args...>& store) noexcept;
basic_format_arg<Context> get(size_t i) const noexcept;
};
using format_args = basic_format_args<format_context>;
using wformat_args = basic_format_args<wformat_context>;
template<class Out, class charT>
using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
// [format.functions], formatting functions
template<class... Args>
string format(string_view fmt, const Args&... args);
template<class... Args>
wstring format(wstring_view fmt, const Args&... args);
template<class... Args>
string format(const locale& loc, string_view fmt, const Args&... args);
template<class... Args>
wstring format(const locale& loc, wstring_view fmt, const Args&... args);
string vformat(string_view fmt, format_args args);
wstring vformat(wstring_view fmt, wformat_args args);
string vformat(const locale& loc, string_view fmt, format_args args);
wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
template<class Out, class... Args>
Out format_to(Out out, string_view fmt, const Args&... args);
template<class Out, class... Args>
Out format_to(Out out, wstring_view fmt, const Args&... args);
template<class Out, class... Args>
Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
template<class Out, class... Args>
Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);
template<class Out>
Out vformat_to(Out out, string_view fmt,
format_args_t<type_identity_t<Out>, char> args);
template<class Out>
Out vformat_to(Out out, wstring_view fmt,
format_args_t<type_identity_t<Out>, wchar_t> args);
template<class Out>
Out vformat_to(Out out, const locale& loc, string_view fmt,
format_args_t<type_identity_t<Out>, char> args);
template<class Out>
Out vformat_to(Out out, const locale& loc, wstring_view fmt,
format_args_t<type_identity_t<Out>, wchar_t> args);
template<class Out> struct format_to_n_result {
Out out;
iter_difference_t<Out> size;
};
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
string_view fmt, const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wstring_view fmt, const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
const locale& loc, string_view fmt,
const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
const locale& loc, wstring_view fmt,
const Args&... args);
template<class... Args>
size_t formatted_size(string_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(wstring_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
// [format.formatter], formatter
template<> struct formatter<char, char>;
template<> struct formatter<char, wchar_t>;
template<> struct formatter<wchar_t, wchar_t>;
template<> struct formatter<charT*, charT>;
template<> struct formatter<const charT*, charT>;
template<size_t N> struct formatter<const charT[N], charT>;
template<class traits, class Allocator>
struct formatter<basic_string<charT, traits, Allocator>, charT>;
template<class traits>
struct formatter<basic_string_view<charT, traits>, charT>;
// [format.parse.ctx], class template basic_format_parse_context
template<class charT>
class basic_format_parse_context {
public:
using char_type = charT;
using const_iterator = typename basic_string_view<charT>::const_iterator;
using iterator = const_iterator;
private:
iterator begin_; // exposition only
iterator end_; // exposition only
enum indexing { unknown, manual, automatic }; // exposition only
indexing indexing_; // exposition only
size_t next_arg_id_; // exposition only
size_t num_args_; // exposition only
public:
constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args = 0) noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr void advance_to(const_iterator it);
constexpr size_t next_arg_id();
constexpr void check_arg_id(size_t id);
};
using format_parse_context = basic_format_parse_context<char>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
// [format.arguments], arguments
// [format.arg], class template basic_format_arg
template<class Context>
class basic_format_arg {
public:
class handle;
private:
using char_type = typename Context::char_type; // exposition only
variant<monostate, bool, char_type,
int, unsigned int, long long int, unsigned long long int,
float, double, long double,
const char_type*, basic_string_view<char_type>,
const void*, handle> value; // exposition only
template<class T> explicit basic_format_arg(const T& v) noexcept; // exposition only
explicit basic_format_arg(float n) noexcept; // exposition only
explicit basic_format_arg(double n) noexcept; // exposition only
explicit basic_format_arg(long double n) noexcept; // exposition only
explicit basic_format_arg(const char_type* s); // exposition only
template<class traits>
explicit basic_format_arg(
basic_string_view<char_type, traits> s) noexcept; // exposition only
template<class traits, class Allocator>
explicit basic_format_arg(
const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only
explicit basic_format_arg(nullptr_t) noexcept; // exposition only
template<class T>
explicit basic_format_arg(const T* p) noexcept; // exposition only
public:
basic_format_arg() noexcept;
explicit operator bool() const noexcept;
};
template<class Visitor, class Context>
see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
// [format.arg.store], class template format-arg-store
template<class Context, class... Args>
struct format-arg-store { // exposition only
array<basic_format_arg<Context>, sizeof...(Args)> args;
};
template<class Context = format_context, class... Args>
format-arg-store<Context, Args...>
make_format_args(const Args&... args);
template<class... Args>
format-arg-store<wformat_context, Args...>
make_wformat_args(const Args&... args);
// [format.error], class format_error
class format_error : public runtime_error {
public:
explicit format_error(const string& what_arg);
explicit format_error(const char* what_arg);
};
// [format.parse.ctx], class template basic_format_parse_context
template<class charT>
class basic_format_parse_context {
public:
using char_type = charT;
using const_iterator = typename basic_string_view<charT>::const_iterator;
using iterator = const_iterator;
private:
iterator begin_; // exposition only
iterator end_; // exposition only
enum indexing { unknown, manual, automatic }; // exposition only
indexing indexing_; // exposition only
size_t next_arg_id_; // exposition only
size_t num_args_; // exposition only
public:
constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args = 0) noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr void advance_to(const_iterator it);
constexpr size_t next_arg_id();
constexpr void check_arg_id(size_t id);
};
using format_parse_context = basic_format_parse_context<char>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
}
*/
// Make sure all feature-test macros are available.
#include <version>
// Enable the contents of the header only when libc++ was built with LIBCXX_ENABLE_INCOMPLETE_FEATURES.
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
#include <__config>
#include <__debug>
#include <__format/format_arg.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/formatter.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_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17
// TODO FMT Remove this once we require compilers with proper C++20 support.
// If the compiler has no concepts support, the format header will be disabled.
// Without concepts support enable_if needs to be used and that too much effort
// to support compilers with partial C++20 support.
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
// 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>;
using wformat_args = basic_format_args<wformat_context>;
template <class _OutIt, class _CharT>
using format_args_t = basic_format_args<basic_format_context<_OutIt, _CharT>>;
template <class _Context, class... _Args>
struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
// TODO FMT Use a built-in array.
array<basic_format_arg<_Context>, sizeof...(_Args)> __args;
};
template <class _Context = format_context, class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...>
make_format_args(const _Args&... __args) {
return {basic_format_arg<_Context>(__args)...};
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...>
make_wformat_args(const _Args&... __args) {
return _VSTD::make_format_args<wformat_context>(__args...);
}
namespace __format {
template <class _Tp, class _CharT>
struct _LIBCPP_TEMPLATE_VIS __formatter_char {
_LIBCPP_HIDE_FROM_ABI
auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
// TODO FMT Implement this function.
return __parse_ctx.begin();
}
_LIBCPP_HIDE_FROM_ABI
auto format(_Tp __c, auto& __ctx) -> decltype(__ctx.out()) {
// TODO FMT Implement the parsed formatting arguments.
auto __out_it = __ctx.out();
*__out_it++ = _CharT(__c);
return __out_it;
}
};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS __formatter_c_string {
_LIBCPP_HIDE_FROM_ABI
auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
// TODO FMT Implement this function.
return __parse_ctx.begin();
}
_LIBCPP_HIDE_FROM_ABI
auto format(const _CharT* __str, auto& __ctx) -> decltype(__ctx.out()) {
// TODO FMT Implement the parsed formatting arguments.
auto __out_it = __ctx.out();
while (*__str)
*__out_it++ = *__str++;
return __out_it;
}
};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS __formatter_string {
_LIBCPP_HIDE_FROM_ABI
auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
// TODO FMT Implement this function.
return __parse_ctx.begin();
}
_LIBCPP_HIDE_FROM_ABI
auto format(basic_string_view<_CharT> __str, auto& __ctx)
-> decltype(__ctx.out()) {
// TODO FMT Implement the parsed formatting arguments.
auto __out_it = __ctx.out();
for (const auto __c : __str)
*__out_it++ = __c;
return __out_it;
}
};
template <class _Tp, class _CharT>
requires(is_arithmetic_v<_Tp> &&
!same_as<_Tp, bool>) struct _LIBCPP_HIDE_FROM_ABI
__formatter_arithmetic {
_LIBCPP_HIDE_FROM_ABI
auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
// TODO FMT Implement
return __parse_ctx.begin();
}
_LIBCPP_HIDE_FROM_ABI
auto format(_Tp __value, auto& __ctx) -> decltype(__ctx.out()) {
return __handle_format(__value, __ctx);
}
private:
template <class _Uv>
_LIBCPP_HIDDEN static string
__convert(_Uv __value) requires(same_as<_CharT, char>) {
return _VSTD::to_string(__value);
}
template <class _Uv>
_LIBCPP_HIDDEN static wstring
__convert(_Uv __value) requires(same_as<_CharT, wchar_t>) {
return _VSTD::to_wstring(__value);
}
template <class _Uv>
_LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx)
-> decltype(__ctx.out())
#ifndef _LIBCPP_HAS_NO_INT128
requires(!same_as<_Uv, __int128_t> && !same_as<_Uv, __uint128_t>)
#endif
{
// TODO FMT Implement using formatting arguments
// TODO FMT Improve PoC since using std::to_string is inefficient.
// Note the code doesn't use std::string::iterator since the unit tests
// test with debug iterators and they fail with strings created from
// std::to_string.
auto __str = __convert(__value);
auto __out_it = __ctx.out();
for (size_t __i = 0, __e = __str.size(); __i != __e; ++__i)
*__out_it++ = __str[__i];
return __out_it;
}
#ifndef _LIBCPP_HAS_NO_INT128
template <class _Uv>
_LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx)
-> decltype(__ctx.out()) requires(same_as<_Uv, __int128_t> ||
same_as<_Uv, __uint128_t>) {
using _To = conditional_t<is_signed_v<_Uv>, long long, unsigned long long>;
// TODO FMT Implement full 128-bit support.
if (__value < numeric_limits<_To>::min() ||
__value > numeric_limits<_To>::max())
__throw_format_error("128-bit value is outside of implemented range");
return __handle_format(static_cast<_To>(__value), __ctx);
}
#endif
};
} // namespace __format
// These specializations are helper stubs and not proper formatters.
// TODO FMT Implement the proper formatter specializations.
// [format.formatter.spec]/2.1 The specializations
template <>
struct _LIBCPP_TEMPLATE_VIS formatter<char, char>
: public __format::__formatter_char<char, char> {};
template <>
struct _LIBCPP_TEMPLATE_VIS formatter<char, wchar_t>
: public __format::__formatter_char<char, wchar_t> {};
template <>
struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t>
: public __format::__formatter_char<wchar_t, wchar_t> {};
// [format.formatter.spec]/2.2 For each charT, the string type specializations
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT>
: public __format::__formatter_c_string<_CharT> {
using _Base = __format::__formatter_c_string<_CharT>;
_LIBCPP_HIDE_FROM_ABI auto format(_CharT* __str, auto& __ctx)
-> decltype(__ctx.out()) {
_LIBCPP_ASSERT(__str, "The basic_format_arg constructor should have "
"prevented an invalid pointer");
return _Base::format(__str, __ctx);
}
};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT>
: public __format::__formatter_c_string<_CharT> {};
template <class _CharT, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT[_Size], _CharT>
: public __format::__formatter_string<_CharT> {
using _Base = __format::__formatter_string<_CharT>;
_LIBCPP_HIDE_FROM_ABI auto format(const _CharT __str[_Size], auto& __ctx)
-> decltype(__ctx.out()) {
return _Base::format(_VSTD::basic_string_view<_CharT>(__str, _Size), __ctx);
}
};
template <class _CharT, class _Traits, class _Allocator>
struct _LIBCPP_TEMPLATE_VIS
formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT>
: public __format::__formatter_string<_CharT> {
using _Base = __format::__formatter_string<_CharT>;
_LIBCPP_HIDE_FROM_ABI auto
format(const basic_string<_CharT, _Traits, _Allocator>& __str, auto& __ctx)
-> decltype(__ctx.out()) {
return _Base::format(_VSTD::basic_string_view<_CharT>(__str), __ctx);
}
};
template <class _CharT, class _Traits>
struct _LIBCPP_TEMPLATE_VIS
formatter<basic_string_view<_CharT, _Traits>, _CharT>
: public __format::__formatter_string<_CharT> {};
// [format.formatter.spec]/2.3
// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
// Boolean.
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
_LIBCPP_HIDE_FROM_ABI
auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
// TODO FMT Implement
return __parse_ctx.begin();
}
_LIBCPP_HIDE_FROM_ABI
auto format(bool __b, auto& __ctx) -> decltype(__ctx.out()) {
// TODO FMT Implement using formatting arguments
auto __out_it = __ctx.out();
*__out_it++ = _CharT('0') + __b;
return __out_it;
}
};
// Signed integral types.
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<signed char, _CharT>
: public __format::__formatter_arithmetic<signed char, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<short, _CharT>
: public __format::__formatter_arithmetic<short, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<int, _CharT>
: public __format::__formatter_arithmetic<int, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<long, _CharT>
: public __format::__formatter_arithmetic<long, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<long long, _CharT>
: public __format::__formatter_arithmetic<long long, _CharT> {};
#ifndef _LIBCPP_HAS_NO_INT128
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT>
: public __format::__formatter_arithmetic<__int128_t, _CharT> {};
#endif
// Unsigned integral types.
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned char, _CharT>
: public __format::__formatter_arithmetic<unsigned char, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned short, _CharT>
: public __format::__formatter_arithmetic<unsigned short, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned, _CharT>
: public __format::__formatter_arithmetic<unsigned, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long, _CharT>
: public __format::__formatter_arithmetic<unsigned long, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long long, _CharT>
: public __format::__formatter_arithmetic<unsigned long long, _CharT> {};
#ifndef _LIBCPP_HAS_NO_INT128
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT>
: public __format::__formatter_arithmetic<__uint128_t, _CharT> {};
#endif
// Floating point types.
// TODO FMT There are no replacements for the floating point stubs due to not
// having floating point support in std::to_chars yet. These stubs aren't
// removed since they are useful for developing the real versions.
// Ultimately the stubs should be implemented properly and this code can be
// removed.
#if 0
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT>
: public __format::__formatter_arithmetic<float, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
formatter<double, _CharT>
: public __format::__formatter_arithmetic<double, _CharT> {};
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
formatter<long double, _CharT>
: public __format::__formatter_arithmetic<long double, _CharT> {};
#endif
namespace __format {
template <class _CharT, class _ParseCtx, class _Ctx>
_LIBCPP_HIDE_FROM_ABI 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);
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 '}'");
}
_VSTD::visit_format_arg(
[&](auto __arg) {
if constexpr (same_as<decltype(__arg), monostate>)
__throw_format_error("Argument index out of bounds");
else {
formatter<decltype(__arg), _CharT> __formatter;
__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 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 _OutIt, class _CharT>
requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
__vformat_to(_OutIt __out_it, basic_string_view<_CharT> __fmt,
format_args_t<type_identity_t<_OutIt>, _CharT> __args) {
return __format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(_VSTD::move(__out_it), __args));
}
template <output_iterator<const char&> _OutIt>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
vformat_to(_OutIt __out_it, string_view __fmt,
format_args_t<type_identity_t<_OutIt>, char> __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
}
template <output_iterator<const wchar_t&> _OutIt>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
vformat_to(_OutIt __out_it, wstring_view __fmt,
format_args_t<type_identity_t<_OutIt>, wchar_t> __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
}
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
format_to(_OutIt __out_it, string_view __fmt, const _Args&... __args) {
return _VSTD::vformat_to(
_VSTD::move(__out_it), __fmt,
_VSTD::make_format_args<basic_format_context<_OutIt, char>>(__args...));
}
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
format_to(_OutIt __out_it, wstring_view __fmt, const _Args&... __args) {
return _VSTD::vformat_to(
_VSTD::move(__out_it), __fmt,
_VSTD::make_format_args<basic_format_context<_OutIt, wchar_t>>(
__args...));
}
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;
}
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;
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
format(string_view __fmt, const _Args&... __args) {
return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
format(wstring_view __fmt, const _Args&... __args) {
return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
}
template <class _OutIt>
struct _LIBCPP_TEMPLATE_VIS format_to_n_result {
_OutIt out;
iter_difference_t<_OutIt> size;
};
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, string_view __fmt,
const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
iter_difference_t<_OutIt> __s = __str.size();
iter_difference_t<_OutIt> __m =
_VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
__out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
return {_VSTD::move(__out_it), __s};
}
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_difference_t<_OutIt> __n, wstring_view __fmt,
const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
iter_difference_t<_OutIt> __s = __str.size();
iter_difference_t<_OutIt> __m =
_VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
__out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
return {_VSTD::move(__out_it), __s};
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
formatted_size(string_view __fmt, const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)).size();
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
formatted_size(wstring_view __fmt, const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)).size();
}
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
template <class _OutIt, class _CharT>
requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
__vformat_to(_OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
format_args_t<type_identity_t<_OutIt>, _CharT> __args) {
return __format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(_VSTD::move(__out_it), __args,
_VSTD::move(__loc)));
}
template <output_iterator<const char&> _OutIt>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
vformat_to(_OutIt __out_it, locale __loc, string_view __fmt,
format_args_t<type_identity_t<_OutIt>, char> __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
__args);
}
template <output_iterator<const wchar_t&> _OutIt>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt,
format_args_t<type_identity_t<_OutIt>, wchar_t> __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
__args);
}
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
_OutIt __out_it, locale __loc, string_view __fmt, const _Args&... __args) {
return _VSTD::vformat_to(
_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
_VSTD::make_format_args<basic_format_context<_OutIt, char>>(__args...));
}
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
_OutIt __out_it, locale __loc, wstring_view __fmt, const _Args&... __args) {
return _VSTD::vformat_to(
_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
_VSTD::make_format_args<basic_format_context<_OutIt, wchar_t>>(
__args...));
}
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;
}
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;
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
format(locale __loc, string_view __fmt, const _Args&... __args) {
return _VSTD::vformat(_VSTD::move(__loc), __fmt,
_VSTD::make_format_args(__args...));
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
format(locale __loc, wstring_view __fmt, const _Args&... __args) {
return _VSTD::vformat(_VSTD::move(__loc), __fmt,
_VSTD::make_wformat_args(__args...));
}
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
string_view __fmt, const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
_VSTD::make_format_args(__args...));
iter_difference_t<_OutIt> __s = __str.size();
iter_difference_t<_OutIt> __m =
_VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
__out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
return {_VSTD::move(__out_it), __s};
}
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_difference_t<_OutIt> __n, locale __loc,
wstring_view __fmt, const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
_VSTD::make_wformat_args(__args...));
iter_difference_t<_OutIt> __s = __str.size();
iter_difference_t<_OutIt> __m =
_VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
__out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
return {_VSTD::move(__out_it), __s};
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
formatted_size(locale __loc, string_view __fmt, const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
return _VSTD::vformat(_VSTD::move(__loc), __fmt,
_VSTD::make_format_args(__args...))
.size();
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
formatted_size(locale __loc, wstring_view __fmt, const _Args&... __args) {
// TODO FMT Improve PoC: using std::string is inefficient.
return _VSTD::vformat(_VSTD::move(__loc), __fmt,
_VSTD::make_wformat_args(__args...))
.size();
}
#endif
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
#endif //_LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
#endif // _LIBCPP_FORMAT