[libc++][format] Adds a formattable concept.

The concept is based on P2286R2 Formatting Ranges. It will be used to
optimise the storage of __format_arg_store as required by LWG-3473.

Depends on D120916

Reviewed By: #libc, Mordante

Differential Revision: https://reviews.llvm.org/D120921

NOKEYCHECK=True
GitOrigin-RevId: 15c809e8e78083d59f1c0b09ca1d1644e0976961
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 55ac4db..2da8b98 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -209,6 +209,7 @@
   __filesystem/space_info.h
   __filesystem/u8path.h
   __format/buffer.h
+  __format/concepts.h
   __format/enable_insertable.h
   __format/format_arg.h
   __format/format_args.h
diff --git a/include/__format/concepts.h b/include/__format/concepts.h
new file mode 100644
index 0000000..8df6493
--- /dev/null
+++ b/include/__format/concepts.h
@@ -0,0 +1,53 @@
+// -*- 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_CONCEPTS_H
+#define _LIBCPP___FORMAT_CONCEPTS_H
+
+#include <__concepts/same_as.h>
+#include <__concepts/semiregular.h>
+#include <__config>
+#include <__format/format_fwd.h>
+#include <__format/format_parse_context.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+// The output iterator isn't specified. A formatter should accept any
+// output_iterator. This iterator is a minimal iterator to test the concept.
+// (Note testing for (w)format_context would be a valid choice, but requires
+// selecting the proper one depending on the type of _CharT.)
+template <class _CharT>
+using __fmt_iter_for = _CharT*;
+
+// The concept is based on P2286R6
+// It lacks the const of __cf as required by, the not yet accepted, LWG-3636.
+// The current formatters can't be easily adapted, but that is WIP.
+// TODO FMT properly implement this concepts once accepted.
+template <class _Tp, class _CharT>
+concept __formattable = (semiregular<formatter<remove_cvref_t<_Tp>, _CharT>>) &&
+                        requires(formatter<remove_cvref_t<_Tp>, _CharT> __f,
+                                 formatter<remove_cvref_t<_Tp>, _CharT> __cf, _Tp __t,
+                                 basic_format_context<__fmt_iter_for<_CharT>, _CharT> __fc,
+                                 basic_format_parse_context<_CharT> __pc) {
+                          { __f.parse(__pc) } -> same_as<typename basic_format_parse_context<_CharT>::iterator>;
+                          { __cf.format(__t, __fc) } -> same_as<__fmt_iter_for<_CharT>>;
+                        };
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FORMAT_CONCEPTS_H
diff --git a/include/__format/format_fwd.h b/include/__format/format_fwd.h
index 0f2e908..908d10d 100644
--- a/include/__format/format_fwd.h
+++ b/include/__format/format_fwd.h
@@ -12,6 +12,7 @@
 
 #include <__availability>
 #include <__config>
+#include <__iterator/concepts.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -27,6 +28,10 @@
 template <class _Context, class... _Args>
 struct _LIBCPP_TEMPLATE_VIS __format_arg_store;
 
+template <class _OutIt, class _CharT>
+  requires output_iterator<_OutIt, const _CharT&>
+class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context;
+
 template <class _Tp, class _CharT = char>
 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter;
 
diff --git a/include/format b/include/format
index 9516278..070bfe2 100644
--- a/include/format
+++ b/include/format
@@ -127,6 +127,7 @@
 #include <__config>
 #include <__debug>
 #include <__format/buffer.h>
+#include <__format/concepts.h>
 #include <__format/enable_insertable.h>
 #include <__format/format_arg.h>
 #include <__format/format_args.h>
diff --git a/include/module.modulemap b/include/module.modulemap
index 7ae3d10..ef97b81 100644
--- a/include/module.modulemap
+++ b/include/module.modulemap
@@ -542,6 +542,7 @@
 
     module __format {
       module buffer                   { private header "__format/buffer.h" }
+      module concepts                 { private header "__format/concepts.h" }
       module enable_insertable        { private header "__format/enable_insertable.h" }
       module format_arg               { private header "__format/format_arg.h" }
       module format_args              { private header "__format/format_args.h" }