[libc++] Don't assume that string_view::const_iterator is a raw pointer
authorLouis Dionne <ldionne.2@gmail.com>
Mon, 28 Nov 2022 13:01:46 +0000 (08:01 -0500)
committerLouis Dionne <ldionne.2@gmail.com>
Mon, 30 Jan 2023 15:19:32 +0000 (10:19 -0500)
Our implementation of std::format assumed that string_view's iterators
were raw pointers in various places. If we want to introduce a checked
iterator in debug mode, that won't be true anymore. This patch removes
that assumption.

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

libcxx/include/__format/format_functions.h
libcxx/include/__format/format_string.h
libcxx/include/__format/formatter_output.h
libcxx/include/__format/parser_std_format_spec.h
libcxx/include/__format/unicode.h
libcxx/include/module.modulemap.in

index 185148c..7589b63 100644 (file)
@@ -38,7 +38,9 @@
 #include <__format/formatter_string.h>
 #include <__format/parser_std_format_spec.h>
 #include <__iterator/back_insert_iterator.h>
+#include <__iterator/concepts.h>
 #include <__iterator/incrementable_traits.h>
+#include <__iterator/readable_traits.h> // iter_value_t
 #include <__variant/monostate.h>
 #include <array>
 #include <string>
@@ -236,21 +238,22 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_forma
   std::__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,
+template <contiguous_iterator _Iterator, class _ParseCtx, class _Ctx>
+_LIBCPP_HIDE_FROM_ABI constexpr _Iterator
+__handle_replacement_field(_Iterator __begin, _Iterator __end,
                            _ParseCtx& __parse_ctx, _Ctx& __ctx) {
+  using _CharT = iter_value_t<_Iterator>;
   __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx);
 
-  bool __parse = *__r.__ptr == _CharT(':');
-  switch (*__r.__ptr) {
+  bool __parse = *__r.__last == _CharT(':');
+  switch (*__r.__last) {
   case _CharT(':'):
     // The arg-id has a format-specifier, advance the input to the format-spec.
-    __parse_ctx.advance_to(__r.__ptr + 1);
+    __parse_ctx.advance_to(__r.__last + 1);
     break;
   case _CharT('}'):
     // The arg-id has no format-specifier.
-    __parse_ctx.advance_to(__r.__ptr);
+    __parse_ctx.advance_to(__r.__last);
     break;
   default:
     std::__throw_format_error("The replacement field arg-id should terminate at a ':' or '}'");
@@ -291,8 +294,8 @@ __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();
+  auto __begin = __parse_ctx.begin();
+  auto __end = __parse_ctx.end();
   typename _Ctx::iterator __out_it = __ctx.out();
   while (__begin != __end) {
     switch (*__begin) {
index d9caf86..a824217 100644 (file)
@@ -13,6 +13,8 @@
 #include <__assert>
 #include <__config>
 #include <__format/format_error.h>
+#include <__iterator/concepts.h>
+#include <__iterator/readable_traits.h> // iter_value_t
 #include <cstddef>
 #include <cstdint>
 
@@ -26,18 +28,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace __format {
 
-template <class _CharT>
+template <contiguous_iterator _Iterator>
 struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
-  const _CharT* __ptr;
+  _Iterator __last;
   uint32_t __value;
 };
 
-template <class _CharT>
-__parse_number_result(const _CharT*, uint32_t) -> __parse_number_result<_CharT>;
+template <contiguous_iterator _Iterator>
+__parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>;
 
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_CharT>
-__parse_number(const _CharT* __begin, const _CharT* __end);
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
+__parse_number(_Iterator __begin, _Iterator __end);
 
 /**
  * The maximum value of a numeric argument.
@@ -53,16 +55,16 @@ __parse_number(const _CharT* __begin, const _CharT* __end);
 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) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
+__parse_zero(_Iterator __begin, _Iterator, 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) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
+__parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) {
   size_t __value = __parse_ctx.next_arg_id();
   _LIBCPP_ASSERT(__value <= __number_max,
                  "Compilers don't support this number of arguments");
@@ -70,10 +72,10 @@ __parse_automatic(const _CharT* __begin, const _CharT*, auto& __parse_ctx) {
   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 = __format::__parse_number(__begin, __end);
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
+__parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
+  __parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end);
   __parse_ctx.check_arg_id(__r.__value);
   return __r;
 }
@@ -86,9 +88,10 @@ __parse_manual(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
  * 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) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
+__parse_number(_Iterator __begin, _Iterator __end_input) {
+  using _CharT = iter_value_t<_Iterator>;
   static_assert(__format::__number_max == INT32_MAX,
                 "The algorithm is implemented based on this value.");
   /*
@@ -98,7 +101,7 @@ __parse_number(const _CharT* __begin, const _CharT* __end_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;
+  _Iterator __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'))
@@ -134,9 +137,10 @@ __parse_number(const _CharT* __begin, const _CharT* __end_input) {
  * 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) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
+__parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
+  using _CharT = iter_value_t<_Iterator>;
   switch (*__begin) {
   case _CharT('0'):
     return __detail::__parse_zero(__begin, __end, __parse_ctx);
index 4676925..82d619e 100644 (file)
@@ -23,6 +23,8 @@
 #include <__format/parser_std_format_spec.h>
 #include <__format/unicode.h>
 #include <__iterator/back_insert_iterator.h>
+#include <__iterator/concepts.h>
+#include <__iterator/readable_traits.h> // iter_value_t
 #include <__type_traits/make_unsigned.h>
 #include <__utility/move.h>
 #include <__utility/unreachable.h>
@@ -261,11 +263,11 @@ __write(basic_string_view<_CharT> __str,
   return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
 }
 
-template <class _CharT, class _ParserCharT>
+template <contiguous_iterator _Iterator, class _ParserCharT>
 _LIBCPP_HIDE_FROM_ABI auto
-__write(const _CharT* __first,
-        const _CharT* __last,
-        output_iterator<const _CharT&> auto __out_it,
+__write(_Iterator __first,
+        _Iterator __last,
+        output_iterator<const iter_value_t<_Iterator>&> auto __out_it,
         __format_spec::__parsed_specifications<_ParserCharT> __specs,
         ptrdiff_t __size) -> decltype(__out_it) {
   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
@@ -275,11 +277,11 @@ __write(const _CharT* __first,
 /// \overload
 ///
 /// Calls the function above where \a __size = \a __last - \a __first.
-template <class _CharT, class _ParserCharT>
+template <contiguous_iterator _Iterator, class _ParserCharT>
 _LIBCPP_HIDE_FROM_ABI auto
-__write(const _CharT* __first,
-        const _CharT* __last,
-        output_iterator<const _CharT&> auto __out_it,
+__write(_Iterator __first,
+        _Iterator __last,
+        output_iterator<const iter_value_t<_Iterator>&> auto __out_it,
         __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) {
   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
   return __formatter::__write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first);
@@ -359,7 +361,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
 
 template <class _CharT>
 _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) {
-  __format_spec::__column_width_result<_CharT> __result =
+  __format_spec::__column_width_result __result =
       __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down);
   __str = basic_string_view<_CharT>{__str.begin(), __result.__last_};
   return __result.__width_;
index c03cec9..f70a825 100644 (file)
@@ -28,6 +28,8 @@
 #include <__format/format_parse_context.h>
 #include <__format/format_string.h>
 #include <__format/unicode.h>
+#include <__iterator/concepts.h>
+#include <__iterator/readable_traits.h> // iter_value_t
 #include <__variant/monostate.h>
 #include <bit>
 #include <cstdint>
@@ -47,9 +49,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace __format_spec {
 
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result< _CharT>
-__parse_arg_id(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result<_Iterator>
+__parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
+  using _CharT = iter_value_t<_Iterator>;
   // This function is a wrapper to call the real parser. But it does the
   // validation for the pre-conditions and post-conditions.
   if (__begin == __end)
@@ -57,10 +60,10 @@ __parse_arg_id(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {
 
   __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx);
 
-  if (__r.__ptr == __end || *__r.__ptr != _CharT('}'))
+  if (__r.__last == __end || *__r.__last != _CharT('}'))
     std::__throw_format_error("Invalid arg-id");
 
-  ++__r.__ptr;
+  ++__r.__last;
   return __r;
 }
 
@@ -268,8 +271,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(basic_format_parse_context<_CharT>& __parse_ctx, __fields __fields)
       -> decltype(__parse_ctx.begin()) {
 
-    const _CharT* __begin = __parse_ctx.begin();
-    const _CharT* __end = __parse_ctx.end();
+    auto __begin = __parse_ctx.begin();
+    auto __end = __parse_ctx.end();
     if (__begin == __end)
       return __begin;
 
@@ -391,8 +394,8 @@ private:
   }
 
   // range-fill and tuple-fill are identical
-  _LIBCPP_HIDE_FROM_ABI constexpr bool
-  __parse_fill_align(const _CharT*& __begin, const _CharT* __end, bool __use_range_fill) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
     _LIBCPP_ASSERT(__begin != __end, "when called with an empty input the function will cause "
                                      "undefined behavior by evaluating data not in the input");
     if (__begin + 1 != __end) {
@@ -415,7 +418,8 @@ private:
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_sign(const _CharT*& __begin) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_sign(_Iterator& __begin) {
     switch (*__begin) {
     case _CharT('-'):
       __sign_ = __sign::__minus;
@@ -433,7 +437,8 @@ private:
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alternate_form(const _CharT*& __begin) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alternate_form(_Iterator& __begin) {
     if (*__begin != _CharT('#'))
       return false;
 
@@ -442,7 +447,8 @@ private:
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_zero_padding(const _CharT*& __begin) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_zero_padding(_Iterator& __begin) {
     if (*__begin != _CharT('0'))
       return false;
 
@@ -452,7 +458,8 @@ private:
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(const _CharT*& __begin, const _CharT* __end, auto& __parse_ctx) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __parse_ctx) {
     if (*__begin == _CharT('0'))
       std::__throw_format_error("A format-spec width field shouldn't have a leading zero");
 
@@ -460,7 +467,7 @@ private:
       __format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __parse_ctx);
       __width_as_arg_ = true;
       __width_ = __r.__value;
-      __begin = __r.__ptr;
+      __begin = __r.__last;
       return true;
     }
 
@@ -471,12 +478,12 @@ private:
     __width_ = __r.__value;
     _LIBCPP_ASSERT(__width_ != 0, "A zero value isn't allowed and should be impossible, "
                                   "due to validations in this function");
-    __begin = __r.__ptr;
+    __begin = __r.__last;
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(const _CharT*& __begin, const _CharT* __end,
-                                                         auto& __parse_ctx) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(_Iterator& __begin, _Iterator __end, auto& __parse_ctx) {
     if (*__begin != _CharT('.'))
       return false;
 
@@ -488,7 +495,7 @@ private:
       __format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __parse_ctx);
       __precision_as_arg_ = true;
       __precision_ = __arg_id.__value;
-      __begin = __arg_id.__ptr;
+      __begin = __arg_id.__last;
       return true;
     }
 
@@ -498,11 +505,12 @@ private:
     __format::__parse_number_result __r = __format::__parse_number(__begin, __end);
     __precision_ = __r.__value;
     __precision_as_arg_ = false;
-    __begin = __r.__ptr;
+    __begin = __r.__last;
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_locale_specific_form(const _CharT*& __begin) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_locale_specific_form(_Iterator& __begin) {
     if (*__begin != _CharT('L'))
       return false;
 
@@ -511,7 +519,8 @@ private:
     return true;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(const _CharT*& __begin) {
+  template <contiguous_iterator _Iterator>
+  _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin) {
     // Determines the type. It does not validate whether the selected type is
     // valid. Most formatters have optional fields that are only allowed for
     // certain types. These parsers need to do validation after the type has
@@ -734,18 +743,18 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spe
   }
 }
 
-template <class _CharT>
+template <contiguous_iterator _Iterator>
 struct __column_width_result {
   /// The number of output columns.
   size_t __width_;
   /// One beyond the last code unit used in the estimation.
   ///
   /// This limits the original output to fit in the wanted number of columns.
-  const _CharT* __last_;
+  _Iterator __last_;
 };
 
-template <class _CharT>
-__column_width_result(size_t, const _CharT*) -> __column_width_result<_CharT>;
+template <contiguous_iterator _Iterator>
+__column_width_result(size_t, _Iterator) -> __column_width_result<_Iterator>;
 
 /// Since a column width can be two it's possible that the requested column
 /// width can't be achieved. Depending on the intended usage the policy can be
@@ -812,12 +821,13 @@ _LIBCPP_HIDE_FROM_ABI constexpr int __column_width(uint32_t __c) noexcept {
   return __detail::__column_width_4(__c);
 }
 
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT> __estimate_column_width_grapheme_clustering(
-    const _CharT* __first, const _CharT* __last, size_t __maximum, __column_width_rounding __rounding) noexcept {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width_grapheme_clustering(
+    _Iterator __first, _Iterator __last, size_t __maximum, __column_width_rounding __rounding) noexcept {
+  using _CharT = iter_value_t<_Iterator>;
   __unicode::__extended_grapheme_cluster_view<_CharT> __view{__first, __last};
 
-  __column_width_result<_CharT> __result{0, __first};
+  __column_width_result<_Iterator> __result{0, __first};
   while (__result.__last_ != __last && __result.__width_ <= __maximum) {
     typename __unicode::__extended_grapheme_cluster_view<_CharT>::__cluster __cluster = __view.__consume();
     int __width = __detail::__column_width(__cluster.__code_point_);
@@ -884,8 +894,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __is_ascii(char32_t __c) { return __c < 0x8
 /// \param __rounding Selects the rounding method.
 ///                   \c __down result.__width_ <= __maximum
 ///                   \c __up result.__width_ <= __maximum + 1
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT> __estimate_column_width(
+template <class _CharT, class _Iterator = typename basic_string_view<_CharT>::const_iterator>
+_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width(
     basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding __rounding) noexcept {
   // The width estimation is done in two steps:
   // - Quickly process for the ASCII part. ASCII has the following properties
@@ -904,7 +914,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT> __estimate_column_
   // need to scan one code unit beyond the requested precision. When this code
   // unit is non-ASCII we omit the current code unit and let the Grapheme
   // clustering algorithm do its work.
-  const _CharT* __it = __str.begin();
+  auto __it = __str.begin();
   if (__format_spec::__is_ascii(*__it)) {
     do {
       --__maximum;
@@ -932,7 +942,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT> __estimate_column_
 }
 #  else // !defined(_LIBCPP_HAS_NO_UNICODE)
 template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<typename basic_string_view<_CharT>::const_iterator>
 __estimate_column_width(basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding) noexcept {
   // When Unicode isn't supported assume ASCII and every code unit is one code
   // point. In ASCII the estimated column width is always one. Thus there's no
index 4327258..b8ac394 100644 (file)
 #define _LIBCPP___FORMAT_UNICODE_H
 
 #include <__assert>
+#include <__concepts/same_as.h>
 #include <__config>
 #include <__format/extended_grapheme_cluster_table.h>
+#include <__iterator/concepts.h>
+#include <__iterator/readable_traits.h> // iter_value_t
 #include <__type_traits/make_unsigned.h>
 #include <__utility/unreachable.h>
 #include <bit>
+#include <string_view>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -62,7 +66,9 @@ struct __consume_p2286_result {
 
 inline constexpr char32_t __replacement_character = U'\ufffd';
 
-_LIBCPP_HIDE_FROM_ABI constexpr bool __is_continuation(const char* __char, int __count) {
+template <contiguous_iterator _Iterator>
+  requires same_as<iter_value_t<_Iterator>, char>
+_LIBCPP_HIDE_FROM_ABI constexpr bool __is_continuation(_Iterator __char, int __count) {
   do {
     if ((*__char & 0b1000'0000) != 0b1000'0000)
       return false;
@@ -82,12 +88,14 @@ class __code_point_view;
 /// UTF-8 specialization.
 template <>
 class __code_point_view<char> {
+  using _Iterator = basic_string_view<char>::const_iterator;
+
 public:
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(const char* __first, const char* __last)
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last)
       : __first_(__first), __last_(__last) {}
 
   _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
-  _LIBCPP_HIDE_FROM_ABI constexpr const char* __position() const noexcept { return __first_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr char32_t __consume() noexcept {
     _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
@@ -207,8 +215,8 @@ public:
 #    endif // _LIBCPP_STD_VER > 20
 
 private:
-  const char* __first_;
-  const char* __last_;
+  _Iterator __first_;
+  _Iterator __last_;
 };
 
 #    ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -225,13 +233,15 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_low(wchar_t __value) {
 /// - 4 UTF-32 (for example Linux)
 template <>
 class __code_point_view<wchar_t> {
+  using _Iterator = typename basic_string_view<wchar_t>::const_iterator;
+
 public:
   static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "sizeof(wchar_t) has a not implemented value");
 
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(const wchar_t* __first, const wchar_t* __last)
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last)
       : __first_(__first), __last_(__last) {}
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const wchar_t* __position() const noexcept { return __first_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
   _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr char32_t __consume() noexcept {
@@ -292,8 +302,8 @@ public:
 #      endif // _LIBCPP_STD_VER > 20
 
 private:
-  const wchar_t* __first_;
-  const wchar_t* __last_;
+  _Iterator __first_;
+  _Iterator __last_;
 };
 #    endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 
@@ -384,8 +394,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __at_extended_grapheme_cluster_break(
 /// Therefore only this code point is extracted.
 template <class _CharT>
 class __extended_grapheme_cluster_view {
+  using _Iterator = typename basic_string_view<_CharT>::const_iterator;
+
 public:
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_view(const _CharT* __first, const _CharT* __last)
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_view(_Iterator __first, _Iterator __last)
       : __code_point_view_(__first, __last),
         __next_code_point_(__code_point_view_.__consume()),
         __next_prop_(__extended_grapheme_custer_property_boundary::__get_property(__next_code_point_)) {}
@@ -401,7 +413,7 @@ public:
     ///
     /// It's expected the caller has the start position and thus can determine
     /// the code unit range of the extended grapheme cluster.
-    const _CharT* __last_;
+    _Iterator __last_;
   };
 
   _LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() {
@@ -422,11 +434,11 @@ private:
   char32_t __next_code_point_;
   __extended_grapheme_custer_property_boundary::__property __next_prop_;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __get_break() {
+  _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __get_break() {
     bool __ri_break_allowed         = true;
     bool __has_extened_pictographic = false;
     while (true) {
-      const _CharT* __result                                          = __code_point_view_.__position();
+      _Iterator __result                                              = __code_point_view_.__position();
       __extended_grapheme_custer_property_boundary::__property __prev = __next_prop_;
       if (__code_point_view_.__at_end()) {
         __next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot;
@@ -444,8 +456,8 @@ private:
   }
 };
 
-template <class _CharT>
-__extended_grapheme_cluster_view(const _CharT*, const _CharT*) -> __extended_grapheme_cluster_view<_CharT>;
+template <contiguous_iterator _Iterator>
+__extended_grapheme_cluster_view(_Iterator, _Iterator) -> __extended_grapheme_cluster_view<iter_value_t<_Iterator>>;
 
 #  else //  _LIBCPP_HAS_NO_UNICODE
 
@@ -453,12 +465,14 @@ __extended_grapheme_cluster_view(const _CharT*, const _CharT*) -> __extended_gra
 // This makes it easier to write code agnostic of the _LIBCPP_HAS_NO_UNICODE define.
 template <class _CharT>
 class __code_point_view {
+  using _Iterator = typename basic_string_view<_CharT>::const_iterator;
+
 public:
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(const _CharT* __first, const _CharT* __last)
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last)
       : __first_(__first), __last_(__last) {}
 
   _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
-  _LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __position() const noexcept { return __first_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr char32_t __consume() noexcept {
     _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
@@ -474,8 +488,8 @@ public:
 #    endif // _LIBCPP_STD_VER > 20
 
 private:
-  const _CharT* __first_;
-  const _CharT* __last_;
+  _Iterator __first_;
+  _Iterator __last_;
 };
 
 #  endif //  _LIBCPP_HAS_NO_UNICODE
index 6bc64be..a128483 100644 (file)
@@ -1012,7 +1012,10 @@ module std [system] {
       module permutable            { private header "__iterator/permutable.h" }
       module prev                  { private header "__iterator/prev.h" }
       module projected             { private header "__iterator/projected.h" }
-      module readable_traits       { private header "__iterator/readable_traits.h" }
+      module readable_traits       {
+        private header "__iterator/readable_traits.h"
+        export __iterator.iterator_traits
+      }
       module reverse_access        { private header "__iterator/reverse_access.h" }
       module reverse_iterator      { private header "__iterator/reverse_iterator.h" }
       module segmented_iterator    { private header "__iterator/segmented_iterator.h" }