STL/stl/inc/ostream

347 строки
13 KiB
C++

// ostream standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _OSTREAM_
#define _OSTREAM_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <__msvc_ostream.hpp>
#if _HAS_CXX23
#include <__msvc_filebuf.hpp>
#include <__msvc_print.hpp>
#include <format>
#endif // ^^^ _HAS_CXX23 ^^^
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
#if _HAS_CXX20
#ifdef _CPPRTTI
_EXPORT_STD template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& emit_on_flush(basic_ostream<_Elem, _Traits>& _Ostr) {
const auto _Sync_buf_ptr = dynamic_cast<_Basic_syncbuf_impl<_Elem, _Traits>*>(_Ostr.rdbuf());
if (_Sync_buf_ptr) {
_Sync_buf_ptr->set_emit_on_sync(true);
}
return _Ostr;
}
_EXPORT_STD template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& noemit_on_flush(basic_ostream<_Elem, _Traits>& _Ostr) {
const auto _Sync_buf_ptr = dynamic_cast<_Basic_syncbuf_impl<_Elem, _Traits>*>(_Ostr.rdbuf());
if (_Sync_buf_ptr) {
_Sync_buf_ptr->set_emit_on_sync(false);
}
return _Ostr;
}
_EXPORT_STD template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& flush_emit(basic_ostream<_Elem, _Traits>& _Ostr) {
_Ostr.flush();
const auto _Sync_buf_ptr = dynamic_cast<_Basic_syncbuf_impl<_Elem, _Traits>*>(_Ostr.rdbuf());
if (_Sync_buf_ptr) {
ios_base::iostate _State = ios_base::goodbit;
const typename basic_ostream<_Elem, _Traits>::sentry _Ok(_Ostr);
if (!_Ok) {
_State |= ios_base::badbit;
} else {
_TRY_IO_BEGIN
const bool _Emit_failed = !_Sync_buf_ptr->_Do_emit();
if (_Emit_failed) {
_State |= ios_base::badbit;
}
_CATCH_IO_(ios_base, _Ostr)
}
_Ostr.setstate(_State);
}
return _Ostr;
}
#else // ^^^ defined(_CPPRTTI) / !defined(_CPPRTTI) vvv
_EXPORT_STD template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& emit_on_flush(basic_ostream<_Elem, _Traits>&) = delete; // requires /GR option
_EXPORT_STD template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& noemit_on_flush(basic_ostream<_Elem, _Traits>&) = delete; // requires /GR option
_EXPORT_STD template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& flush_emit(basic_ostream<_Elem, _Traits>&) = delete; // requires /GR option
#endif // ^^^ !defined(_CPPRTTI) ^^^
#endif // ^^^ _HAS_CXX20 ^^^
#if _HAS_CXX23
#ifdef _CPPRTTI
template <int = 0>
ios_base::iostate _Print_noformat_nonunicode(ostream& _Ostr, const string_view _Str) {
// *LOCKED*
//
// This function is called from a context in which an ostream::sentry has been
// constructed.
ios_base::iostate _State = ios_base::goodbit;
_TRY_IO_BEGIN
const auto _Characters_written = _Ostr.rdbuf()->sputn(_Str.data(), static_cast<streamsize>(_Str.size()));
const bool _Was_insertion_successful = static_cast<size_t>(_Characters_written) == _Str.size();
if (!_Was_insertion_successful) [[unlikely]] {
_State |= ios_base::badbit;
}
_CATCH_IO_(ios_base, _Ostr)
return _State;
}
template <int = 0>
ios_base::iostate _Print_newline_only_nonunicode(ostream& _Ostr) {
// *LOCKED*
//
// This function is called from a context in which an ostream::sentry has been
// constructed.
ios_base::iostate _State = ios_base::goodbit;
_TRY_IO_BEGIN
const bool _Was_insertion_successful = _Ostr.rdbuf()->sputc('\n') == '\n';
if (!_Was_insertion_successful) [[unlikely]] {
_State |= ios_base::badbit;
}
_CATCH_IO_(ios_base, _Ostr)
return _State;
}
template <int = 0>
void _Vprint_nonunicode_impl(
const _Add_newline _Add_nl, ostream& _Ostr, const string_view _Fmt_str, const format_args _Fmt_args) {
const ostream::sentry _Ok(_Ostr);
ios_base::iostate _State = ios_base::goodbit;
if (!_Ok) [[unlikely]] {
_State |= ios_base::badbit;
} else [[likely]] {
// This is intentionally kept outside of the try/catch block in _Print_noformat_nonunicode()
// (see N4950 [ostream.formatted.print]/3.2).
string _Output_str = _STD vformat(_Ostr.getloc(), _Fmt_str, _Fmt_args);
if (_Add_nl == _Add_newline::_Yes) {
_Output_str.push_back('\n');
}
_State |= _STD _Print_noformat_nonunicode(_Ostr, _Output_str);
}
_Ostr.setstate(_State);
}
template <class _UnicodeConsoleFn, class _FallbackFn, class _Filebuf_type = filebuf>
ios_base::iostate _Do_on_maybe_unicode_console(
ostream& _Ostr, _UnicodeConsoleFn _Unicode_console_func, _FallbackFn _Fallback_func) {
// *LOCKED*
//
// This function is called from a context in which an ostream::sentry has been
// constructed.
ios_base::iostate _State = ios_base::goodbit;
// The std::ostream& overload of vprint_unicode() expects you to determine whether the stream refers
// to a unicode console or not based solely on the std::ostream& provided. That class simply doesn't
// provide enough information to know this in every case. The best we can do (without breaking ABI)
// is check if the underlying std::streambuf object of the std::ostream& actually refers to a std::filebuf
// object. This requires the use of a dynamic_cast. (This is also why the std::ostream& overloads of
// std::print() et al. are deleted when RTTI is disabled.)
streambuf* const _Streambuf = _Ostr.rdbuf();
const auto _Filebuf = dynamic_cast<_Filebuf_type*>(_Streambuf);
// If we got nullptr, then it probably isn't being used for a unicode console...
if (_Filebuf == nullptr) {
_State |= _Fallback_func();
return _State;
}
FILE* const _File_stream = _Filebuf->_Myfile;
const __std_unicode_console_retrieval_result _Unicode_console_retrieval_result{
__std_get_unicode_console_handle_from_file_stream(_File_stream)};
// See the documentation for __std_unicode_console_retrieval_result to understand why we do this.
bool _Is_unicode_console;
#pragma warning(push)
#pragma warning(disable : 4061) // enumerator not explicitly handled by switch label
switch (_Unicode_console_retrieval_result._Error) {
case __std_win_error::_Success:
_Is_unicode_console = true;
break;
case __std_win_error::_File_not_found:
_Is_unicode_console = false;
break;
case __std_win_error::_Not_supported:
[[unlikely]] return _State;
default:
[[unlikely]] return ios_base::failbit;
}
#pragma warning(pop)
if (_Is_unicode_console) {
_TRY_IO_BEGIN
const bool _Was_flush_successful = _Ostr.rdbuf()->pubsync() != -1;
if (!_Was_flush_successful) [[unlikely]] {
_State |= ios_base::badbit;
return _State;
}
const __std_win_error _Unicode_console_print_result =
_Unicode_console_func(_Unicode_console_retrieval_result._Console_handle);
if (_Unicode_console_print_result != __std_win_error::_Success) [[unlikely]] {
_State |= ios_base::badbit;
}
_CATCH_IO_(ios_base, _Ostr)
} else {
_State |= _Fallback_func();
}
return _State;
}
template <int = 0>
ios_base::iostate _Print_noformat_unicode(ostream& _Ostr, const string_view _Str) {
const auto _Unicode_console = [&](const __std_unicode_console_handle _Console_handle) {
return __std_print_to_unicode_console(_Console_handle, _Str.data(), _Str.size());
};
const auto _Fallback = [&] { return _STD _Print_noformat_nonunicode(_Ostr, _Str); };
return _STD _Do_on_maybe_unicode_console(_Ostr, _Unicode_console, _Fallback);
}
template <int = 0>
ios_base::iostate _Print_newline_only_unicode(ostream& _Ostr) {
const auto _Unicode_console = [](const __std_unicode_console_handle _Console_handle) {
return __std_print_newline_only_to_unicode_console(_Console_handle);
};
const auto _Fallback = [&] { return _STD _Print_newline_only_nonunicode(_Ostr); };
return _STD _Do_on_maybe_unicode_console(_Ostr, _Unicode_console, _Fallback);
}
template <int = 0>
void _Vprint_unicode_impl(
const _Add_newline _Add_nl, ostream& _Ostr, const string_view _Fmt_str, const format_args _Fmt_args) {
const ostream::sentry _Ok(_Ostr);
ios_base::iostate _State = ios_base::goodbit;
if (!_Ok) [[unlikely]] {
_State |= ios_base::badbit;
} else [[likely]] {
// This is intentionally kept outside of the try/catch block in _Print_noformat_unicode()
// (see N4950 [ostream.formatted.print]/3.2).
string _Output_str = _STD vformat(_Ostr.getloc(), _Fmt_str, _Fmt_args);
if (_Add_nl == _Add_newline::_Yes) {
_Output_str.push_back('\n');
}
_State |= _STD _Print_noformat_unicode(_Ostr, _Output_str);
}
_Ostr.setstate(_State);
}
template <int = 0>
void _Print_noformat(ostream& _Ostr, const string_view _Str) {
const ostream::sentry _Ok(_Ostr);
ios_base::iostate _State = ios_base::goodbit;
if (!_Ok) [[unlikely]] {
_State |= ios_base::badbit;
} else [[likely]] {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_State |= _STD _Print_noformat_unicode(_Ostr, _Str);
} else {
_State |= _STD _Print_noformat_nonunicode(_Ostr, _Str);
}
}
_Ostr.setstate(_State);
}
template <class... _Types>
void _Print_impl(const _Add_newline _Add_nl, ostream& _Ostr, const format_string<_Types...> _Fmt, _Types&&... _Args) {
constexpr bool _Has_format_args = sizeof...(_Types) > 0;
// This is intentionally kept outside of the try/catch block in _Print_noformat_*()
// (see N4950 [ostream.formatted.print]/3.2).
if constexpr (_Has_format_args) {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Vprint_unicode_impl(_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
} else {
_STD _Vprint_nonunicode_impl(_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
}
} else {
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};
_STD _Print_noformat(_Ostr, _Unescaped_str);
}
}
_EXPORT_STD template <class... _Types>
void print(ostream& _Ostr, const format_string<_Types...> _Fmt, _Types&&... _Args) {
_STD _Print_impl(_Add_newline::_Nope, _Ostr, _Fmt, _STD forward<_Types>(_Args)...);
}
_EXPORT_STD template <class... _Types>
void println(ostream& _Ostr, const format_string<_Types...> _Fmt, _Types&&... _Args) {
_STD _Print_impl(_Add_newline::_Yes, _Ostr, _Fmt, _STD forward<_Types>(_Args)...);
}
_EXPORT_STD template <int = 0> // improves throughput, see GH-2329
void println(ostream& _Ostr) {
const ostream::sentry _Ok(_Ostr);
ios_base::iostate _State = ios_base::goodbit;
if (!_Ok) [[unlikely]] {
_State |= ios_base::badbit;
} else [[likely]] {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_State |= _STD _Print_newline_only_unicode(_Ostr);
} else {
_State |= _STD _Print_newline_only_nonunicode(_Ostr);
}
}
_Ostr.setstate(_State);
}
_EXPORT_STD template <int = 0> // improves throughput, see GH-2329
void vprint_unicode(ostream& _Ostr, const string_view _Fmt_str, const format_args _Fmt_args) {
_STD _Vprint_unicode_impl(_Add_newline::_Nope, _Ostr, _Fmt_str, _Fmt_args);
}
_EXPORT_STD template <int = 0> // improves throughput, see GH-2329
void vprint_nonunicode(ostream& _Ostr, const string_view _Fmt_str, const format_args _Fmt_args) {
_STD _Vprint_nonunicode_impl(_Add_newline::_Nope, _Ostr, _Fmt_str, _Fmt_args);
}
#else // ^^^ defined(_CPPRTTI) / !defined(_CPPRTTI) vvv
_EXPORT_STD template <class... _Types>
void print(ostream&, format_string<_Types...>, _Types&&...) = delete; // requires /GR option
_EXPORT_STD template <class... _Types>
void println(ostream&, format_string<_Types...>, _Types&&...) = delete; // requires /GR option
_EXPORT_STD void vprint_unicode(ostream&, string_view, format_args) = delete; // requires /GR option
_EXPORT_STD void vprint_nonunicode(ostream&, string_view, format_args) = delete; // requires /GR option
#endif // ^^^ !defined(_CPPRTTI) ^^^
#endif // ^^^ _HAS_CXX23 ^^^
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _OSTREAM_