[libc++][format] Add basic_format_parse_context.

Implements parts of:
- P0645 Text Formatting

Depends on D92214

Reland with changes:
The format header will only be compiled if the compiler used has support
for concepts. This should fix the issues with the initial version.

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

GitOrigin-RevId: 38ddeade65c50343a7f6a0daec57139b07ec7807
diff --git a/include/format b/include/format
index 833423a..9e41120 100644
--- a/include/format
+++ b/include/format
@@ -19,14 +19,51 @@
     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>;
 }
 
 */
 
 #include <__config>
 #include <stdexcept>
+#include <string_view>
 #include <version>
 
+#ifdef _LIBCPP_NO_EXCEPTIONS
+#include <cstdlib>
+#endif
+
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
@@ -38,6 +75,12 @@
 
 #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.
+#ifndef _LIBCPP_HAS_NO_CONCEPTS
+
 class _LIBCPP_EXCEPTION_ABI format_error : public runtime_error {
 public:
   _LIBCPP_INLINE_VISIBILITY explicit format_error(const string& __s)
@@ -47,6 +90,89 @@
   virtual ~format_error() noexcept;
 };
 
+_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY void
+__throw_format_error(const char* __s) {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+  throw format_error(__s);
+#else
+  (void)__s;
+  _VSTD::abort();
+#endif
+}
+
+template <class _CharT>
+class _LIBCPP_TEMPLATE_VIS basic_format_parse_context {
+public:
+  using char_type = _CharT;
+  using const_iterator =
+      typename _VSTD::basic_string_view<_CharT>::const_iterator;
+  using iterator = const_iterator;
+
+public:
+  _LIBCPP_INLINE_VISIBILITY
+  constexpr explicit basic_format_parse_context(
+      _VSTD::basic_string_view<_CharT> __fmt, size_t __num_args = 0) noexcept
+      : __begin_(__fmt.begin()),
+        __end_(__fmt.end()),
+        __indexing_(__unknown),
+        __next_arg_id_(0),
+        __num_args_(__num_args) {}
+
+  basic_format_parse_context(const basic_format_parse_context&) = delete;
+  basic_format_parse_context&
+  operator=(const basic_format_parse_context&) = delete;
+
+  _LIBCPP_INLINE_VISIBILITY constexpr const_iterator begin() const noexcept {
+    return __begin_;
+  }
+  _LIBCPP_INLINE_VISIBILITY constexpr const_iterator end() const noexcept {
+    return __end_;
+  }
+  _LIBCPP_INLINE_VISIBILITY constexpr void advance_to(const_iterator __it) {
+    __begin_ = __it;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY constexpr size_t next_arg_id() {
+    if (__indexing_ == __manual)
+      __throw_format_error("Using automatic argument numbering in manual "
+                           "argument numbering mode");
+
+    if (__indexing_ == __unknown)
+      __indexing_ = __automatic;
+    return __next_arg_id_++;
+  }
+  _LIBCPP_INLINE_VISIBILITY constexpr void check_arg_id(size_t __id) {
+    if (__indexing_ == __automatic)
+      __throw_format_error("Using manual argument numbering in automatic "
+                           "argument numbering mode");
+
+    if (__indexing_ == __unknown)
+      __indexing_ = __manual;
+
+    // Throws an exception to make the expression a non core constant
+    // expression as required by:
+    // [format.parse.ctx]/11
+    //   Remarks: Call expressions where id >= num_args_ are not core constant
+    //   expressions ([expr.const]).
+    // Note: the Throws clause [format.parse.ctx]/10 doesn't specify the
+    // behavior when id >= num_args_.
+    if (_VSTD::is_constant_evaluated() && __id >= __num_args_)
+      __throw_format_error("Argument index outside the valid range");
+  }
+
+private:
+  iterator __begin_;
+  iterator __end_;
+  enum _Indexing { __unknown, __manual, __automatic };
+  _Indexing __indexing_;
+  size_t __next_arg_id_;
+  size_t __num_args_;
+};
+
+using format_parse_context = basic_format_parse_context<char>;
+using wformat_parse_context = basic_format_parse_context<wchar_t>;
+
+#endif //_LIBCPP_HAS_NO_CONCEPTS
 #endif //_LIBCPP_STD_VER > 17
 
 _LIBCPP_END_NAMESPACE_STD