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 | // streamsize basic_streambuf<charT, traits>::sputc(const char_type* s, streamsize n); |
21 | // |
22 | // This test also validates the observable behaviour after move assignment and |
23 | // construction. This test uses a large buffer so the underlying string is in |
24 | // long 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 | std::basic_string<CharT> expected; |
55 | for (int i = 0; i < 1024; ++i) |
56 | expected.push_back(input[i % input.size()]); |
57 | |
58 | using SyncBuf = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT>>; |
59 | { // Normal |
60 | std::basic_stringbuf<CharT> buf; |
61 | test_allocator_statistics stats; |
62 | test_allocator<CharT> allocator{&stats}; |
63 | |
64 | { |
65 | SyncBuf sync_buf{&buf, allocator}; |
66 | std::streamsize ret = sync_buf.sputn(expected.data(), expected.size()); |
67 | assert(ret == 1024); |
68 | |
69 | // The synchronization happens upon destruction of sync_buf. |
70 | assert(buf.str().empty()); |
71 | assert(stats.allocated_size >= 1024); |
72 | } |
73 | assert(buf.str() == expected); |
74 | assert(stats.allocated_size == 0); |
75 | } |
76 | { // Move construction |
77 | std::basic_stringbuf<CharT> buf; |
78 | test_allocator_statistics stats; |
79 | test_allocator<CharT> allocator{&stats}; |
80 | |
81 | { |
82 | SyncBuf sync_buf{&buf, allocator}; |
83 | std::streamsize ret = sync_buf.sputn(expected.data(), expected.size()); |
84 | assert(ret == 1024); |
85 | { |
86 | SyncBuf new_sync_buf{std::move(sync_buf)}; |
87 | ret = new_sync_buf.sputn(expected.data(), expected.size()); |
88 | assert(ret == 1024); |
89 | |
90 | // The synchronization happens upon destruction of new_sync_buf. |
91 | assert(buf.str().empty()); |
92 | assert(stats.allocated_size >= 2048); |
93 | } |
94 | assert(buf.str() == expected + expected); |
95 | assert(stats.allocated_size == 0); |
96 | } |
97 | assert(buf.str() == expected + expected); |
98 | assert(stats.allocated_size == 0); |
99 | } |
100 | { // Move assignment non-propagating allocator |
101 | std::basic_stringbuf<CharT> buf; |
102 | test_allocator_statistics stats; |
103 | test_allocator<CharT> allocator{&stats}; |
104 | static_assert(!std::allocator_traits<test_allocator<CharT>>::propagate_on_container_move_assignment::value); |
105 | |
106 | { |
107 | SyncBuf sync_buf{&buf, allocator}; |
108 | std::streamsize ret = sync_buf.sputn(expected.data(), expected.size()); |
109 | assert(ret == 1024); |
110 | { |
111 | SyncBuf new_sync_buf; |
112 | test_allocator<CharT> a = new_sync_buf.get_allocator(); |
113 | new_sync_buf = std::move(sync_buf); |
114 | assert(new_sync_buf.get_allocator() == a); |
115 | |
116 | ret = new_sync_buf.sputn(expected.data(), expected.size()); |
117 | assert(ret == 1024); |
118 | |
119 | // The synchronization happens upon destruction of new_sync_buf. |
120 | assert(buf.str().empty()); |
121 | } |
122 | assert(buf.str() == expected + expected); |
123 | } |
124 | assert(buf.str() == expected + expected); |
125 | } |
126 | } |
127 | |
128 | int main(int, char**) { |
129 | test<char>(); |
130 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
131 | test<wchar_t>(); |
132 | #endif |
133 | return 0; |
134 | } |
135 | |