[libcxx-commits] [libcxx] 1562e51 - [libc++] Don't assume that string_view::const_iterator is a raw pointer
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 30 07:19:55 PST 2023
Author: Louis Dionne
Date: 2023-01-30T10:19:32-05:00
New Revision: 1562e5149174b86c8f9d0b4d2ec0101fe67dddcb
URL: https://github.com/llvm/llvm-project/commit/1562e5149174b86c8f9d0b4d2ec0101fe67dddcb
DIFF: https://github.com/llvm/llvm-project/commit/1562e5149174b86c8f9d0b4d2ec0101fe67dddcb.diff
LOG: [libc++] Don't assume that string_view::const_iterator is a raw pointer
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
Added:
Modified:
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
Removed:
################################################################################
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 185148ccba531..7589b63efdc64 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -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) {
diff --git a/libcxx/include/__format/format_string.h b/libcxx/include/__format/format_string.h
index d9caf866a17d0..a82421784db4e 100644
--- a/libcxx/include/__format/format_string.h
+++ b/libcxx/include/__format/format_string.h
@@ -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);
diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h
index 467692559ce91..82d619e3d2403 100644
--- a/libcxx/include/__format/formatter_output.h
+++ b/libcxx/include/__format/formatter_output.h
@@ -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,
ptr
diff _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_;
diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h
index c03cec9796364..f70a8258ce655 100644
--- a/libcxx/include/__format/parser_std_format_spec.h
+++ b/libcxx/include/__format/parser_std_format_spec.h
@@ -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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
_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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
}
// 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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
__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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
__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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
__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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
__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 @@ class _LIBCPP_TEMPLATE_VIS __parser {
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
diff --git a/libcxx/include/__format/unicode.h b/libcxx/include/__format/unicode.h
index 432725876082e..b8ac394b617c6 100644
--- a/libcxx/include/__format/unicode.h
+++ b/libcxx/include/__format/unicode.h
@@ -11,11 +11,15 @@
#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 @@ class __code_point_view<char> {
# 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 @@ class __code_point_view<wchar_t> {
# 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 @@ class __extended_grapheme_cluster_view {
///
/// 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 @@ class __extended_grapheme_cluster_view {
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 @@ class __extended_grapheme_cluster_view {
}
};
-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 @@ class __code_point_view {
# endif // _LIBCPP_STD_VER > 20
private:
- const _CharT* __first_;
- const _CharT* __last_;
+ _Iterator __first_;
+ _Iterator __last_;
};
# endif // _LIBCPP_HAS_NO_UNICODE
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 6bc64be69d608..a12848335ca58 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -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" }
More information about the libcxx-commits
mailing list