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 | // Tests the inherited function using a custom allocator. |
19 | // |
20 | // int_type basic_streambuf<charT, traits>::sputc(char_type c); |
21 | // |
22 | // This test also validates the observable behaviour after move assignment and |
23 | // construction. This test uses a small so the underlying string is in short |
24 | // mode. |
25 | |
26 | #include <array> |
27 | #include <syncstream> |
28 | #include <cassert> |
29 | #include <sstream> |
30 | |
31 | #include "test_macros.h" |
32 | #include "test_allocator.h" |
33 | |
34 | template <class CharT> |
35 | void test() { |
36 | std::array< CharT, 17> input{ |
37 | CharT('a'), |
38 | CharT('1'), |
39 | CharT('+'), |
40 | CharT('A'), |
41 | CharT('g'), |
42 | CharT('0'), |
43 | CharT('@'), |
44 | CharT('Z'), |
45 | CharT('q'), |
46 | CharT('8'), |
47 | CharT('#'), |
48 | CharT('D'), |
49 | CharT('t'), |
50 | CharT('9'), |
51 | CharT('$'), |
52 | CharT('A'), |
53 | CharT(' ')}; |
54 | using SyncBuf = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT>>; |
55 | |
56 | { // Normal |
57 | std::basic_string<CharT> expected; |
58 | std::basic_stringbuf<CharT> buf; |
59 | test_allocator_statistics stats; |
60 | test_allocator<CharT> allocator{&stats}; |
61 | |
62 | { |
63 | SyncBuf sync_buf{&buf, allocator}; |
64 | for (int i = 0; i < 1024; ++i) { |
65 | CharT c = input[i % input.size()]; |
66 | expected.push_back(c); |
67 | typename SyncBuf::int_type ret = sync_buf.sputc(c); |
68 | assert(ret == typename SyncBuf::int_type(c)); |
69 | } |
70 | // The synchronization happens upon destruction of sync_buf. |
71 | assert(buf.str().empty()); |
72 | assert(stats.allocated_size >= 1024); |
73 | } |
74 | assert(buf.str() == expected); |
75 | assert(stats.allocated_size == 0); |
76 | } |
77 | { // Move construction |
78 | std::basic_stringbuf<CharT> buf; |
79 | test_allocator_statistics stats; |
80 | test_allocator<CharT> allocator{&stats}; |
81 | |
82 | { |
83 | SyncBuf sync_buf{&buf, allocator}; |
84 | CharT c = CharT('4'); |
85 | typename SyncBuf::int_type ret = sync_buf.sputc(c); |
86 | assert(ret == typename SyncBuf::int_type(c)); |
87 | |
88 | { |
89 | c = CharT('2'); |
90 | |
91 | SyncBuf new_sync_buf{std::move(sync_buf)}; |
92 | ret = new_sync_buf.sputc(c); |
93 | assert(ret == typename SyncBuf::int_type(c)); |
94 | |
95 | // The synchronization happens upon destruction of new_sync_buf. |
96 | assert(buf.str().empty()); |
97 | assert(stats.allocated_size >= 2); |
98 | } |
99 | assert(buf.str().size() == 2); |
100 | assert(buf.str()[0] == CharT('4')); |
101 | assert(buf.str()[1] == CharT('2')); |
102 | assert(stats.allocated_size == 0); |
103 | } |
104 | assert(buf.str().size() == 2); |
105 | assert(buf.str()[0] == CharT('4')); |
106 | assert(buf.str()[1] == CharT('2')); |
107 | assert(stats.allocated_size == 0); |
108 | } |
109 | { // Move assignment non-propagating allocator |
110 | std::basic_stringbuf<CharT> buf; |
111 | test_allocator_statistics stats; |
112 | test_allocator<CharT> allocator{&stats}; |
113 | static_assert(!std::allocator_traits<test_allocator<CharT>>::propagate_on_container_move_assignment::value); |
114 | |
115 | { |
116 | SyncBuf sync_buf{&buf, allocator}; |
117 | CharT c = CharT('4'); |
118 | typename SyncBuf::int_type ret = sync_buf.sputc(c); |
119 | assert(ret == typename SyncBuf::int_type(c)); |
120 | |
121 | { |
122 | c = CharT('2'); |
123 | |
124 | SyncBuf new_sync_buf; |
125 | test_allocator<CharT> a = new_sync_buf.get_allocator(); |
126 | new_sync_buf = std::move(sync_buf); |
127 | assert(new_sync_buf.get_allocator() == a); |
128 | |
129 | ret = new_sync_buf.sputc(c); |
130 | assert(ret == typename SyncBuf::int_type(c)); |
131 | |
132 | // The synchronization happens upon destruction of new_sync_buf. |
133 | assert(buf.str().empty()); |
134 | } |
135 | assert(buf.str().size() == 2); |
136 | assert(buf.str()[0] == CharT('4')); |
137 | assert(buf.str()[1] == CharT('2')); |
138 | } |
139 | assert(buf.str().size() == 2); |
140 | assert(buf.str()[0] == CharT('4')); |
141 | assert(buf.str()[1] == CharT('2')); |
142 | } |
143 | } |
144 | |
145 | int main(int, char**) { |
146 | test<char>(); |
147 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
148 | test<wchar_t>(); |
149 | #endif |
150 | return 0; |
151 | } |
152 | |