[libcxx-commits] [libcxx] 91dd072 - [libc++][format] Move iterators when needed.
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 18 09:45:47 PDT 2022
Author: Mark de Wever
Date: 2022-10-18T18:45:41+02:00
New Revision: 91dd07235411ec7743311298546c4f3f767930f3
URL: https://github.com/llvm/llvm-project/commit/91dd07235411ec7743311298546c4f3f767930f3
DIFF: https://github.com/llvm/llvm-project/commit/91dd07235411ec7743311298546c4f3f767930f3.diff
LOG: [libc++][format] Move iterators when needed.
LWG-3539 was already implemented but not marked as done.
LWG-3567 is implemented in this commit.
Reviewed By: ldionne, #libc
Differential Revision: https://reviews.llvm.org/D112368
Added:
Modified:
libcxx/docs/Status/Cxx2bIssues.csv
libcxx/include/__format/buffer.h
libcxx/include/__format/format_context.h
libcxx/test/std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp
libcxx/test/std/utilities/format/format.formatter/format.context/format.context/out.pass.cpp
libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index f039c25e953c6..1a297190e98d6 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -83,7 +83,7 @@
`3532 <https://wg21.link/LWG3532>`__,"``split_view<V, P>::inner-iterator<true>::operator++(int)`` should depend on ``Base``","June 2021","","","|ranges|"
`3533 <https://wg21.link/LWG3533>`__,"Make ``base() const &`` consistent across iterator wrappers that supports ``input_iterators``","June 2021","|Complete|","14.0","|ranges|"
`3536 <https://wg21.link/LWG3536>`__,"Should ``chrono::from_stream()`` assign zero to duration for failure?","June 2021","","","|chrono|"
-`3539 <https://wg21.link/LWG3539>`__,"``format_to`` must not copy models of ``output_iterator<const charT&>``","June 2021","","","|format|"
+`3539 <https://wg21.link/LWG3539>`__,"``format_to`` must not copy models of ``output_iterator<const charT&>``","June 2021","|Complete|","14.0","|format|"
`3540 <https://wg21.link/LWG3540>`__,"ยง[format.arg] There should be no const in ``basic_format_arg(const T* p)``","June 2021","|Complete|","14.0","|format|"
`3541 <https://wg21.link/LWG3541>`__,"``indirectly_readable_traits`` should be SFINAE-friendly for all types","June 2021","|Complete|","14.0","|ranges|"
`3542 <https://wg21.link/LWG3542>`__,"``basic_format_arg`` mishandles ``basic_string_view`` with custom traits","June 2021","|Complete|","14.0","|format|"
@@ -120,7 +120,7 @@
`3561 <https://wg21.link/LWG3561>`__,"Issue with internal counter in ``discard_block_engine``","October 2021","",""
`3563 <https://wg21.link/LWG3563>`__,"``keys_view`` example is broken","October 2021","","","|ranges|"
`3566 <https://wg21.link/LWG3566>`__,"Constraint recursion for ``operator<=>(optional<T>, U)``","October 2021","","","|spaceship|"
-`3567 <https://wg21.link/LWG3567>`__,"Formatting move-only iterators take two","October 2021","","","|format|"
+`3567 <https://wg21.link/LWG3567>`__,"Formatting move-only iterators take two","October 2021","|Complete|","16.0","|format|"
`3568 <https://wg21.link/LWG3568>`__,"``basic_istream_view`` needs to initialize ``value_``","October 2021","|Complete|","16.0","|ranges|"
`3570 <https://wg21.link/LWG3570>`__,"``basic_osyncstream::emit`` should be an unformatted output function","October 2021","",""
`3571 <https://wg21.link/LWG3571>`__,"``flush_emit`` should set ``badbit`` if the ``emit`` call fails","October 2021","",""
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index 504f87106c561..4f7577eb06055 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -14,6 +14,7 @@
#include <__algorithm/fill_n.h>
#include <__algorithm/max.h>
#include <__algorithm/min.h>
+#include <__algorithm/ranges_copy_n.h>
#include <__algorithm/transform.h>
#include <__algorithm/unwrap_iter.h>
#include <__config>
@@ -275,10 +276,10 @@ class _LIBCPP_TEMPLATE_VIS __writer_iterator {
_LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it)
: __out_it_{_VSTD::move(__out_it)} {}
- _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
+ _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
- __out_it_ = _VSTD::copy_n(__ptr, __n, _VSTD::move(__out_it_));
+ __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;
}
private:
diff --git a/libcxx/include/__format/format_context.h b/libcxx/include/__format/format_context.h
index 37d4fe1eb5c54..19468de45ca37 100644
--- a/libcxx/include/__format/format_context.h
+++ b/libcxx/include/__format/format_context.h
@@ -100,8 +100,8 @@ class
return *__loc_;
}
#endif
- _LIBCPP_HIDE_FROM_ABI iterator out() { return __out_it_; }
- _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = __it; }
+ _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
+ _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
private:
iterator __out_it_;
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp
index 04f3f50be5999..e61188ab84f9d 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp
@@ -18,18 +18,20 @@
#include "test_macros.h"
#include "test_format_context.h"
+#include "test_iterators.h"
template <class OutIt, class CharT>
void test(
std::basic_format_args<std::basic_format_context<OutIt, CharT>> args) {
{
- std::basic_string<CharT> str[3];
- std::basic_format_context context = test_format_context_create(OutIt{str[0]}, args);
- context.out() = CharT('a');
- context.advance_to(OutIt{str[1]});
- context.out() = CharT('b');
- context.advance_to(OutIt{str[2]});
- context.out() = CharT('c');
+ std::basic_string<CharT> str[3] = {
+ std::basic_string<CharT>{1}, std::basic_string<CharT>{1}, std::basic_string<CharT>{1}};
+ std::basic_format_context context = test_format_context_create(OutIt{str[0].begin()}, args);
+ *context.out() = CharT('a');
+ context.advance_to(OutIt{str[1].begin()});
+ *context.out() = CharT('b');
+ context.advance_to(OutIt{str[2].begin()});
+ *context.out() = CharT('c');
assert(str[0].size() == 1);
assert(str[0].front() == CharT('a'));
@@ -42,27 +44,25 @@ void test(
void test() {
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char>>, char>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char>::iterator>, char>>()));
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<wchar_t>::iterator>, wchar_t>>()));
#endif
#ifndef TEST_HAS_NO_CHAR8_T
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char8_t>::iterator>, char8_t>>()));
#endif
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char16_t>>,
- char16_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char16_t>::iterator>, char16_t>>()));
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char32_t>>,
- char32_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char32_t>::iterator>, char32_t>>()));
}
int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/out.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/out.pass.cpp
index c358a33083ce0..effcec78ebe77 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/out.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/out.pass.cpp
@@ -18,17 +18,20 @@
#include "test_macros.h"
#include "test_format_context.h"
+#include "test_iterators.h"
template <class OutIt, class CharT>
void test(
std::basic_format_args<std::basic_format_context<OutIt, CharT>> args) {
{
- std::basic_string<CharT> str;
- OutIt out_it{str};
- std::basic_format_context context = test_format_context_create(out_it, args);
- context.out() = CharT('a');
- context.out() = CharT('b');
- context.out() = CharT('c');
+ std::basic_string<CharT> str = std::basic_string<CharT>(3, CharT(' '));
+ std::basic_format_context context = test_format_context_create(OutIt{str.begin()}, args);
+
+ // Note this operation is moving the iterator
+ OutIt out_it = context.out();
+ *out_it++ = CharT('a');
+ *out_it++ = CharT('b');
+ *out_it++ = CharT('c');
assert(str.size() == 3);
assert(str[0] == CharT('a'));
@@ -39,26 +42,25 @@ void test(
void test() {
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char>>, char>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char>::iterator>, char>>()));
+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<wchar_t>::iterator>, wchar_t>>()));
#endif
#ifndef TEST_HAS_NO_CHAR8_T
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char8_t>::iterator>, char8_t>>()));
#endif
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char16_t>>,
- char16_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char16_t>::iterator>, char16_t>>()));
test(std::basic_format_args(
- std::make_format_args<std::basic_format_context<
- std::back_insert_iterator<std::basic_string<char32_t>>,
- char32_t>>()));
+ std::make_format_args<
+ std::basic_format_context<cpp20_output_iterator<std::basic_string<char32_t>::iterator>, char32_t>>()));
}
int main(int, char**) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
index f94bfef17aaa1..b4726c280aa25 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
@@ -32,6 +32,7 @@
#include "format_tests.h"
#include "string_literal.h"
#include "test_format_string.h"
+#include "test_iterators.h"
auto test =
[]<class CharT, class... Args>(
@@ -55,10 +56,11 @@ auto test =
{
assert(expected.size() < 4096 && "Update the size of the buffer.");
CharT out[4096];
- CharT* it = std::format_to(out, std::locale(), fmt, std::forward<Args>(args)...);
- assert(std::distance(out, it) == int(expected.size()));
+ cpp20_output_iterator<CharT*> it =
+ std::format_to(cpp20_output_iterator{out}, std::locale(), fmt, std::forward<Args>(args)...);
+ assert(std::distance(out, base(it)) == int(expected.size()));
// Convert to std::string since output contains '\0' for boolean tests.
- assert(std::basic_string<CharT>(out, it) == expected);
+ assert(std::basic_string<CharT>(out, base(it)) == expected);
}
};
diff --git a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
index 0fbd6654ef513..04e4f1f4c61bb 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
@@ -29,6 +29,7 @@
#include "format_tests.h"
#include "string_literal.h"
#include "test_format_string.h"
+#include "test_iterators.h"
auto test =
[]<class CharT, class... Args>(
@@ -52,10 +53,10 @@ auto test =
{
assert(expected.size() < 4096 && "Update the size of the buffer.");
CharT out[4096];
- CharT* it = std::format_to(out, fmt, std::forward<Args>(args)...);
- assert(std::distance(out, it) == int(expected.size()));
+ cpp20_output_iterator<CharT*> it = std::format_to(cpp20_output_iterator{out}, fmt, std::forward<Args>(args)...);
+ assert(std::distance(out, base(it)) == int(expected.size()));
// Convert to std::string since output contains '\0' for boolean tests.
- assert(std::basic_string<CharT>(out, it) == expected);
+ assert(std::basic_string<CharT>(out, base(it)) == expected);
}
};
More information about the libcxx-commits
mailing list