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