1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: no-localization
11 // UNSUPPORTED: libcpp-has-no-experimental-syncstream
12
13 // <syncstream>
14
15 // template <class charT, class traits, class Allocator>
16 // class basic_syncbuf;
17
18 // void swap(basic_syncbuf& other) noexcept;
19
20 #include <syncstream>
21 #include <sstream>
22 #include <cassert>
23
24 #include "test_macros.h"
25
26 #include <iostream>
27
28 template <class CharT>
test_basic()29 static void test_basic() {
30 std::basic_stringbuf<CharT> sstr1;
31 std::basic_stringbuf<CharT> sstr2;
32 std::basic_string<CharT> expected(42, CharT('*')); // a long string
33
34 {
35 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
36 sync_buf1.sputc(CharT('A')); // a short string
37
38 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
39 sync_buf2.sputn(expected.data(), expected.size());
40
41 #if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
42 assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);
43 assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 1);
44 #endif
45
46 sync_buf1.swap(sync_buf2);
47 assert(sync_buf1.get_wrapped() == &sstr2);
48 assert(sync_buf2.get_wrapped() == &sstr1);
49
50 assert(sstr1.str().empty());
51 assert(sstr2.str().empty());
52
53 #if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)
54 assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);
55 assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 1);
56 #endif
57 }
58
59 assert(sstr1.str().size() == 1);
60 assert(sstr1.str()[0] == CharT('A'));
61 assert(sstr2.str() == expected);
62 }
63
64 template <class CharT>
test_short_write_after_swap()65 static void test_short_write_after_swap() {
66 std::basic_stringbuf<CharT> sstr1;
67 std::basic_stringbuf<CharT> sstr2;
68 std::basic_string<CharT> expected(42, CharT('*')); // a long string
69
70 {
71 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
72 sync_buf1.sputc(CharT('A')); // a short string
73
74 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
75 sync_buf2.sputn(expected.data(), expected.size());
76
77 sync_buf1.swap(sync_buf2);
78 sync_buf1.sputc(CharT('B'));
79 expected.push_back(CharT('B'));
80 sync_buf2.sputc(CharT('Z'));
81
82 assert(sstr1.str().empty());
83 assert(sstr2.str().empty());
84 }
85
86 assert(sstr1.str().size() == 2);
87 assert(sstr1.str()[0] == CharT('A'));
88 assert(sstr1.str()[1] == CharT('Z'));
89 assert(sstr2.str() == expected);
90 }
91
92 template <class CharT>
test_long_write_after_swap()93 static void test_long_write_after_swap() {
94 std::basic_stringbuf<CharT> sstr1;
95 std::basic_stringbuf<CharT> sstr2;
96 std::basic_string<CharT> expected(42, CharT('*')); // a long string
97
98 {
99 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
100 sync_buf1.sputc(CharT('A')); // a short string
101
102 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
103 sync_buf2.sputn(expected.data(), expected.size());
104
105 sync_buf1.swap(sync_buf2);
106 sync_buf1.sputn(expected.data(), expected.size());
107 sync_buf2.sputn(expected.data(), expected.size());
108
109 assert(sstr1.str().empty());
110 assert(sstr2.str().empty());
111 }
112
113 assert(sstr1.str().size() == 1 + expected.size());
114 assert(sstr1.str()[0] == CharT('A'));
115 assert(sstr1.str().substr(1) == expected);
116 assert(sstr2.str() == expected + expected);
117 }
118
119 template <class CharT>
test_emit_on_sync()120 static void test_emit_on_sync() {
121 { // false false
122
123 std::basic_stringbuf<CharT> sstr1;
124 std::basic_stringbuf<CharT> sstr2;
125 std::basic_string<CharT> expected(42, CharT('*')); // a long string
126
127 {
128 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
129 sync_buf1.set_emit_on_sync(false);
130 sync_buf1.sputc(CharT('A')); // a short string
131
132 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
133 sync_buf2.set_emit_on_sync(false);
134 sync_buf2.sputn(expected.data(), expected.size());
135
136 sync_buf1.swap(sync_buf2);
137
138 assert(sstr1.str().empty());
139 assert(sstr2.str().empty());
140
141 sync_buf1.pubsync();
142 assert(sstr1.str().empty());
143 assert(sstr2.str().empty());
144
145 sync_buf2.pubsync();
146 assert(sstr1.str().empty());
147 assert(sstr2.str().empty());
148 }
149
150 assert(sstr1.str().size() == 1);
151 assert(sstr1.str()[0] == CharT('A'));
152 assert(sstr2.str() == expected);
153 }
154
155 { // false true
156
157 std::basic_stringbuf<CharT> sstr1;
158 std::basic_stringbuf<CharT> sstr2;
159 std::basic_string<CharT> expected(42, CharT('*')); // a long string
160
161 {
162 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
163 sync_buf1.set_emit_on_sync(true);
164 sync_buf1.sputc(CharT('A')); // a short string
165
166 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
167 sync_buf2.set_emit_on_sync(false);
168 sync_buf2.sputn(expected.data(), expected.size());
169
170 sync_buf1.swap(sync_buf2);
171
172 assert(sstr1.str().empty());
173 assert(sstr2.str().empty());
174
175 sync_buf1.pubsync();
176 assert(sstr1.str().empty());
177 assert(sstr2.str().empty());
178
179 sync_buf2.pubsync();
180 assert(sstr1.str().size() == 1);
181 assert(sstr1.str()[0] == CharT('A'));
182 assert(sstr2.str().empty());
183 }
184
185 assert(sstr1.str().size() == 1);
186 assert(sstr1.str()[0] == CharT('A'));
187 assert(sstr2.str() == expected);
188 }
189
190 { // true false
191
192 std::basic_stringbuf<CharT> sstr1;
193 std::basic_stringbuf<CharT> sstr2;
194 std::basic_string<CharT> expected(42, CharT('*')); // a long string
195
196 {
197 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
198 sync_buf1.set_emit_on_sync(false);
199 sync_buf1.sputc(CharT('A')); // a short string
200
201 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
202 sync_buf2.set_emit_on_sync(true);
203 sync_buf2.sputn(expected.data(), expected.size());
204
205 sync_buf1.swap(sync_buf2);
206
207 assert(sstr1.str().empty());
208 assert(sstr2.str().empty());
209
210 sync_buf1.pubsync();
211 assert(sstr1.str().empty());
212 assert(sstr2.str() == expected);
213
214 sync_buf2.pubsync();
215 assert(sstr1.str().empty());
216 assert(sstr2.str() == expected);
217 }
218
219 assert(sstr1.str().size() == 1);
220 assert(sstr1.str()[0] == CharT('A'));
221 assert(sstr2.str() == expected);
222 }
223
224 { // true true
225
226 std::basic_stringbuf<CharT> sstr1;
227 std::basic_stringbuf<CharT> sstr2;
228 std::basic_string<CharT> expected(42, CharT('*')); // a long string
229
230 {
231 std::basic_syncbuf<CharT> sync_buf1(&sstr1);
232 sync_buf1.set_emit_on_sync(true);
233 sync_buf1.sputc(CharT('A')); // a short string
234
235 std::basic_syncbuf<CharT> sync_buf2(&sstr2);
236 sync_buf2.set_emit_on_sync(true);
237 sync_buf2.sputn(expected.data(), expected.size());
238
239 sync_buf1.swap(sync_buf2);
240
241 assert(sstr1.str().empty());
242 assert(sstr2.str().empty());
243
244 sync_buf1.pubsync();
245 assert(sstr1.str().empty());
246 assert(sstr2.str() == expected);
247
248 sync_buf2.pubsync();
249 assert(sstr1.str().size() == 1);
250 assert(sstr1.str()[0] == CharT('A'));
251 assert(sstr2.str() == expected);
252 }
253
254 assert(sstr1.str().size() == 1);
255 assert(sstr1.str()[0] == CharT('A'));
256 assert(sstr2.str() == expected);
257 }
258 }
259
260 template <class CharT>
test()261 static void test() {
262 test_basic<CharT>();
263 test_emit_on_sync<CharT>();
264 test_short_write_after_swap<CharT>();
265 test_long_write_after_swap<CharT>();
266 }
267
main(int,char **)268 int main(int, char**) {
269 test<char>();
270 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
271 test<wchar_t>();
272 #endif
273
274 return 0;
275 }
276