__ret_os << __x;
return __ret_os;
}
+
+#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+ template<typename _CharT, typename _Traits>
+ class __syncbuf_base : public basic_streambuf<_CharT, _Traits>
+ {
+ public:
+ static bool*
+ _S_get(basic_streambuf<_CharT, _Traits>* __buf) noexcept
+ {
+ if (auto __p = dynamic_cast<__syncbuf_base*>(__buf))
+ return &__p->_M_emit_on_sync;
+ return nullptr;
+ }
+
+ protected:
+ __syncbuf_base(basic_streambuf<_CharT, _Traits>* __w = nullptr)
+ : _M_wrapped(__w)
+ { }
+
+ basic_streambuf<_CharT, _Traits>* _M_wrapped = nullptr;
+ bool _M_emit_on_sync = false;
+ bool _M_needs_sync = false;
+ };
+
+ template<typename _CharT, typename _Traits>
+ inline basic_ostream<_CharT, _Traits>&
+ emit_on_flush(basic_ostream<_CharT, _Traits>& __os)
+ {
+ if (bool* __flag = __syncbuf_base<_CharT, _Traits>::_S_get(__os.rdbuf()))
+ *__flag = true;
+ return __os;
+ }
+
+ template<typename _CharT, typename _Traits>
+ inline basic_ostream<_CharT, _Traits>&
+ noemit_on_flush(basic_ostream<_CharT, _Traits>& __os)
+ {
+ if (bool* __flag = __syncbuf_base<_CharT, _Traits>::_S_get(__os.rdbuf()))
+ *__flag = false;
+ return __os;
+ }
+
+ template<typename _CharT, typename _Traits>
+ inline basic_ostream<_CharT, _Traits>&
+ flush_emit(basic_ostream<_CharT, _Traits>& __os)
+ {
+ struct _Restore
+ {
+ ~_Restore() { *_M_flag = _M_prev; }
+
+ bool _M_prev = false;
+ bool* _M_flag = &_M_prev;
+ } __restore;
+
+ if (bool* __flag = __syncbuf_base<_CharT, _Traits>::_S_get(__os.rdbuf()))
+ {
+ __restore._M_prev = *__flag;
+ __restore._M_flag = __flag;
+ *__flag = true;
+ }
+
+ __os.flush();
+ return __os;
+ }
+
+#endif // C++20
+
#endif // C++11
_GLIBCXX_END_NAMESPACE_VERSION
template<typename _CharT, typename _Traits = char_traits<_CharT>,
typename _Alloc = allocator<_CharT>>
- class basic_syncbuf : public basic_streambuf<_CharT, _Traits>
+ class basic_syncbuf : public __syncbuf_base<_CharT, _Traits>
{
public:
using char_type = _CharT;
explicit
basic_syncbuf(streambuf_type* __obuf)
- : basic_syncbuf(__obuf, allocator_type{})
+ : basic_syncbuf(__obuf, allocator_type{})
{ }
basic_syncbuf(streambuf_type* __obuf, const allocator_type& __alloc)
- : _M_wrapped(__obuf)
- , _M_impl(__alloc)
- , _M_mtx(__obuf)
+ : __syncbuf_base<_CharT, _Traits>(__obuf)
+ , _M_impl(__alloc)
+ , _M_mtx(__obuf)
{ }
basic_syncbuf(basic_syncbuf&& __other)
- : _M_wrapped(__other._M_wrapped)
- , _M_impl(std::move(__other._M_impl))
- , _M_mtx(std::move(__other._M_mtx))
- , _M_emit_on_sync(__other._M_emit_on_sync)
- , _M_needs_sync(__other._M_needs_sync)
+ : __syncbuf_base<_CharT, _Traits>(__other._M_wrapped)
+ , _M_impl(std::move(__other._M_impl))
+ , _M_mtx(std::move(__other._M_mtx))
{
+ this->_M_emit_on_sync = __other._M_emit_on_sync;
+ this->_M_needs_sync = __other._M_needs_sync;
__other._M_wrapped = nullptr;
}
{ }
}
- basic_syncbuf& operator=(basic_syncbuf&& __other)
+ basic_syncbuf&
+ operator=(basic_syncbuf&& __other)
{
- if (std::__addressof(__other) != this)
- {
- emit();
+ emit();
+
+ _M_impl = std::move(__other._M_impl);
+ this->_M_emit_on_sync = __other._M_emit_on_sync;
+ this->_M_needs_sync = __other._M_needs_sync;
+ this->_M_wrapped = __other._M_wrapped;
+ __other._M_wrapped = nullptr;
+ _M_mtx = std::move(__other._M_mtx);
- _M_impl = std::move(__other._M_impl);
- _M_wrapped = __other._M_wrapped; __other._M_wrapped = nullptr;
- _M_mtx = std::move(__other._M_mtx);
- _M_emit_on_sync = __other._M_emit_on_sync;
- _M_needs_sync = __other._M_needs_sync;
- }
return *this;
}
void
- swap(basic_syncbuf& __other)
+ swap(basic_syncbuf& __other) noexcept
{
- if (std::__addressof(__other) != this)
- {
- std::swap(_M_impl, __other._M_impl);
- std::swap(_M_wrapped, __other._M_wrapped);
- std::swap(_M_mtx, __other._M_mtx);
- std::swap(_M_emit_on_sync, __other._M_emit_on_sync);
- std::swap(_M_needs_sync, __other._M_needs_sync);
- }
+ using _ATr = allocator_traits<_Alloc>;
+ if constexpr (!_ATr::propagate_on_container_swap::value)
+ __glibcxx_assert(get_allocator() == __other.get_allocator());
+
+ std::swap(_M_impl, __other._M_impl);
+ std::swap(this->_M_emit_on_sync, __other._M_emit_on_sync);
+ std::swap(this->_M_needs_sync, __other._M_needs_sync);
+ std::swap(this->_M_wrapped, __other._M_wrapped);
+ std::swap(_M_mtx, __other._M_mtx);
}
bool
emit()
{
- if (!_M_wrapped)
+ if (!this->_M_wrapped)
return false;
- auto __s = _M_impl.view();
- if (__s.empty())
- return true;
+ auto __s = std::move(_M_impl).str();
const lock_guard<__mutex> __l(_M_mtx);
- if (_M_wrapped->sputn(__s.data(), __s.size()) != __s.size())
- return false;
+ if (auto __size = __s.size())
+ {
+ auto __n = this->_M_wrapped->sputn(__s.data(), __size);
+ if (__n != __size)
+ {
+ __s.erase(0, __n);
+ _M_impl.str(std::move(__s));
+ return false;
+ }
+ }
- if (_M_needs_sync)
+ if (this->_M_needs_sync)
{
- _M_needs_sync = false;
- if (_M_wrapped->pubsync() != 0)
+ this->_M_needs_sync = false;
+ if (this->_M_wrapped->pubsync() != 0)
return false;
}
-
- _M_impl.str("");
return true;
}
streambuf_type*
get_wrapped() const noexcept
- { return _M_wrapped; }
+ { return this->_M_wrapped; }
- allocator_type get_allocator() const noexcept
+ allocator_type
+ get_allocator() const noexcept
{ return _M_impl.get_allocator(); }
void
set_emit_on_sync(bool __b) noexcept
- { _M_emit_on_sync = __b; }
+ { this->_M_emit_on_sync = __b; }
protected:
int
sync() override
{
- auto __res = _M_impl.pubsync();
- if (__res == 0)
- {
- _M_needs_sync = true;
- if (_M_emit_on_sync)
- return emit() ? 0 : -1;
- }
- return __res;
+ this->_M_needs_sync = true;
+ if (this->_M_emit_on_sync && !emit())
+ return -1;
+ return 0;
+ }
+
+ int_type
+ overflow(int_type __c) override
+ {
+ int_type __eof = traits_type::eof();
+ if (__builtin_expect(!traits_type::eq_int_type(__c, __eof), true))
+ return _M_impl.sputc(__c);
+ return __eof;
}
streamsize
{ return _M_impl.sputn(__s, __n); }
private:
- streambuf_type* _M_wrapped;
-
- using __impl_type = basic_stringbuf<char_type, traits_type,
- allocator_type>;
- __impl_type _M_impl;
+ basic_stringbuf<char_type, traits_type, allocator_type> _M_impl;
struct __mutex
{
void
lock()
{
- if (_M_mtx)
- _M_mtx->lock();
+ _M_mtx->lock();
}
void
unlock()
{
- if (_M_mtx)
- _M_mtx->unlock();
+ _M_mtx->unlock();
}
// FIXME: This should be put in the .so
return __m[__key];
}
#else
- __mutex(void*)
- { }
-
- void
- swap(__mutex&&) noexcept
- { }
-
- void
- lock()
- { }
-
- void
- unlock()
- { }
+ __mutex(void*) { }
+ void swap(__mutex&&) noexcept { }
+ void lock() { }
+ void unlock() { }
#endif
- __mutex(const __mutex&) = delete;
- __mutex& operator=(const __mutex&) = delete;
-
__mutex(__mutex&&) = default;
__mutex& operator=(__mutex&&) = default;
};
__mutex _M_mtx;
-
- bool _M_emit_on_sync = false;
- bool _M_needs_sync = false;
};
template <typename _CharT, typename _Traits = char_traits<_CharT>,
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target cxx11-abi }
+
+#include <syncstream>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::stringbuf sb;
+ std::osyncstream s(&sb);
+ s << "abc" << std::emit_on_flush << "def" << std::flush << "ghi"
+ << std::emit_on_flush << std::noemit_on_flush << std::endl;
+ VERIFY( sb.view() == "abcdef" );
+ s << "jkl" << std::flush_emit << "mno" << std::flush;
+ VERIFY( sb.view() == "abcdefghi\njkl" );
+ s.emit();
+ VERIFY( sb.view() == "abcdefghi\njklmno" );
+}
+
+int
+main()
+{
+ test01();
+}