[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