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_osyncstream; |
17 | |
18 | // basic_osyncstream& operator=(basic_osyncstream&& rhs); |
19 | |
20 | #include <syncstream> |
21 | #include <sstream> |
22 | #include <cassert> |
23 | |
24 | #include "test_macros.h" |
25 | #include "test_allocator.h" |
26 | |
27 | template <class CharT, bool propagate> |
28 | static void test() { |
29 | using Traits = std::char_traits<CharT>; |
30 | using Allocator = std::conditional_t<propagate, other_allocator<CharT>, test_allocator<CharT>>; |
31 | static_assert(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value == propagate); |
32 | |
33 | using OS = std::basic_osyncstream<CharT, Traits, Allocator>; |
34 | |
35 | std::basic_stringbuf<CharT, Traits, Allocator> base1; |
36 | std::basic_stringbuf<CharT, Traits, Allocator> base2; |
37 | |
38 | { |
39 | OS out1{&base1, Allocator{42}}; |
40 | assert(out1.get_wrapped() == &base1); |
41 | |
42 | typename OS::syncbuf_type* sb1 = out1.rdbuf(); |
43 | assert(sb1->get_wrapped() == &base1); |
44 | assert(sb1->get_allocator().get_data() == 42); |
45 | |
46 | out1 << CharT('A'); |
47 | |
48 | static_assert(!noexcept(out1.operator=(std::move(out1)))); // LWG-3867 |
49 | OS out2{&base2, Allocator{99}}; |
50 | |
51 | out2 << CharT('Z'); |
52 | |
53 | // Validate the data is still in the syncbuf and not in the stringbuf. |
54 | assert(base1.str().empty()); |
55 | assert(base2.str().empty()); |
56 | |
57 | out2 = std::move(out1); |
58 | |
59 | // Since sb2 is overwritten by the move its data should be in its stringbuf. |
60 | assert(base1.str().empty()); |
61 | assert(base2.str().size() == 1); |
62 | assert(base2.str()[0] == CharT('Z')); |
63 | |
64 | assert(out2.get_wrapped() == &base1); |
65 | |
66 | typename OS::syncbuf_type* sb2 = out2.rdbuf(); |
67 | assert(sb2->get_wrapped() == &base1); |
68 | if constexpr (std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) |
69 | assert(sb2->get_allocator().get_data() == 42); |
70 | else |
71 | assert(sb2->get_allocator().get_data() == 99); |
72 | |
73 | assert(out1.get_wrapped() == nullptr); |
74 | assert(sb1->get_wrapped() == nullptr); |
75 | |
76 | // The data written to 2 will be stored in sb1. The write happens after the destruction. |
77 | out2 << CharT('B'); |
78 | assert(base1.str().empty()); |
79 | } |
80 | |
81 | assert(base1.str().size() == 2); |
82 | assert(base1.str()[0] == CharT('A')); |
83 | assert(base1.str()[1] == CharT('B')); |
84 | assert(base2.str().size() == 1); |
85 | assert(base2.str()[0] == CharT('Z')); |
86 | } |
87 | |
88 | template <class CharT> |
89 | static void test() { |
90 | test<CharT, true>(); |
91 | test<CharT, false>(); |
92 | } |
93 | |
94 | int main(int, char**) { |
95 | test<char>(); |
96 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
97 | test<wchar_t>(); |
98 | #endif |
99 | |
100 | return 0; |
101 | } |
102 | |