1 // { dg-options "-std=gnu++23" }
2 // { dg-do run { target { c++23 && cxx11_abi } } }
3 
4 #include <string>
5 
6 #ifndef __cpp_lib_string_resize_and_overwrite
7 #error "Feature test macro for resize_and_overwrite is missing in <string>"
8 #elif __cpp_lib_string_resize_and_overwrite != 202110L
9 # error "Feature test macro for resize_and_overwrite has wrong value in <string>"
10 #endif
11 
12 
13 #include <cstring>
14 #include <testsuite_hooks.h>
15 
16 // P1072R10 basic_string::resize_and_overwrite
17 
18 void
test01()19 test01()
20 {
21   std::string s = "foo";
22   s.resize_and_overwrite(99, [](char* p, int n) {
23     VERIFY( n == 99 );
24     VERIFY( !std::strncmp(p, "foo", 3) );
25     std::strcpy(p, "monkey tennis");
26     return 6;
27   });
28   VERIFY( s == "monkey" );
29   VERIFY( s.size() == 6 );
30   VERIFY( s.capacity() >= 99 );
31   VERIFY( s[6] == '\0' );
32 
33   const auto str = s.data();
34 
35   s.resize_and_overwrite(50, [](char* p, int n) -> unsigned {
36     VERIFY( n == 50 );
37     VERIFY( !std::strncmp(p, "monkey", 3) );
38     std::strcpy(p, "Partridge among the pidgeons");
39     return 9;
40   });
41   VERIFY( s.data() == str ); // No reallocation
42   VERIFY( s == "Partridge" );
43   VERIFY( s[9] == '\0' );
44 }
45 
46 void
test02()47 test02()
48 {
49   std::string s;
50   auto p = s.data();
51   s.resize_and_overwrite(0, [](auto...) { return 0; });
52   VERIFY( s.empty() );
53   VERIFY( s[0] == '\0' );
54   VERIFY( s.data() == p );
55 
56   s = "short string";
57   p = s.data();
58   s.resize_and_overwrite(0, [](auto...) { return 0; });
59   VERIFY( s.empty() );
60   VERIFY( s[0] == '\0' );
61   VERIFY( s.data() == p );
62 
63   s = "a string that is long enough to not be a short string";
64   p = s.data();
65   s.resize_and_overwrite(0, [](auto...) { return 0; });
66   VERIFY( s.empty() );
67   VERIFY( s[0] == '\0' );
68   VERIFY( s.data() == p );
69 }
70 
71 void
test03()72 test03()
73 {
74   struct Op
75   {
76     int operator()(char*, int) & = delete;
77     int operator()(char*, int) const & = delete;
78     int operator()(char* p, int n) && { std::memset(p, 'a', n+1); return n; }
79     int operator()(char*, int) const && = delete;
80   };
81   std::string s;
82   s.resize_and_overwrite(42, Op{});
83   VERIFY( s.size() == 42 );
84   VERIFY( s == std::string(42, 'a') );
85   VERIFY( s[42] == '\0' );
86 
87   s.resize_and_overwrite(0, [](auto&& p, auto&& n) {
88     static_assert( std::is_same_v<decltype(p), char*&> );
89     static_assert( std::is_same_v<decltype(n), std::string::size_type&> );
90     return 0;
91   });
92 }
93 
94 void
test04()95 test04()
96 {
97   std::string s = "this tests how the library copes with undefined behaviour";
98 
99   try {
100     s.resize_and_overwrite(13, [](auto...) -> int { throw "undefined"; });
101   } catch (...) {
102     // The standard doesn't require this, but we leave the string empty:
103     VERIFY( s.size() == 0 );
104     VERIFY( s[0] == '\0' );
105   }
106 }
107 
108 constexpr bool
test05()109 test05()
110 {
111   std::string s;
112   s.resize_and_overwrite(20, [](char* p, auto n) {
113     *p = '!'; // direct assignment should be OK
114     std::char_traits<char>::copy(p, "constexpr", 9);
115     return 9;
116   });
117   VERIFY( s == "constexpr" );
118   return true;
119 }
120 
main()121 int main()
122 {
123   test01();
124   test02();
125   test03();
126   test04();
127   static_assert( test05() );
128 }
129