brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.0 KiB · dd6dd32 Raw
400 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710// UNSUPPORTED: no-localization11// UNSUPPORTED: libcpp-has-no-experimental-syncstream12 13// <syncstream>14 15// template <class charT, class traits, class Allocator>16// class basic_syncbuf;17 18// basic_syncbuf& operator=(basic_syncbuf&& rhs);19 20#include <syncstream>21#include <sstream>22#include <cassert>23#include <concepts>24 25#include "test_macros.h"26 27template <class T, class propagate>28struct test_allocator : std::allocator<T> {29  using propagate_on_container_move_assignment = propagate;30 31  int id{-1};32 33  test_allocator(int _id = -1) : id(_id) {}34  test_allocator(test_allocator const& other)            = default;35  test_allocator(test_allocator&& other)                 = default;36  test_allocator& operator=(const test_allocator& other) = default;37 38  test_allocator& operator=(test_allocator&& other) {39    if constexpr (propagate_on_container_move_assignment::value)40      id = other.id;41    else42      id = -1;43    return *this;44  }45};46 47template <class T>48class test_buf : public std::basic_streambuf<T> {49public:50  int id;51 52  test_buf(int _id = 0) : id(_id) {}53 54  T* _pptr() { return this->pptr(); }55};56 57template <class T, class Alloc = std::allocator<T>>58class test_syncbuf : public std::basic_syncbuf<T, std::char_traits<T>, Alloc> {59  using Base = std::basic_syncbuf<T, std::char_traits<T>, Alloc>;60 61public:62  test_syncbuf() = default;63 64  test_syncbuf(test_buf<T>* buf, Alloc alloc) : Base(buf, alloc) {}65 66  test_syncbuf(typename Base::streambuf_type* buf, Alloc alloc) : Base(buf, alloc) {}67 68  void _setp(T* begin, T* end) { return this->setp(begin, end); }69};70 71// Helper wrapper to inspect the internal state of the basic_syncbuf72//73// This is used to validate some standard requirements and libc++74// implementation details.75template <class CharT, class Traits, class Allocator>76class syncbuf_inspector : public std::basic_syncbuf<CharT, Traits, Allocator> {77public:78  syncbuf_inspector() = default;79  explicit syncbuf_inspector(std::basic_syncbuf<CharT, Traits, Allocator>&& base)80      : std::basic_syncbuf<CharT, Traits, Allocator>(std::move(base)) {}81 82  void operator=(std::basic_syncbuf<CharT, Traits, Allocator>&& base) { *this = std::move(base); }83 84  using std::basic_syncbuf<CharT, Traits, Allocator>::pbase;85  using std::basic_syncbuf<CharT, Traits, Allocator>::pptr;86  using std::basic_syncbuf<CharT, Traits, Allocator>::epptr;87};88 89template <class CharT>90static void test_assign() {91  test_buf<CharT> base;92 93  { // Test using the real class, propagating allocator.94    using BuffT = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT, std::true_type>>;95 96    BuffT buff1(&base, test_allocator<CharT, std::true_type>{42});97    buff1.sputc(CharT('A'));98 99    assert(buff1.get_wrapped() != nullptr);100 101    BuffT buff2;102    assert(buff2.get_allocator().id == -1);103    buff2 = std::move(buff1);104    assert(buff1.get_wrapped() == nullptr);105    assert(buff2.get_wrapped() == &base);106 107    assert(buff2.get_wrapped() == &base);108    assert(buff2.get_allocator().id == 42);109  }110 111  { // Test using the real class, non-propagating allocator.112    using BuffT = std::basic_syncbuf<CharT, std::char_traits<CharT>, test_allocator<CharT, std::false_type>>;113 114    BuffT buff1(&base, test_allocator<CharT, std::false_type>{42});115    buff1.sputc(CharT('A'));116 117    assert(buff1.get_wrapped() != nullptr);118 119    BuffT buff2;120    assert(buff2.get_allocator().id == -1);121    buff2 = std::move(buff1);122    assert(buff1.get_wrapped() == nullptr);123    assert(buff2.get_wrapped() == &base);124 125    assert(buff2.get_wrapped() == &base);126    assert(buff2.get_allocator().id == -1);127  }128 129  { // Move assignment propagating allocator130    // Test using the inspection wrapper.131    // Not all these requirements are explicitly in the Standard,132    // however the asserts are based on secondary requirements. The133    // LIBCPP_ASSERTs are implementation specific.134 135    using BuffT = std::basic_syncbuf<CharT, std::char_traits<CharT>, std::allocator<CharT>>;136 137    using Inspector = syncbuf_inspector<CharT, std::char_traits<CharT>, std::allocator<CharT>>;138    Inspector inspector1{BuffT(&base)};139    inspector1.sputc(CharT('A'));140 141    assert(inspector1.get_wrapped() != nullptr);142    assert(inspector1.pbase() != nullptr);143    assert(inspector1.pptr() != nullptr);144    assert(inspector1.epptr() != nullptr);145    assert(inspector1.pbase() != inspector1.pptr());146    assert(inspector1.pptr() - inspector1.pbase() == 1);147    [[maybe_unused]] std::streamsize size = inspector1.epptr() - inspector1.pbase();148 149    Inspector inspector2;150    inspector2 = std::move(inspector1);151 152    assert(inspector1.get_wrapped() == nullptr);153    LIBCPP_ASSERT(inspector1.pbase() == nullptr);154    LIBCPP_ASSERT(inspector1.pptr() == nullptr);155    LIBCPP_ASSERT(inspector1.epptr() == nullptr);156    assert(inspector1.pbase() == inspector1.pptr());157 158    assert(inspector2.get_wrapped() == &base);159    LIBCPP_ASSERT(inspector2.pbase() != nullptr);160    LIBCPP_ASSERT(inspector2.pptr() != nullptr);161    LIBCPP_ASSERT(inspector2.epptr() != nullptr);162    assert(inspector2.pptr() - inspector2.pbase() == 1);163    LIBCPP_ASSERT(inspector2.epptr() - inspector2.pbase() == size);164  }165}166 167template <class CharT>168static void test_basic() {169  { // Test properties170    std::basic_syncbuf<CharT> sync_buf1(nullptr);171    std::basic_syncbuf<CharT> sync_buf2(nullptr);172    [[maybe_unused]] std::same_as<std::basic_syncbuf<CharT>&> decltype(auto) ret =173        sync_buf1.operator=(std::move(sync_buf2));174  }175 176  std::basic_stringbuf<CharT> sstr1;177  std::basic_stringbuf<CharT> sstr2;178  std::basic_string<CharT> expected(42, CharT('*')); // a long string179 180  {181    std::basic_syncbuf<CharT> sync_buf1(&sstr1);182    sync_buf1.sputc(CharT('A')); // a short string183 184    std::basic_syncbuf<CharT> sync_buf2(&sstr2);185    sync_buf2.sputn(expected.data(), expected.size());186 187#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)188    assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);189    assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 1);190#endif191 192    sync_buf2 = std::move(sync_buf1);193    assert(sync_buf2.get_wrapped() == &sstr1);194 195    assert(sstr1.str().empty());196    assert(sstr2.str() == expected);197 198#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_THREADS)199    assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr1) == 1);200    assert(std::__wrapped_streambuf_mutex::__instance().__get_count(&sstr2) == 0);201#endif202  }203 204  assert(sstr1.str().size() == 1);205  assert(sstr1.str()[0] == CharT('A'));206  assert(sstr2.str() == expected);207}208 209template <class CharT>210static void test_short_write_after_assign() {211  std::basic_stringbuf<CharT> sstr1;212  std::basic_stringbuf<CharT> sstr2;213  std::basic_string<CharT> expected(42, CharT('*')); // a long string214 215  {216    std::basic_syncbuf<CharT> sync_buf1(&sstr1);217    sync_buf1.sputc(CharT('A')); // a short string218 219    std::basic_syncbuf<CharT> sync_buf2(&sstr2);220    sync_buf2.sputn(expected.data(), expected.size());221 222    sync_buf2 = std::move(sync_buf1);223    sync_buf2.sputc(CharT('Z'));224 225    assert(sstr1.str().empty());226    assert(sstr2.str() == expected);227  }228 229  assert(sstr1.str().size() == 2);230  assert(sstr1.str()[0] == CharT('A'));231  assert(sstr1.str()[1] == CharT('Z'));232  assert(sstr2.str() == expected);233}234 235template <class CharT>236static void test_long_write_after_assign() {237  std::basic_stringbuf<CharT> sstr1;238  std::basic_stringbuf<CharT> sstr2;239  std::basic_string<CharT> expected(42, CharT('*')); // a long string240 241  {242    std::basic_syncbuf<CharT> sync_buf1(&sstr1);243    sync_buf1.sputc(CharT('A')); // a short string244 245    std::basic_syncbuf<CharT> sync_buf2(&sstr2);246    sync_buf2.sputn(expected.data(), expected.size());247 248    sync_buf2 = std::move(sync_buf1);249    sync_buf2.sputn(expected.data(), expected.size());250 251    assert(sstr1.str().empty());252    assert(sstr2.str() == expected);253  }254 255  assert(sstr1.str().size() == 1 + expected.size());256  assert(sstr1.str()[0] == CharT('A'));257  assert(sstr1.str().substr(1) == expected);258  assert(sstr2.str() == expected);259}260 261template <class CharT>262static void test_emit_on_assign() {263  { // don't emit / don't emit264 265    std::basic_stringbuf<CharT> sstr1;266    std::basic_stringbuf<CharT> sstr2;267    std::basic_string<CharT> expected(42, CharT('*')); // a long string268 269    {270      std::basic_syncbuf<CharT> sync_buf1(&sstr1);271      sync_buf1.set_emit_on_sync(false);272      sync_buf1.sputc(CharT('A')); // a short string273 274      std::basic_syncbuf<CharT> sync_buf2(&sstr2);275      sync_buf2.set_emit_on_sync(false);276      sync_buf2.sputn(expected.data(), expected.size());277 278      sync_buf2 = std::move(sync_buf1);279      assert(sstr1.str().empty());280      assert(sstr2.str() == expected);281 282      sync_buf2.pubsync();283      assert(sstr1.str().empty());284      assert(sstr2.str() == expected);285    }286 287    assert(sstr1.str().size() == 1);288    assert(sstr1.str()[0] == CharT('A'));289    assert(sstr2.str() == expected);290  }291 292  { // don't emit / do emit293 294    std::basic_stringbuf<CharT> sstr1;295    std::basic_stringbuf<CharT> sstr2;296    std::basic_string<CharT> expected(42, CharT('*')); // a long string297 298    {299      std::basic_syncbuf<CharT> sync_buf1(&sstr1);300      sync_buf1.set_emit_on_sync(true);301      sync_buf1.sputc(CharT('A')); // a short string302 303      std::basic_syncbuf<CharT> sync_buf2(&sstr2);304      sync_buf2.set_emit_on_sync(false);305      sync_buf2.sputn(expected.data(), expected.size());306 307      sync_buf2 = std::move(sync_buf1);308      assert(sstr1.str().empty());309      assert(sstr2.str() == expected);310 311      sync_buf2.pubsync();312      assert(sstr1.str().size() == 1);313      assert(sstr1.str()[0] == CharT('A'));314      assert(sstr2.str() == expected);315    }316 317    assert(sstr1.str().size() == 1);318    assert(sstr1.str()[0] == CharT('A'));319    assert(sstr2.str() == expected);320  }321 322  { // do emit / don't emit323 324    std::basic_stringbuf<CharT> sstr1;325    std::basic_stringbuf<CharT> sstr2;326    std::basic_string<CharT> expected(42, CharT('*')); // a long string327 328    {329      std::basic_syncbuf<CharT> sync_buf1(&sstr1);330      sync_buf1.set_emit_on_sync(false);331      sync_buf1.sputc(CharT('A')); // a short string332 333      std::basic_syncbuf<CharT> sync_buf2(&sstr2);334      sync_buf2.set_emit_on_sync(true);335      sync_buf2.sputn(expected.data(), expected.size());336 337      sync_buf2 = std::move(sync_buf1);338      assert(sstr1.str().empty());339      assert(sstr2.str() == expected);340 341      sync_buf2.pubsync();342      assert(sstr1.str().empty());343      assert(sstr2.str() == expected);344    }345 346    assert(sstr1.str().size() == 1);347    assert(sstr1.str()[0] == CharT('A'));348    assert(sstr2.str() == expected);349  }350 351  { // do emit / do emit352 353    std::basic_stringbuf<CharT> sstr1;354    std::basic_stringbuf<CharT> sstr2;355    std::basic_string<CharT> expected(42, CharT('*')); // a long string356 357    {358      std::basic_syncbuf<CharT> sync_buf1(&sstr1);359      sync_buf1.set_emit_on_sync(true);360      sync_buf1.sputc(CharT('A')); // a short string361 362      std::basic_syncbuf<CharT> sync_buf2(&sstr2);363      sync_buf2.set_emit_on_sync(true);364      sync_buf2.sputn(expected.data(), expected.size());365 366      sync_buf2 = std::move(sync_buf1);367      assert(sstr1.str().empty());368      assert(sstr2.str() == expected);369 370      sync_buf2.pubsync();371      assert(sstr1.str().size() == 1);372      assert(sstr1.str()[0] == CharT('A'));373      assert(sstr2.str() == expected);374    }375 376    assert(sstr1.str().size() == 1);377    assert(sstr1.str()[0] == CharT('A'));378    assert(sstr2.str() == expected);379  }380}381 382template <class CharT>383static void test() {384  test_assign<CharT>();385  test_basic<CharT>();386  test_short_write_after_assign<CharT>();387  test_long_write_after_assign<CharT>();388  test_emit_on_assign<CharT>();389}390 391int main(int, char**) {392  test<char>();393 394#ifndef TEST_HAS_NO_WIDE_CHARACTERS395  test<wchar_t>();396#endif397 398  return 0;399}400