[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

NOKEYCHECK=True
GitOrigin-RevId: d7444d9f41e34886d7d316659090ba6bf4d61cba
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 33bc1ec..3a926e6 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -134,6 +134,8 @@
   __format/format_error.h
   __format/format_fwd.h
   __format/format_parse_context.h
+  __format/format_string.h
+  __format/formatter.h
   __function_like.h
   __functional_base
   __functional/binary_function.h
diff --git a/include/__format/format_string.h b/include/__format/format_string.h
new file mode 100644
index 0000000..864053f
--- /dev/null
+++ b/include/__format/format_string.h
@@ -0,0 +1,174 @@
+// -*- 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_STRING_H
+#define _LIBCPP___FORMAT_FORMAT_STRING_H
+
+#include <__config>
+#include <__debug>
+#include <__format/format_error.h>
+#include <cstddef>
+#include <cstdint>
+
+#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)
+
+namespace __format {
+
+template <class _CharT>
+struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
+  const _CharT* __ptr;
+  uint32_t __value;
+};
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_number(const _CharT* __begin, const _CharT* __end);
+
+/**
+ * The maximum value of a numeric argument.
+ *
+ * This is used for:
+ * * arg-id
+ * * width as value or arg-id.
+ * * precision as value or arg-id.
+ *
+ * The value is compatible with the maximum formatting width and precision
+ * using the `%*` syntax on a 32-bit system.
+ */
+inline constexpr uint32_t __number_max = INT32_MAX;
+
+namespace __detail {
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_zero(const _CharT* __begin, const _CharT*, auto& __parse_ctx) {
+  __parse_ctx.check_arg_id(0);
+  return {++__begin, 0}; // can never be larger than the maximum.
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_automatic(const _CharT* __begin, const _CharT*, auto& __parse_ctx) {
+  size_t __value = __parse_ctx.next_arg_id();
+  _LIBCPP_ASSERT(__value <= __number_max,
+                 "Compilers don't support this number of arguments");
+
+  return {__begin, uint32_t(__value)};
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_manual(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
+  __parse_number_result<_CharT> __r = __parse_number(__begin, __end);
+  __parse_ctx.check_arg_id(__r.__value);
+  return __r;
+}
+
+} // namespace __detail
+
+/**
+ * Parses a number.
+ *
+ * The number is used for the 31-bit values @em width and @em precision. This
+ * allows a maximum value of 2147483647.
+ */
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_number(const _CharT* __begin, const _CharT* __end_input) {
+  static_assert(__format::__number_max == INT32_MAX,
+                "The algorithm is implemented based on this value.");
+  /*
+   * Limit the input to 9 digits, otherwise we need two checks during every
+   * iteration:
+   * - Are we at the end of the input?
+   * - Does the value exceed width of an uint32_t? (Switching to uint64_t would
+   *   have the same issue, but with a higher maximum.)
+   */
+  const _CharT* __end = __end_input - __begin > 9 ? __begin + 9 : __end_input;
+  uint32_t __value = *__begin - _CharT('0');
+  while (++__begin != __end) {
+    if (*__begin < _CharT('0') || *__begin > _CharT('9'))
+      return {__begin, __value};
+
+    __value = __value * 10 + *__begin - _CharT('0');
+  }
+
+  if (__begin != __end_input && *__begin >= _CharT('0') &&
+      *__begin <= _CharT('9')) {
+
+    /*
+     * There are more than 9 digits, do additional validations:
+     * - Does the 10th digit exceed the maximum allowed value?
+     * - Are there more than 10 digits?
+     * (More than 10 digits always overflows the maximum.)
+     */
+    uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0');
+    if (__v > __number_max ||
+        (__begin != __end_input && *__begin >= _CharT('0') &&
+         *__begin <= _CharT('9')))
+      __throw_format_error("The numeric value of the format-spec is too large");
+
+    __value = __v;
+  }
+
+  return {__begin, __value};
+}
+
+/**
+ * Multiplexer for all parse functions.
+ *
+ * The parser will return a pointer beyond the last consumed character. This
+ * should be the closing '}' of the arg-id.
+ */
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
+__parse_arg_id(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
+  switch (*__begin) {
+  case _CharT('0'):
+    return __detail::__parse_zero(__begin, __end, __parse_ctx);
+
+  case _CharT(':'):
+    // This case is conditionally valid. It's allowed in an arg-id in the
+    // replacement-field, but not in the std-format-spec. The caller can
+    // provide a better diagnostic, so accept it here unconditionally.
+  case _CharT('}'):
+    return __detail::__parse_automatic(__begin, __end, __parse_ctx);
+  }
+  if (*__begin < _CharT('0') || *__begin > _CharT('9'))
+    __throw_format_error(
+        "The arg-id of the format-spec starts with an invalid character");
+
+  return __detail::__parse_manual(__begin, __end, __parse_ctx);
+}
+
+} // namespace __format
+
+#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___FORMAT_FORMAT_STRING_H
diff --git a/include/__format/formatter.h b/include/__format/formatter.h
new file mode 100644
index 0000000..2aec2f4
--- /dev/null
+++ b/include/__format/formatter.h
@@ -0,0 +1,64 @@
+// -*- 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_FORMATTER_H
+#define _LIBCPP___FORMAT_FORMATTER_H
+
+#include <__availability>
+#include <__config>
+#include <__format/format_error.h>
+
+#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)
+
+// Currently not implemented specializations throw an exception when used. This
+// does not conform to the Standard. However not all Standard defined formatters
+// have been implemented yet. Until that time the current behavior is intended.
+// TODO FMT Disable the default template.
+template <class _Tp, class _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter {
+  _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto parse(auto& __parse_ctx)
+      -> decltype(__parse_ctx.begin()) {
+    __throw();
+  }
+
+  _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto format(_Tp, auto& __ctx)
+      -> decltype(__ctx.out()) {
+    __throw();
+  }
+
+private:
+  _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw() {
+    __throw_format_error("Argument type not implemented yet");
+  }
+};
+
+#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___FORMAT_FORMATTER_H
diff --git a/include/format b/include/format
index b320b75..90547e2 100644
--- a/include/format
+++ b/include/format
@@ -54,6 +54,85 @@
   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 {
@@ -191,17 +270,32 @@
 #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
@@ -241,11 +335,604 @@
   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
diff --git a/include/module.modulemap b/include/module.modulemap
index 5ef0f9a..ba14615 100644
--- a/include/module.modulemap
+++ b/include/module.modulemap
@@ -441,6 +441,8 @@
       module format_error         { private header "__format/format_error.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 formatter            { private header "__format/formatter.h"            }
     }
   }
   module forward_list {