[libcxx-commits] [libcxx] [libc++] Use __wrap_iter in string_view and array in the unstable ABI (PR #74482)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Dec 6 07:20:41 PST 2023
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/74482
>From 582203cc86f744589fdc27c619933421adfdc018 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 5 Dec 2023 09:57:07 -0500
Subject: [PATCH] [libc++] Use __wrap_iter in string_view and array in the
unstable ABI
std::string_view and std::array iterators don't have to be raw pointers,
and in fact other implementations don't represent them as raw pointers.
Them being raw pointers in libc++ makes it easier for users to write
non-portable code. This is bad in itself, but this is even worse when
considering efforts like hardening where we want an easy ability to
swap for a different iterator type. If users depend on iterators being
raw pointers, this becomes a build break.
Hence, this patch enables the use of __wrap_iter in the unstable ABI,
creating a long term path towards making this the default. This patch
may break code that assumes these iterators are raw pointers for
people compiling with the unstable ABI.
This patch also removes several assumptions that array iterators are
raw pointers in the code base and in the test suite.
---
libcxx/include/__config | 6 +
libcxx/include/__format/buffer.h | 12 +-
libcxx/include/__format/formatter_integral.h | 32 +-
libcxx/include/__format/formatter_output.h | 34 +-
libcxx/include/__iterator/wrap_iter.h | 2 +
libcxx/include/array | 22 +-
libcxx/include/string_view | 11 +-
.../print.fun/transcoding.pass.cpp | 5 +-
...nst_proxy_iterators_lifetime_bugs.pass.cpp | 18 +-
.../containers/sequences/array/types.pass.cpp | 4 -
.../span.cons/iterator_sentinel.pass.cpp | 5 +-
.../formatter.floating_point.pass.cpp | 594 ++++++++++--------
.../formatter.pointer.pass.cpp | 4 +-
13 files changed, 431 insertions(+), 318 deletions(-)
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 7f66042f90256..7352e57c2de65 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -168,6 +168,12 @@
// pointer from 16 to 8. This changes the output of std::string::max_size,
// which makes it ABI breaking
# define _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
+// Define std::array/std::string_view iterators to be __wrap_iters instead of raw
+// pointers, which prevents people from relying on a non-portable implementation
+// detail. This is especially useful because enabling bounded iterators hardening
+// requires code not to make these assumptions.
+# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY
+# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
# elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index 8aa58d6464bbf..24608a0b1d200 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -130,8 +130,10 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
/// A std::transform wrapper.
///
/// Like @ref __copy it may need to do type conversion.
- template <__fmt_char_type _InCharT, class _UnaryOperation>
- _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
+ template <contiguous_iterator _Iterator,
+ class _UnaryOperation,
+ __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
+ _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
_LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
size_t __n = static_cast<size_t>(__last - __first);
@@ -590,8 +592,10 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
__size_ += __n;
}
- template <__fmt_char_type _InCharT, class _UnaryOperation>
- _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
+ template <contiguous_iterator _Iterator,
+ class _UnaryOperation,
+ __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
+ _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
_LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
size_t __n = static_cast<size_t>(__last - __first);
diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h
index 598decb0a95ea..93a41f9417588 100644
--- a/libcxx/include/__format/formatter_integral.h
+++ b/libcxx/include/__format/formatter_integral.h
@@ -20,6 +20,8 @@
#include <__format/format_error.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
+#include <__iterator/concepts.h>
+#include <__memory/pointer_traits.h>
#include <__system_error/errc.h>
#include <__type_traits/make_unsigned.h>
#include <__utility/unreachable.h>
@@ -49,7 +51,8 @@ namespace __formatter {
// Generic
//
-_LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, __format_spec::__sign __sign) {
+template <contiguous_iterator _Iterator>
+_LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __negative, __format_spec::__sign __sign) {
if (__negative)
*__buf++ = '-';
else
@@ -148,14 +151,15 @@ _LIBCPP_HIDE_FROM_ABI auto __format_char(
// Integer
//
-/** Wrapper around @ref to_chars, returning the output pointer. */
-template <integral _Tp>
-_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, int __base) {
+/** Wrapper around @ref to_chars, returning the output iterator. */
+template <contiguous_iterator _Iterator, integral _Tp>
+_LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, _Tp __value, int __base) {
// TODO FMT Evaluate code overhead due to not calling the internal function
// directly. (Should be zero overhead.)
- to_chars_result __r = std::to_chars(__first, __last, __value, __base);
+ to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base);
_LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small");
- return __r.ptr;
+ auto __diff = __r.ptr - std::to_address(__first);
+ return __first + __diff;
}
/**
@@ -203,9 +207,9 @@ consteval size_t __buffer_size() noexcept
+ 1; // Reserve space for the sign.
}
-template <class _OutIt, class _CharT>
-_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first,
- const char* __last, string&& __grouping, _CharT __sep,
+template <class _OutIt, contiguous_iterator _Iterator, class _CharT>
+_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, _Iterator __begin, _Iterator __first,
+ _Iterator __last, string&& __grouping, _CharT __sep,
__format_spec::__parsed_specifications<_CharT> __specs) {
int __size = (__first - __begin) + // [sign][prefix]
(__last - __first) + // data
@@ -269,22 +273,22 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, c
-template <unsigned_integral _Tp, class _CharT, class _FormatContext>
+template <unsigned_integral _Tp, contiguous_iterator _Iterator, class _CharT, class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer(
_Tp __value,
_FormatContext& __ctx,
__format_spec::__parsed_specifications<_CharT> __specs,
bool __negative,
- char* __begin,
- char* __end,
+ _Iterator __begin,
+ _Iterator __end,
const char* __prefix,
int __base) {
- char* __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
+ _Iterator __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
if (__specs.__std_.__alternate_form_ && __prefix)
while (*__prefix)
*__first++ = *__prefix++;
- char* __last = __formatter::__to_buffer(__first, __end, __value, __base);
+ _Iterator __last = __formatter::__to_buffer(__first, __end, __value, __base);
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
if (__specs.__std_.__locale_specific_form_) {
diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h
index 2909fcd9baf1e..6c7892d86900d 100644
--- a/libcxx/include/__format/formatter_output.h
+++ b/libcxx/include/__format/formatter_output.h
@@ -23,8 +23,9 @@
#include <__format/unicode.h>
#include <__iterator/back_insert_iterator.h>
#include <__iterator/concepts.h>
-#include <__iterator/iterator_traits.h> // iter_value_t
+#include <__iterator/iterator_traits.h>
#include <__memory/addressof.h>
+#include <__memory/pointer_traits.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
#include <cstddef>
@@ -110,26 +111,32 @@ _LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterat
}
}
-template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
-_LIBCPP_HIDE_FROM_ABI auto
-__copy(const _CharT* __first, const _CharT* __last, output_iterator<const _OutCharT&> auto __out_it)
+template <contiguous_iterator _Iterator,
+ __fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type,
+ __fmt_char_type _OutCharT = _CharT>
+_LIBCPP_HIDE_FROM_ABI auto __copy(_Iterator __first, _Iterator __last, output_iterator<const _OutCharT&> auto __out_it)
-> decltype(__out_it) {
return __formatter::__copy(basic_string_view{__first, __last}, std::move(__out_it));
}
-template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
-_LIBCPP_HIDE_FROM_ABI auto __copy(const _CharT* __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it)
+template <contiguous_iterator _Iterator,
+ __fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type,
+ __fmt_char_type _OutCharT = _CharT>
+_LIBCPP_HIDE_FROM_ABI auto __copy(_Iterator __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it)
-> decltype(__out_it) {
- return __formatter::__copy(basic_string_view{__first, __n}, std::move(__out_it));
+ return __formatter::__copy(basic_string_view{std::to_address(__first), __n}, std::move(__out_it));
}
/// Transform wrapper.
///
/// This uses a "mass output function" of __format::__output_buffer when possible.
-template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT, class _UnaryOperation>
+template <contiguous_iterator _Iterator,
+ __fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type,
+ __fmt_char_type _OutCharT = _CharT,
+ class _UnaryOperation>
_LIBCPP_HIDE_FROM_ABI auto
-__transform(const _CharT* __first,
- const _CharT* __last,
+__transform(_Iterator __first,
+ _Iterator __last,
output_iterator<const _OutCharT&> auto __out_it,
_UnaryOperation __operation) -> decltype(__out_it) {
if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
@@ -260,8 +267,11 @@ __write(_Iterator __first,
return __formatter::__write(__first, __last, std::move(__out_it), __specs, __last - __first);
}
-template <class _CharT, class _ParserCharT, class _UnaryOperation>
-_LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last,
+template <contiguous_iterator _Iterator,
+ class _CharT = typename iterator_traits<_Iterator>::value_type,
+ class _ParserCharT,
+ class _UnaryOperation>
+_LIBCPP_HIDE_FROM_ABI auto __write_transformed(_Iterator __first, _Iterator __last,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
_UnaryOperation __op) -> decltype(__out_it) {
diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h
index d028d7b3c33c7..b9cb69dfd799a 100644
--- a/libcxx/include/__iterator/wrap_iter.h
+++ b/libcxx/include/__iterator/wrap_iter.h
@@ -99,8 +99,10 @@ class __wrap_iter
template <class _Up> friend class __wrap_iter;
template <class _CharT, class _Traits, class _Alloc> friend class basic_string;
+ template<class _CharT, class _Traits> friend class basic_string_view;
template <class _Tp, class _Alloc> friend class _LIBCPP_TEMPLATE_VIS vector;
template <class _Tp, size_t> friend class _LIBCPP_TEMPLATE_VIS span;
+ template <class _Tp, size_t _Size> friend struct array;
};
template <class _Iter1>
diff --git a/libcxx/include/array b/libcxx/include/array
index 127092f6bca9b..6311782a516aa 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -120,6 +120,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
#include <__config>
#include <__fwd/array.h>
#include <__iterator/reverse_iterator.h>
+#include <__iterator/wrap_iter.h>
#include <__tuple/sfinae_helpers.h>
#include <__type_traits/conditional.h>
#include <__type_traits/is_array.h>
@@ -164,14 +165,19 @@ template <class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS array
{
// types:
- using __self = array;
- using value_type = _Tp;
- using reference = value_type&;
- using const_reference = const value_type&;
- using iterator = value_type*;
- using const_iterator = const value_type*;
- using pointer = value_type*;
- using const_pointer = const value_type*;
+ using __self = array;
+ using value_type = _Tp;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+#if defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY)
+ using iterator = __wrap_iter<pointer>;
+ using const_iterator = __wrap_iter<const_pointer>;
+#else
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+#endif
using size_type = size_t;
using difference_type = ptrdiff_t;
using reverse_iterator = std::reverse_iterator<iterator>;
diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 3712584a6666d..282ddbc0be9ca 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -215,6 +215,7 @@ namespace std {
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
+#include <__iterator/wrap_iter.h>
#include <__memory/pointer_traits.h>
#include <__ranges/concepts.h>
#include <__ranges/data.h>
@@ -279,10 +280,12 @@ public:
using const_pointer = const _CharT*;
using reference = _CharT&;
using const_reference = const _CharT&;
-#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
+#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS)
using const_iterator = __bounded_iter<const_pointer>;
+#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW)
+ using const_iterator = __wrap_iter<const_pointer>;
#else
- using const_iterator = const_pointer; // See [string.view.iterators]
+ using const_iterator = const_pointer;
#endif
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
@@ -367,7 +370,7 @@ public:
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
return std::__make_bounded_iter(data(), data(), data() + size());
#else
- return __data_;
+ return const_iterator(__data_);
#endif
}
@@ -376,7 +379,7 @@ public:
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
return std::__make_bounded_iter(data() + size(), data(), data() + size());
#else
- return __data_ + __size_;
+ return const_iterator(__data_ + __size_);
#endif
}
diff --git a/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp
index 3936edb8bd083..168fa40a243c5 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/print.fun/transcoding.pass.cpp
@@ -8,6 +8,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: no-filesystem
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
// <print>
@@ -32,9 +33,9 @@ constexpr void test(std::basic_string_view<CharT> expected, std::string_view inp
std::array<CharT, 1024> buffer;
std::ranges::fill(buffer, CharT('*'));
- CharT* out = std::__unicode::__transcode(input.begin(), input.end(), buffer.data());
+ auto out = std::__unicode::__transcode(input.begin(), input.end(), buffer.begin());
- assert(std::basic_string_view<CharT>(buffer.data(), out) == expected);
+ assert(std::basic_string_view<CharT>(buffer.begin(), out) == expected);
out = std::find_if(out, buffer.end(), [](CharT c) { return c != CharT('*'); });
assert(out == buffer.end());
diff --git a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
index 3a335c44ed1e1..0de22022526a6 100644
--- a/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
+++ b/libcxx/test/std/algorithms/robust_against_proxy_iterators_lifetime_bugs.pass.cpp
@@ -547,24 +547,22 @@ class ConstexprIterator {
#endif // TEST_STD_VER > 17
-template <class T, std::size_t N = 32>
+template <class T, std::size_t StorageSize = 32>
class Input {
- using Array = std::array<T, N>;
-
std::size_t size_ = 0;
- Array values_ = {};
+ T values_[StorageSize] = {};
public:
- template <std::size_t N2>
- TEST_CONSTEXPR_CXX20 Input(std::array<T, N2> from) {
- static_assert(N2 <= N, "");
+ template <std::size_t N>
+ TEST_CONSTEXPR_CXX20 Input(std::array<T, N> from) {
+ static_assert(N <= StorageSize, "");
std::copy(from.begin(), from.end(), begin());
- size_ = N2;
+ size_ = N;
}
- TEST_CONSTEXPR_CXX20 typename Array::iterator begin() { return values_.begin(); }
- TEST_CONSTEXPR_CXX20 typename Array::iterator end() { return values_.begin() + size_; }
+ TEST_CONSTEXPR_CXX20 T* begin() { return values_; }
+ TEST_CONSTEXPR_CXX20 T* end() { return values_ + size_; }
TEST_CONSTEXPR_CXX20 std::size_t size() const { return size_; }
};
diff --git a/libcxx/test/std/containers/sequences/array/types.pass.cpp b/libcxx/test/std/containers/sequences/array/types.pass.cpp
index f86e008d2e8de..c509810507962 100644
--- a/libcxx/test/std/containers/sequences/array/types.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/types.pass.cpp
@@ -54,8 +54,6 @@ int main(int, char**)
typedef std::array<T, 10> C;
static_assert((std::is_same<C::reference, T&>::value), "");
static_assert((std::is_same<C::const_reference, const T&>::value), "");
- LIBCPP_STATIC_ASSERT((std::is_same<C::iterator, T*>::value), "");
- LIBCPP_STATIC_ASSERT((std::is_same<C::const_iterator, const T*>::value), "");
test_iterators<C>();
static_assert((std::is_same<C::pointer, T*>::value), "");
static_assert((std::is_same<C::const_pointer, const T*>::value), "");
@@ -76,8 +74,6 @@ int main(int, char**)
typedef std::array<T, 0> C;
static_assert((std::is_same<C::reference, T&>::value), "");
static_assert((std::is_same<C::const_reference, const T&>::value), "");
- LIBCPP_STATIC_ASSERT((std::is_same<C::iterator, T*>::value), "");
- LIBCPP_STATIC_ASSERT((std::is_same<C::const_iterator, const T*>::value), "");
test_iterators<C>();
static_assert((std::is_same<C::pointer, T*>::value), "");
static_assert((std::is_same<C::const_pointer, const T*>::value), "");
diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
index 73b13ccc34cf8..e893b5ae62874 100644
--- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
@@ -114,7 +114,10 @@ class throw_operator_minus {
friend difference_type operator-(throw_operator_minus, throw_operator_minus) { throw 42; };
friend bool operator==(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ == y.it_; }
- friend auto operator<=>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <=> y.it_; }
+ friend bool operator<(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ < y.it_; }
+ friend bool operator>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ > y.it_; }
+ friend bool operator<=(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <= y.it_; }
+ friend bool operator>=(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ >= y.it_; }
};
template <class It>
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
index 87e2f9628757b..2df7834477291 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -61,7 +61,7 @@ void test(std::basic_string_view<CharT> fmt, ArithmeticT arg, std::basic_string<
if (expected.empty()) {
std::array<char, 128> buffer;
- expected.append(buffer.begin(), std::to_chars(buffer.begin(), buffer.end(), arg).ptr);
+ expected.append(buffer.data(), std::to_chars(buffer.data(), buffer.data() + buffer.size(), arg).ptr);
}
assert(result == expected);
@@ -84,321 +84,401 @@ void test_termination_condition(StringT f, ArithmeticT arg, StringT expected = {
template <class CharT, class ArithmeticT>
void test_hex_lower_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
- test_termination_condition(STR(".20000a}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000a}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000a}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
- test_termination_condition(STR(".20000La}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000La}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000La}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_hex_upper_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000A}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000A}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000A}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000LA}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::hex, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000LA}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000LA}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_scientific_lower_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
- test_termination_condition(STR(".20000e}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000e}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000e}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
- test_termination_condition(STR(".20000Le}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000Le}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000Le}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_scientific_upper_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000E}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000E}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000E}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000LE}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::scientific, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000LE}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000LE}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_fixed_lower_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
- test_termination_condition(STR(".20000f}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000f}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000f}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
- test_termination_condition(STR(".20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000Lf}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_fixed_upper_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000F}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000F}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000F}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000LF}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::fixed, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000LF}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000LF}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_general_lower_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
- test_termination_condition(STR(".20000g}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000g}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000g}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
- test_termination_condition(STR(".20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ test_termination_condition(STR(".20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000Lg}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
template <class CharT, class ArithmeticT>
void test_general_upper_case_precision(ArithmeticT value) {
- std::array<char, 25'000> buffer;
- char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000G}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- std::size_t size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000G}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000G}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+
#ifndef TEST_HAS_NO_LOCALIZATION
- end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr;
- std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
- test_termination_condition(STR(".20000LG}"), value, std::basic_string<CharT>{buffer.begin(), end});
-
- size = buffer.end() - end;
- std::fill_n(end, size, '#');
- test_termination_condition(STR("#<25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end());
- test_termination_condition(STR("#^25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end());
- test_termination_condition(STR("#>25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
- std::fill_n(buffer.begin(), size, '0');
- if (std::signbit(value)) {
- buffer[0] = '-';
- buffer[size] = '0';
+ {
+ std::array<char, 25'000> buffer;
+ char* end_ptr = std::to_chars(buffer.data(), buffer.data() + buffer.size(), value, std::chars_format::general, 20'000).ptr;
+ std::size_t size = end_ptr - buffer.data();
+ auto end = buffer.begin() + size;
+ std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); });
+ test_termination_condition(STR(".20000LG}"), value, std::basic_string<CharT>{buffer.begin(), end});
+
+ std::size_t unused = buffer.end() - end;
+ std::fill_n(end, unused, '#');
+ test_termination_condition(STR("#<25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - (unused / 2), buffer.end());
+ test_termination_condition(STR("#^25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::rotate(buffer.begin(), buffer.end() - ((unused + 1) / 2), buffer.end());
+ test_termination_condition(STR("#>25000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
+ std::fill_n(buffer.begin(), unused, '0');
+ if (std::signbit(value)) {
+ buffer[0] = '-';
+ buffer[unused] = '0';
+ }
+ test_termination_condition(STR("025000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
}
- test_termination_condition(STR("025000.20000LG}"), value, std::basic_string<CharT>{buffer.begin(), buffer.end()});
#endif
}
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
index 347458d7d7562..ff5bfe0fb472a 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.pointer.pass.cpp
@@ -58,8 +58,8 @@ void test(StringT expected, StringViewT fmt, PointerT arg, std::size_t offset) {
std::array<char, 128> buffer;
buffer[0] = CharT('0');
buffer[1] = CharT('x');
- expected.append(buffer.begin(),
- std::to_chars(buffer.begin() + 2, buffer.end(), reinterpret_cast<std::uintptr_t>(arg), 16).ptr);
+ expected.append(buffer.data(),
+ std::to_chars(buffer.data() + 2, buffer.data() + buffer.size(), reinterpret_cast<std::uintptr_t>(arg), 16).ptr);
}
assert(result == expected);
}
More information about the libcxx-commits
mailing list