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>
test()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
main(int,char **)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