| 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 | |