[libc++] Add noexcept clauses to swap per P0408R7 (Efficient Access to basic_stringbu...
authorPiotr Fusik <fox@scene.pl>
Sat, 24 Jun 2023 16:27:06 +0000 (18:27 +0200)
committerMark de Wever <koraq@xs4all.nl>
Sat, 24 Jun 2023 16:29:21 +0000 (18:29 +0200)
Reviewed By: #libc, Mordante

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

libcxx/include/sstream
libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/member_swap_noexcept.pass.cpp [new file with mode: 0644]
libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/nonmember_swap_noexcept.pass.cpp [new file with mode: 0644]

index 26c8992..05756eb 100644 (file)
@@ -36,7 +36,7 @@ public:
 
     // [stringbuf.assign] Assign and swap:
     basic_stringbuf& operator=(basic_stringbuf&& rhs);
-    void swap(basic_stringbuf& rhs);
+    void swap(basic_stringbuf& rhs) noexcept(see below);                               // conditionally noexcept since C++20
 
     // [stringbuf.members] Member functions:
     basic_string<char_type, traits_type, allocator_type> str() const;
@@ -57,8 +57,8 @@ protected:
 
 // [stringbuf.assign] non member swap
 template <class charT, class traits, class Allocator>
-  void swap(basic_stringbuf<charT, traits, Allocator>& x,
-            basic_stringbuf<charT, traits, Allocator>& y);
+void swap(basic_stringbuf<charT, traits, Allocator>& x,
+          basic_stringbuf<charT, traits, Allocator>& y); // conditionally noexcept since C++20
 
 typedef basic_stringbuf<char>    stringbuf;
 typedef basic_stringbuf<wchar_t> wstringbuf;
@@ -97,8 +97,8 @@ public:
 };
 
 template <class charT, class traits, class Allocator>
-  void swap(basic_istringstream<charT, traits, Allocator>& x,
-            basic_istringstream<charT, traits, Allocator>& y);
+void swap(basic_istringstream<charT, traits, Allocator>& x,
+          basic_istringstream<charT, traits, Allocator>& y);
 
 typedef basic_istringstream<char>    istringstream;
 typedef basic_istringstream<wchar_t> wistringstream;
@@ -138,8 +138,8 @@ public:
 };
 
 template <class charT, class traits, class Allocator>
-  void swap(basic_ostringstream<charT, traits, Allocator>& x,
-            basic_ostringstream<charT, traits, Allocator>& y);
+void swap(basic_ostringstream<charT, traits, Allocator>& x,
+          basic_ostringstream<charT, traits, Allocator>& y);
 
 typedef basic_ostringstream<char>    ostringstream;
 typedef basic_ostringstream<wchar_t> wostringstream;
@@ -179,8 +179,8 @@ public:
 };
 
 template <class charT, class traits, class Allocator>
-  void swap(basic_stringstream<charT, traits, Allocator>& x,
-            basic_stringstream<charT, traits, Allocator>& y);
+void swap(basic_stringstream<charT, traits, Allocator>& x,
+          basic_stringstream<charT, traits, Allocator>& y);
 
 typedef basic_stringstream<char>    stringstream;
 typedef basic_stringstream<wchar_t> wstringstream;
@@ -252,7 +252,12 @@ public:
 
     // [stringbuf.assign] Assign and swap:
     basic_stringbuf& operator=(basic_stringbuf&& __rhs);
-    void swap(basic_stringbuf& __rhs);
+    void swap(basic_stringbuf& __rhs)
+#if _LIBCPP_STD_VER >= 20
+        noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
+                 allocator_traits<allocator_type>::is_always_equal::value)
+#endif
+        ;
 
     // [stringbuf.members] Member functions:
     string_type str() const;
@@ -368,6 +373,10 @@ basic_stringbuf<_CharT, _Traits, _Allocator>::operator=(basic_stringbuf&& __rhs)
 template <class _CharT, class _Traits, class _Allocator>
 void
 basic_stringbuf<_CharT, _Traits, _Allocator>::swap(basic_stringbuf& __rhs)
+#if _LIBCPP_STD_VER >= 20
+    noexcept(allocator_traits<_Allocator>::propagate_on_container_swap::value ||
+             allocator_traits<_Allocator>::is_always_equal::value)
+#endif
 {
     char_type* __p = const_cast<char_type*>(__rhs.__str_.data());
     ptrdiff_t __rbinp = -1;
@@ -447,6 +456,9 @@ inline _LIBCPP_INLINE_VISIBILITY
 void
 swap(basic_stringbuf<_CharT, _Traits, _Allocator>& __x,
      basic_stringbuf<_CharT, _Traits, _Allocator>& __y)
+#if _LIBCPP_STD_VER >= 20
+    noexcept(noexcept(__x.swap(__y)))
+#endif
 {
     __x.swap(__y);
 }
diff --git a/libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/member_swap_noexcept.pass.cpp b/libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/member_swap_noexcept.pass.cpp
new file mode 100644 (file)
index 0000000..cdb09df
--- /dev/null
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <sstream>
+
+// template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
+// class basic_stringbuf
+
+// void swap(basic_stringbuf& rhs)
+//   noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
+//            allocator_traits<allocator_type>::is_always_equal::value);
+
+#include <sstream>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <class T>
+struct test_alloc {
+  using value_type = T;
+
+  [[nodiscard]] constexpr T* allocate(std::size_t) { return nullptr; }
+  void deallocate(void*, unsigned) {}
+};
+
+template <class T>
+struct test_alloc_propagate_on_container_swap : test_alloc<T> {
+  using propagate_on_container_swap = std::true_type;
+};
+
+template <class T>
+struct test_alloc_is_always_equal : test_alloc<T> {
+  using is_always_equal = std::true_type;
+};
+
+template <class T>
+struct test_alloc_propagate_on_container_swap_is_always_equal : test_alloc<T> {
+  using propagate_on_container_swap = std::true_type;
+  using is_always_equal             = std::true_type;
+};
+
+template <class T>
+struct test_alloc_not_empty : test_alloc<T> {
+  bool dummy;
+};
+
+template <class T>
+struct test_alloc_propagate_on_container_swap_not_empty : test_alloc<T> {
+  using propagate_on_container_swap = std::true_type;
+  bool dummy;
+};
+
+template <class CharT>
+static void test() {
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc<CharT>> buf;
+    static_assert(noexcept(buf.swap(buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap<CharT>> buf;
+    static_assert(noexcept(buf.swap(buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_is_always_equal<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_is_always_equal<CharT>> buf;
+    static_assert(noexcept(buf.swap(buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_is_always_equal<CharT>>
+        buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_is_always_equal<CharT>>
+        buf;
+    static_assert(noexcept(buf.swap(buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf;
+    static_assert(!noexcept(buf.swap(buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_not_empty<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_not_empty<CharT>> buf;
+    static_assert(noexcept(buf.swap(buf1)));
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/nonmember_swap_noexcept.pass.cpp b/libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/nonmember_swap_noexcept.pass.cpp
new file mode 100644 (file)
index 0000000..fdefc5e
--- /dev/null
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <sstream>
+
+// template <class charT, class traits, class Allocator>
+// void swap(basic_stringbuf<charT, traits, Allocator>& x,
+//           basic_stringbuf<charT, traits, Allocator>& y)
+//   noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
+//            allocator_traits<allocator_type>::is_always_equal::value);
+
+#include <sstream>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <class T>
+struct test_alloc {
+  using value_type = T;
+
+  [[nodiscard]] constexpr T* allocate(std::size_t) { return nullptr; }
+  void deallocate(void*, unsigned) {}
+};
+
+template <class T>
+struct test_alloc_propagate_on_container_swap : test_alloc<T> {
+  using propagate_on_container_swap = std::true_type;
+};
+
+template <class T>
+struct test_alloc_is_always_equal : test_alloc<T> {
+  using is_always_equal = std::true_type;
+};
+
+template <class T>
+struct test_alloc_propagate_on_container_swap_is_always_equal : test_alloc<T> {
+  using propagate_on_container_swap = std::true_type;
+  using is_always_equal             = std::true_type;
+};
+
+template <class T>
+struct test_alloc_not_empty : test_alloc<T> {
+  bool dummy;
+};
+
+template <class T>
+struct test_alloc_propagate_on_container_swap_not_empty : test_alloc<T> {
+  using propagate_on_container_swap = std::true_type;
+  bool dummy;
+};
+
+template <class CharT>
+static void test() {
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc<CharT>> buf;
+    static_assert(noexcept(swap(buf, buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap<CharT>> buf;
+    static_assert(noexcept(swap(buf, buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_is_always_equal<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_is_always_equal<CharT>> buf;
+    static_assert(noexcept(swap(buf, buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_is_always_equal<CharT>>
+        buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_is_always_equal<CharT>>
+        buf;
+    static_assert(noexcept(swap(buf, buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf;
+    static_assert(!noexcept(swap(buf, buf1)));
+  }
+  {
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_not_empty<CharT>> buf1;
+    std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_not_empty<CharT>> buf;
+    static_assert(noexcept(swap(buf, buf1)));
+  }
+}
+
+int main(int, char**) {
+  test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#endif
+  return 0;
+}