Index: libcxx/docs/Cxx2aStatus.rst =================================================================== --- libcxx/docs/Cxx2aStatus.rst +++ libcxx/docs/Cxx2aStatus.rst @@ -45,6 +45,8 @@ .. [#note-P0619] P0619: Only ``std::allocator`` part is implemented. + .. [#note-P0053R7] P0053R7: Only ``std::basic_syncbuf`` part is implemented. + .. _issues-status-cxx2a: Index: libcxx/docs/Cxx2aStatusPaperStatus.csv =================================================================== --- libcxx/docs/Cxx2aStatusPaperStatus.csv +++ libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -193,3 +193,4 @@ "`P2102 `__","LWG","Make 'implicit expression variations' more explicit (Wording for US185)","Prague","* *","" "`P2106 `__","LWG","Alternative wording for GB315 and GB316","Prague","* *","" "`P2116 `__","LWG","Remove tuple-like protocol support from fixed-extent span","Prague","|Complete|","11.0" +"`P0053R7 `__","LWG","","Albuquerque","|Partial|","12.0" Index: libcxx/include/CMakeLists.txt =================================================================== --- libcxx/include/CMakeLists.txt +++ libcxx/include/CMakeLists.txt @@ -163,6 +163,7 @@ support/xlocale/__nop_locale_mgmt.h support/xlocale/__posix_l_fallback.h support/xlocale/__strtonum_fallback.h + syncstream system_error tgmath.h thread Index: libcxx/include/iosfwd =================================================================== --- libcxx/include/iosfwd +++ libcxx/include/iosfwd @@ -50,6 +50,9 @@ template > class istreambuf_iterator; template > class ostreambuf_iterator; +template , class Allocator = allocator > + class basic_syncbuf; + typedef basic_ios ios; typedef basic_ios wios; @@ -87,6 +90,9 @@ typedef fpos::state_type> streampos; typedef fpos::state_type> wstreampos; +typedef basic_syncbuf syncbuf; +typedef basic_syncbuf wsyncbuf; + } // std */ @@ -152,6 +158,14 @@ template > class _LIBCPP_TEMPLATE_VIS ostreambuf_iterator; +#if _LIBCPP_STD_VER > 17 + +template , + class _Allocator = allocator<_CharT> > + class _LIBCPP_TEMPLATE_VIS basic_syncbuf; + +#endif // _LIBCPP_STD_VER > 17 + typedef basic_ios ios; typedef basic_ios wios; @@ -185,6 +199,13 @@ typedef basic_ofstream wofstream; typedef basic_fstream wfstream; +#if _LIBCPP_STD_VER > 17 + +typedef basic_syncbuf syncbuf; +typedef basic_syncbuf wsyncbuf; + +#endif // _LIBCPP_STD_VER > 17 + template class _LIBCPP_TEMPLATE_VIS fpos; typedef fpos streampos; typedef fpos wstreampos; Index: libcxx/include/syncstream =================================================================== --- /dev/null +++ libcxx/include/syncstream @@ -0,0 +1,285 @@ +// -*- C++ -*- +//===-------------------------- syncstream -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP_SYNCSTREAM +#define _LIBCPP_SYNCSTREAM + +/* + syncstream synopsis + +namespace std { + +template +class basic_syncbuf + : public basic_streambuf { + +public: + using char_type = charT; + using int_type = typename traits::int_type; + using pos_type = typename traits::pos_type; + using off_type = typename traits::off_type; + using traits_type = traits; + using allocator_type = Allocator; + + using streambuf_type = basic_streambuf; + + explicit + basic_syncbuf(streambuf_type* obuf = nullptr) + : basic_syncbuf(obuf, Allocator()) { } + basic_syncbuf(streambuf_type*, const Allocator&); + basic_syncbuf(basic_syncbuf&&); + ~basic_syncbuf(); + + basic_syncbuf& operator=(basic_syncbuf&&); + void swap(basic_syncbuf&); + + bool emit(); + streambuf_type* get_wrapped() const noexcept; + allocator_type get_allocator() const noexcept; + void set_emit_on_sync(bool) noexcept; + +protected: + int sync() override; + +private: + streambuf_type* wrapped; // exposition only + bool emit_on_sync{}; // exposition only +}; + +template +void swap(basic_syncbuf&, + basic_syncbuf&); + +using syncbuf = basic_syncbuf; +using wsyncbuf = basic_syncbuf; + +} // namespace std + +*/ + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +#include <__config> +#include +#include +#include + + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +template +class _LIBCPP_TYPE_VIS basic_syncbuf + : public basic_streambuf<_CharT, _Traits> +{ +public: + using char_type = _CharT; + using int_type = typename _Traits::int_type; + using pos_type = typename _Traits::pos_type; + using off_type = typename _Traits::off_type; + using traits_type = _Traits; + using allocator_type = _Allocator; + + using streambuf_type = basic_streambuf; + + using string_type = basic_string; + using stringbuf_type = basic_stringbuf<_CharT, traits_type, allocator_type>; + + explicit basic_syncbuf(streambuf_type* __obuf = nullptr) + : basic_syncbuf(__obuf, allocator_type{}) {} + + basic_syncbuf(streambuf_type* __obuf, const allocator_type& __a) + : __mtx(__obuf), __buf(string_type{__a}), __wrapped(__obuf) {} + + basic_syncbuf(basic_syncbuf&& __other) noexcept + : __mtx(std::move(__other.__mtx)), __buf(std::move(__other.__buf)), + __wrapped(__other.__wrapped), __emit_on_sync(__other.__emit_on_sync), + __needs_flush(__other.__needs_flush) + { + __other.__wrapped = nullptr; + } + + ~basic_syncbuf() + { + _no_throw_emit(); + } + + basic_syncbuf& operator=(basic_syncbuf&& __other) noexcept + { + _no_throw_emit(); + + __mtx = std::move(__other.__mtx); + __buf = std::move(__other.__buf); + __wrapped = __other.__wrapped; + __emit_on_sync = __other.__emit_on_sync; + __needs_flush = __other.__needs_flush; + + __other.__wrapped = nullptr; + + return *this; + } + + _LIBCPP_HIDE_FROM_ABI + void swap(basic_syncbuf& __other) + { + std::swap(__mtx, __other.__mtx); + std::swap(__buf, __other.__buf); + std::swap(__wrapped, __other.__wrapped); + std::swap(__emit_on_sync, __other.__emit_on_sync); + std::swap(__needs_flush, __other.__needs_flush); + } + + _LIBCPP_HIDE_FROM_ABI + bool emit() + { + if (!__wrapped) + { + return false; + } + + // auto __view = __buf.view(); // C++20 + // auto __str = std::move(__buf).str(); // C++20 + decltype(__buf.str()) __str; + { + stringbuf_type __temp = std::move(__buf); + __str = __temp.str(); + } + + lock_guard<__mutex> __lk{__mtx}; + if (std::streamsize __size = __str.size()) + { + if (__wrapped->sputn(__str.data(), __size) != __size) + { + return false; + } + } + + if (__needs_flush) + { + __needs_flush = false; + return !__wrapped->pubsync(); + } + + return true; + } + + _LIBCPP_HIDE_FROM_ABI + streambuf_type* get_wrapped() const noexcept + { + return __wrapped; + } + + _LIBCPP_HIDE_FROM_ABI + allocator_type get_allocator() const noexcept + { + // return __buf.get_allocator(); // C++20 + return allocator_type{}; + } + + _LIBCPP_HIDE_FROM_ABI + void set_emit_on_sync(bool __b) noexcept + { + __emit_on_sync = __b; + } + +protected: + _LIBCPP_HIDE_FROM_ABI + int sync() override + { + __needs_flush = true; + return !__emit_on_sync || emit() ? 0 : traits_type::eof(); + } + + _LIBCPP_HIDE_FROM_ABI + streamsize xsputn(const char_type* __s, streamsize __n) override + { + return __buf.sputn(__s, __n); + } + +private: + _LIBCPP_HIDE_FROM_ABI + void _no_throw_emit() noexcept + { +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + emit(); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + } +#endif // _LIBCPP_NO_EXCEPTIONS + } + + struct __mutex + { + mutex* __mtx; + + __mutex(streambuf_type* __ptr) + : __mtx(_get_mutex(__ptr)) {} + + _LIBCPP_HIDE_FROM_ABI + static mutex* _get_mutex(streambuf_type* __ptr) + { + static mutex __lock; + static map __map; + lock_guard __lk{__lock}; + return std::addressof(__map[__ptr]); + } + + _LIBCPP_HIDE_FROM_ABI + void lock() + { + __mtx->lock(); + } + + _LIBCPP_HIDE_FROM_ABI + void unlock() + { + __mtx->unlock(); + } + + _LIBCPP_HIDE_FROM_ABI + void swap(__mutex& other) + { + std::swap(__mtx, other.__mtx); + } + }; + + __mutex __mtx; + stringbuf_type __buf; + streambuf_type* __wrapped; + bool __emit_on_sync{}; + bool __needs_flush{}; +}; + + +template +_LIBCPP_HIDE_FROM_ABI +void swap(basic_syncbuf<_CharT, _Traits, _Allocator>& __a, + basic_syncbuf<_CharT, _Traits, _Allocator>& __b) +{ + __a.swap(__b); +} + +using syncbuf = basic_syncbuf; +using wsyncbuf = basic_syncbuf; + +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SYNCSTREAM Index: libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist =================================================================== --- libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist +++ libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist @@ -32,12 +32,15 @@ {'is_defined': False, 'name': '_ZTVSt13runtime_error', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTVSt14overflow_error', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTVSt16invalid_argument', 'size': 0, 'type': 'OBJECT'} +{'is_defined': False, 'name': '_ZTVSt9exception', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZdaPv', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZdaPvSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZdlPv', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZdlPvSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '_Znam', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZnamSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '_Znwm', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZnwmSt11align_val_t', 'type': 'FUNC'} {'is_defined': False, 'name': '__cxa_allocate_exception', 'type': 'FUNC'} {'is_defined': False, 'name': '__cxa_begin_catch', 'type': 'FUNC'} {'is_defined': False, 'name': '__cxa_current_primary_exception', 'type': 'FUNC'} @@ -1965,6 +1968,8 @@ {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDiEE', 'size': 96, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDsEE', 'size': 96, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IwEE', 'size': 96, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTVNSt3__120__time_get_c_storageIcEE', 'size': 72, 'type': 'OBJECT'} +{'is_defined': True, 'name': '_ZTVNSt3__120__time_get_c_storageIwEE', 'size': 72, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__14__fs10filesystem16filesystem_errorE', 'size': 40, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIcEE', 'size': 104, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIwEE', 'size': 136, 'type': 'OBJECT'} Index: libcxx/test/libcxx/double_include.sh.cpp =================================================================== --- libcxx/test/libcxx/double_include.sh.cpp +++ libcxx/test/libcxx/double_include.sh.cpp @@ -122,6 +122,9 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_THREADS +#include +#endif #include #include #ifndef _LIBCPP_HAS_NO_THREADS Index: libcxx/test/libcxx/input.output/syncstream/lit.local.cfg =================================================================== --- /dev/null +++ libcxx/test/libcxx/input.output/syncstream/lit.local.cfg @@ -0,0 +1,6 @@ +# Load the same local configuration as the corresponding one in libcxx/test/std +import os +inLibcxx = os.path.join('libcxx', 'test', 'libcxx') +inStd = os.path.join('libcxx', 'test', 'std') +localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd) +config.load_from_path(localConfig, lit_config) Index: libcxx/test/libcxx/input.output/syncstream/version.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/input.output/syncstream/version.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include + +#include "test_macros.h" + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main(int, char**) +{ + + return 0; +} Index: libcxx/test/libcxx/min_max_macros.compile.pass.cpp =================================================================== --- libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -203,6 +203,10 @@ TEST_MACROS(); #include TEST_MACROS(); +#ifndef _LIBCPP_HAS_NO_THREADS +#include +TEST_MACROS(); +#endif #include TEST_MACROS(); #include Index: libcxx/test/libcxx/no_assert_include.compile.pass.cpp =================================================================== --- libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -115,6 +115,9 @@ #include #include #include +#ifndef _LIBCPP_HAS_NO_THREADS +#include +#endif #include #include #ifndef _LIBCPP_HAS_NO_THREADS Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.assign/member_swap.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.assign/member_swap.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// basic_syncbuf(const basic_syncbuf& rhs); // implicitly deleted + +#include +#include + + +int main(int, char**) +{ + std::stringbuf buf; + std::syncbuf sbuf{&buf}; + std::syncbuf nullbuf; + + assert(sbuf.get_wrapped() == &buf); + assert(nullbuf.get_wrapped() == nullptr); + + sbuf.swap(nullbuf); + + assert(sbuf.get_wrapped() == nullptr); + assert(nullbuf.get_wrapped() == &buf); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.assign/move_assign.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.assign/move_assign.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// basic_syncbuf& operator=(basic_syncbuf&&); + +#include +#include + +#include + +int main(int, char**) +{ + std::stringbuf buf; + { + std::syncbuf sbuf{&buf}; + + std::stringbuf buf2; + std::syncbuf sbuf2{&buf2}; + + sbuf.sputn("DEF", 3); + sbuf2.sputn("ABC", 3); + + assert(buf.str() == ""); + assert(buf2.str() == ""); + + sbuf2 = std::move(sbuf); + + assert(sbuf.get_wrapped() == nullptr); + assert(sbuf2.get_wrapped() == &buf); + + assert(buf.str() == ""); + assert(buf2.str() == "ABC"); + } + assert(buf.str() == "DEF"); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.assign/nonmember_swap.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.assign/nonmember_swap.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// template +// void swap(basic_syncbuf&, +// basic_syncbuf&); + +#include +#include + + +int main(int, char**) +{ + std::stringbuf buf; + std::syncbuf sbuf{&buf}; + std::syncbuf nullbuf; + + assert(sbuf.get_wrapped() == &buf); + assert(nullbuf.get_wrapped() == nullptr); + + std::swap(sbuf, nullbuf); + + assert(sbuf.get_wrapped() == nullptr); + assert(nullbuf.get_wrapped() == &buf); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/allocator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/allocator.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// basic_syncbuf(streambuf_type*, const Allocator&); + +#include +#include + + +int main(int, char**) +{ + std::syncbuf::allocator_type a; + std::syncbuf buf{nullptr, a}; + assert(buf.get_allocator() == a); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/copy.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/copy.fail.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// basic_syncbuf(const basic_syncbuf& rhs); // implicitly deleted + +#include + +std::syncbuf &get(); + +int main(int, char**) +{ + std::syncbuf sb = get(); // expected-error {{call to implicitly-deleted copy constructor}} + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/default.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/default.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// explicit basic_syncbuf(streambuf_type* __obuf = nullptr); + +#include +#include + +#include "test_convertible.h" + + +int main(int, char**) +{ + static_assert(!test_convertible(), ""); + static_assert(!test_convertible(), ""); + + std::syncbuf buf; + assert(buf.get_wrapped() == nullptr); + assert(buf.get_allocator() == std::allocator{}); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/explicit.compile.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/explicit.compile.fail.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// explicit basic_syncbuf(streambuf_type* __obuf = nullptr); + +#include + + +int main(int, char**) +{ + std::stringbuf s; + std::syncbuf sb = &s; + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/wrapped.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.cons/wrapped.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// basic_syncbuf(); + +#include +#include + + +int main(int, char**) +{ + std::stringbuf sbuf; + std::syncbuf buf{&sbuf}; + assert(buf.get_wrapped() == &sbuf); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.dtor/dtor.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.dtor/dtor.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// ~basic_syncbuf(); + +#include +#include + + +static bool emit_threw; + +// std::basic_syncbuf::emit is not virtual, but with a non empty buffer +// and non null wrapped streambuf, emit will call sputn on the streambuf. +struct test : public std::stringbuf +{ + std::streamsize xsputn(const char *, std::streamsize n) override + { + emit_threw = true; + return n; + } +}; + + +int main(int, char**) +{ + { + try { + test t; + std::syncbuf s{&t}; + s.sputn("ABC", 3); + } catch (int i) { + assert(false); + } + assert(emit_threw); + } + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/emit.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/emit.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// bool emit(); + +#include +#include + + +struct bad_sputn : public std::stringbuf +{ + std::streamsize xsputn(const char *, std::streamsize n) override + { + return n - 1; + } +}; + +struct bad_sync : public std::stringbuf +{ + int sync() override + { + return -1; + } +}; + +struct pubsync : public std::syncbuf +{ + using std::syncbuf::sync; +}; + +int main(int, char**) +{ + { + std::stringbuf sbuf; + { + std::syncbuf buf{&sbuf}; + buf.sputn("world", 5); + assert(buf.emit()); + sbuf.sputn("Hello ", 6); + } + assert(sbuf.str() == "worldHello "); + } + + { + std::syncbuf buf{nullptr}; + assert(!buf.emit()); + } + + { + bad_sputn sbuf; + std::syncbuf buf{&sbuf}; + buf.sputn("ABC", 3); + assert(!buf.emit()); + } + + { + bad_sync sbuf; + pubsync buf; + buf.sputn("ABC", 3); + buf.sync(); + assert(!buf.emit()); + } + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/emit_mt.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/emit_mt.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// bool emit(); + +#include +#include +#include +#include +#include + + +static void print_chars(std::streambuf *os, int to_print) +{ + std::syncbuf buf{os}; + char c = to_print; + for (int i = 0; i < 10; ++i) { + std::this_thread::yield(); + buf.sputn(&c, 1); + } +} + +bool all_contigous_chars(const std::string &str) +{ + for (auto it = str.begin(), cur_end = it + 10, end = str.end(); + it != end; it = cur_end, cur_end += 10) { + if (!std::all_of(it, cur_end, [it] (auto c) { return c == *it; })) + return false; + } + return true; +} + +int main(int, char**) +{ + std::stringbuf buf; + std::vector threads; + for (int i = 0; i < std::numeric_limits::max(); ++i) + threads.emplace_back(print_chars, &buf, i); + + for (auto &t : threads) + t.join(); + + auto str = buf.str(); + assert(str.size() == 10 * threads.size()); + assert(all_contigous_chars(str)); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/set_emit_on_sync.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/set_emit_on_sync.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf; + +// void set_emit_on_sync(bool) noexcept; + +#include +#include + +bool emit_called; + +// std::basic_syncbuf::emit is not virtual, but with a non empty buffer +// and non null wrapped streambuf, emit will call sputn on the streambuf. +struct test : public std::stringbuf +{ + std::streamsize xsputn(const char *, std::streamsize n) override + { + emit_called = true; + return n; + } +}; + +struct public_sync : public std::syncbuf +{ + using std::syncbuf::syncbuf; + using std::syncbuf::sync; +}; + + +int main(int, char**) +{ + { + test t; + public_sync s{&t}; + s.sputn("ABC", 3); + s.sync(); + assert(!emit_called); + } + { + emit_called = false; + test t; + public_sync s{&t}; + s.sputn("ABC", 3); + s.set_emit_on_sync(true); + s.sync(); + assert(emit_called); + } + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/sputn.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/syncstream.syncbuf.members/sputn.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template , +// class Allocator = allocator> +// class basic_syncbuf : public basic_streambuf; + +// From basic_streambuf +// streamsize sputn(const char_type*, streamsize); + +// ~basic_syncbuf(); + +#include +#include + + +int main(int, char**) +{ + std::stringbuf sbuf; + { + std::syncbuf buf{&sbuf}; + buf.sputn("world", 5); + sbuf.sputn("Hello ", 6); + } + assert(sbuf.str() == "Hello world"); + + return 0; +} Index: libcxx/test/std/input.output/syncstream/syncstream.syncbuf/types.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/input.output/syncstream/syncstream.syncbuf/types.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template > +// class basic_syncstream +// { +// public: +// // types: +// using char_type = charT; +// using int_type = typename traits::int_type; +// using pos_type = typename traits::pos_type; +// using off_type = typename traits::off_type; +// using traits_type = traits; +// using allocator_type = Allocator; + +#include +#include + + +int main(int, char**) +{ + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same::int_type>::value), ""); + static_assert((std::is_same::pos_type>::value), ""); + static_assert((std::is_same::off_type>::value), ""); + static_assert((std::is_same>::value), ""); + static_assert((std::is_same>::value), ""); + + static_assert((std::is_same::value), ""); + static_assert((std::is_same >::value), ""); + static_assert((std::is_same::int_type>::value), ""); + static_assert((std::is_same::pos_type>::value), ""); + static_assert((std::is_same::off_type>::value), ""); + static_assert((std::is_same>::value), ""); + static_assert((std::is_same>::value), ""); + + return 0; +} Index: libcxx/utils/generate_feature_test_macro_components.py =================================================================== --- libcxx/utils/generate_feature_test_macro_components.py +++ libcxx/utils/generate_feature_test_macro_components.py @@ -487,7 +487,11 @@ "name": "__cpp_lib_constexpr_dynamic_alloc", "values": { "c++2a": int(201907) }, "headers": ["memory"] - }, + }, { + "name": "__cpp_lib_syncbuf", + "values": {"c++2a": int(201803) }, + "headers": ["syncstream"] + } ]], key=lambda tc: tc["name"]) # Map from each header to the Lit annotations that should be used for