From 6aa63f3bd62c02506b1a7291ab2c819dfe13552a Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Tue, 25 Jul 2023 16:31:52 +0200 Subject: [PATCH] ios: Combine and simplify i/odiagstream We need this for a rare use-case, so maintaining three flavors of diagstream is too expensive. Furthermore, the buffering was removed for simplicity. Signed-off-by: Simon Rozman --- UnitTests/ios.cpp | 20 ++- include/stdex/ios.hpp | 282 ++++++++---------------------------------- 2 files changed, 61 insertions(+), 241 deletions(-) diff --git a/UnitTests/ios.cpp b/UnitTests/ios.cpp index 53bc1ad90..11019843a 100644 --- a/UnitTests/ios.cpp +++ b/UnitTests/ios.cpp @@ -59,18 +59,17 @@ namespace UnitTests TEST_METHOD(diagstream) { constexpr size_t n = 3; + unique_ptr f[n]; + vector fv(n); { - unique_ptr f[n]; - vector fv(n); - for (size_t i = 0; i < n; ++i) - { + for (size_t i = 0; i < n; ++i) { WCHAR path[MAX_PATH]; ExpandEnvironmentStringsW(stdex::sprintf(L"%%temp%%\\file%zu.dat", NULL, i).c_str(), path, _countof(path)); - f[i].reset(new ofstream(path, ios_base::out | ios_base::binary)); + f[i].reset(new std::fstream(path, ios_base::out | ios_base::binary)); fv[i] = f[i].get(); } - stdex::odiagstream d(fv.begin(), fv.end(), 8); + stdex::diagstream d(fv.begin(), fv.end()); srand(0); auto write_some_random = [](_Inout_ ostream& f, _In_ size_t amount) { @@ -87,16 +86,13 @@ namespace UnitTests } { - unique_ptr f[n]; - vector fv(n); - for (size_t i = 0; i < n; ++i) - { + for (size_t i = 0; i < n; ++i) { WCHAR path[MAX_PATH]; ExpandEnvironmentStringsW(stdex::sprintf(L"%%temp%%\\file%zu.dat", NULL, i).c_str(), path, _countof(path)); - f[i].reset(new ifstream(path, ios_base::in | ios_base::binary)); + f[i].reset(new std::fstream(path, ios_base::in | ios_base::binary)); fv[i] = f[i].get(); } - stdex::idiagstream d(fv.begin(), fv.end(), 8); + stdex::diagstream d(fv.begin(), fv.end()); do { uint32_t r; d.read(reinterpret_cast(&r), sizeof(r) / sizeof(char)); diff --git a/include/stdex/ios.hpp b/include/stdex/ios.hpp index a6f2bfaea..48f1d3584 100644 --- a/include/stdex/ios.hpp +++ b/include/stdex/ios.hpp @@ -341,270 +341,95 @@ namespace stdex /// Verifies multiple input streams read the same data. /// template - class basic_idiagstreambuf : public std::basic_streambuf<_Elem, _Traits> + class basic_diagstreambuf : public std::basic_streambuf<_Elem, _Traits> { public: - using guest_stream = std::basic_istream<_Elem, _Traits>; - - basic_idiagstreambuf(_In_reads_(count) const guest_stream** streams, _In_ size_t count, _In_ size_t buf_size = 2048) : - m_streams(stream, count), - m_buf(buf_size) - {} + using guest_stream = std::basic_iostream<_Elem, _Traits>; template - basic_idiagstreambuf(_In_ const _Iter first, _In_ const _Iter last, _In_ size_t buf_size = 2048) : - m_streams(first, last), - m_buf(buf_size) - {} + basic_diagstreambuf(_In_ const _Iter first, _In_ const _Iter last) : m_streams(first, last) {} + basic_diagstreambuf(_In_reads_(count) guest_stream* const* streams, _In_ size_t count) : basic_diagstreambuf(streams, streams + count) {} private: - basic_idiagstreambuf(_In_ const basic_idiagstreambuf<_Elem, _Traits>& other); - basic_idiagstreambuf<_Elem, _Traits>& operator =(_In_ const basic_idiagstreambuf<_Elem, _Traits>& other); - basic_idiagstreambuf(_Inout_ basic_idiagstreambuf<_Elem, _Traits>&& other) noexcept; - basic_idiagstreambuf<_Elem, _Traits>& operator =(_Inout_ basic_idiagstreambuf<_Elem, _Traits>&& other) noexcept; + basic_diagstreambuf(_In_ const basic_diagstreambuf<_Elem, _Traits>& other); + basic_diagstreambuf<_Elem, _Traits>& operator =(_In_ const basic_diagstreambuf<_Elem, _Traits>& other); + basic_diagstreambuf(_Inout_ basic_diagstreambuf<_Elem, _Traits>&& other) noexcept; + basic_diagstreambuf<_Elem, _Traits>& operator =(_Inout_ basic_diagstreambuf<_Elem, _Traits>&& other) noexcept; protected: virtual pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) { - if ((which & std::ios_base::in) && !m_streams.empty()) { - setg(nullptr, nullptr, nullptr); + if (m_streams.empty()) + return pos_type{ off_type{-1} }; + auto r = pos_type{ off_type{-1} }; + if ((which & std::ios_base::in)) { m_streams[0]->seekg(off, way); - bool errors = m_streams[0]->bad(); + r = m_streams[0]->bad() ? pos_type{ off_type{-1} } : m_streams[0]->tellg(); for (size_t i = 1, n = m_streams.size(); i < n; ++i) { m_streams[i]->seekg(off, way); - errors |= m_streams[i]->bad(); + if (m_streams[i]->bad()) + r = pos_type{ off_type{-1} }; } - return errors ? pos_type{ off_type{-1} } : m_streams[0]->tellg(); } - return pos_type{ off_type{-1} }; + if ((which & std::ios_base::out)) { + m_streams[0]->seekp(off, way); + r = m_streams[0]->bad() ? pos_type{ off_type{-1} } : m_streams[0]->tellp(); + for (size_t i = 1, n = m_streams.size(); i < n; ++i) { + m_streams[i]->seekp(off, way); + if (m_streams[i]->bad()) + r = pos_type{ off_type{-1} }; + } + } + return r; } virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) { - if ((which & std::ios_base::in) && !m_streams.empty()) { - setg(nullptr, nullptr, nullptr); - m_streams[0]->seekg(pos); - bool errors = m_streams[0]->bad(); - for (size_t i = 1, n = m_streams.size(); i < n; ++i) { - m_streams[i]->seekg(pos); - errors |= m_streams[i]->bad(); - } - return errors ? pos_type{ off_type{-1} } : m_streams[0]->tellg(); - } - return pos_type{ off_type{-1} }; + return seekoff(pos, std::ios_base::beg, which); } virtual int_type underflow() { + int_type eof = _Traits::eof(); if (m_streams.empty()) - goto error; - size_t cap = m_buf.capacity(); - m_buf.resize(cap); - _Elem* data = m_buf.data(); - m_streams[0]->read(data, cap); - auto read = m_streams[0]->gcount(); - if (!read) - goto error; - m_temp.resize(cap); - _Elem* temp_data = m_temp.data(); + eof; + _Elem data; + m_streams[0]->read(&data, 1); + int_type r = m_streams[0]->gcount() == 1 ? _Traits::to_int_type(data) : eof; for (size_t i = 1, n = m_streams.size(); i < n; ++i) { - m_streams[i]->read(temp_data, cap); - auto temp_read = m_streams[i]->gcount(); - if (read != temp_read || !std::equal(data, data + read, temp_data)) - goto error; + m_streams[i]->read(&data, 1); + int_type temp_r = m_streams[i]->gcount() == 1 ? _Traits::to_int_type(data) : eof; + if (r != temp_r) + r = eof; } - setg(data, data, data + read); - return _Traits::to_int_type(m_buf.front()); - - error: - setg(nullptr, nullptr, nullptr); - return _Traits::eof(); - } - - protected: - std::vector m_streams; - std::vector<_Elem> m_buf, m_temp; - }; - - /// - /// Diagnostic input stream - /// - /// Verifies multiple input streams read the same data. - /// - template - class basic_idiagstream : public std::basic_istream<_Elem, _Traits> - { - public: - using guest_stream = std::basic_istream<_Elem, _Traits>; - - basic_idiagstream(_In_reads_(count) const guest_stream** streams, _In_ size_t count, _In_ size_t buf_size = 2048) : - m_buf(streams, count, buf_size), - std::basic_istream<_Elem, _Traits>(&m_buf) - {} - - template - basic_idiagstream(_In_ const _Iter first, _In_ const _Iter last, _In_ size_t buf_size = 2048) : - m_buf(first, last, buf_size), - std::basic_istream<_Elem, _Traits>(&m_buf) - {} - - protected: - basic_idiagstreambuf<_Elem, _Traits> m_buf; - }; - - using idiagstream = basic_idiagstream>; - using widiagstream = basic_idiagstream>; - - /// - /// Diagnostic output stream buffer - /// - /// Writes to multiple output streams the same data. - /// - template - class basic_odiagstreambuf : public std::basic_streambuf<_Elem, _Traits> - { - public: - using guest_stream = std::basic_ostream<_Elem, _Traits>; - - basic_odiagstreambuf(_In_reads_(count) const guest_stream** streams, _In_ size_t count, _In_ size_t buf_size = 2048) : - m_streams(stream, count), - m_buf(buf_size) - { - setp(m_buf.data(), m_buf.data(), m_buf.data() + m_buf.size()); - } - - template - basic_odiagstreambuf(_In_ const _Iter first, _In_ const _Iter last, _In_ size_t buf_size = 2048) : - m_streams(first, last), - m_buf(buf_size) - {} - - private: - basic_odiagstreambuf(_In_ const basic_odiagstreambuf<_Elem, _Traits>& other); - basic_odiagstreambuf<_Elem, _Traits>& operator =(_In_ const basic_odiagstreambuf<_Elem, _Traits>& other); - basic_odiagstreambuf(_Inout_ basic_odiagstreambuf<_Elem, _Traits>&& other) noexcept; - basic_odiagstreambuf<_Elem, _Traits>& operator =(_Inout_ basic_odiagstreambuf<_Elem, _Traits>&& other) noexcept; - - protected: - virtual pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) - { - if ((which & std::ios_base::out) && !m_streams.empty()) { - if (sync() < 0) - return pos_type{ off_type{-1} }; - m_streams[0]->seekp(off, way); - bool errors = m_streams[0]->bad(); - for (size_t i = 1, n = m_streams.size(); i < n; ++i) { - m_streams[i]->seekp(off, way); - errors |= m_streams[i]->bad(); - } - return errors ? pos_type{ off_type{-1} } : m_streams[0]->tellp(); - } - return pos_type{ off_type{-1} }; - } - - virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) - { - if ((which & std::ios_base::out) && !m_streams.empty()) { - if (sync() < 0) - return pos_type{ off_type{-1} }; - m_streams[0]->seekp(pos); - bool errors = m_streams[0]->bad(); - for (size_t i = 1, n = m_streams.size(); i < n; ++i) { - m_streams[i]->seekp(pos); - errors |= m_streams[i]->bad(); - } - return errors ? pos_type{ off_type{-1} } : m_streams[0]->tellp(); - } - return pos_type{ off_type{-1} }; + return r; } virtual int_type overflow(int_type ch = _Traits::eof()) { - if (sync() < 0) - return _Traits::eof(); if (_Traits::not_eof(ch)) { - m_buf.front() = _Traits::to_char_type(ch); - _Elem* data = m_buf.data(); - setp(data, data + 1, data + m_buf.size()); + _Elem data = _Traits::to_char_type(ch); + bool good = true; + for (size_t i = 0, n = m_streams.size(); i < n; ++i) { + m_streams[i]->write(&data, 1); + good &= m_streams[i]->good(); + } + return good ? 0 : _Traits::eof(); } return 0; } virtual int sync() { - _Elem* data = m_buf.data(); - size_t size = pptr() - pbase(); - if (!size) - return 0; - bool errors = false; - for (size_t i = 0, n = m_streams.size(); i < n; ++i) { - try { m_streams[i]->write(data, size); } - catch (std::exception) { errors = true; } - if (!m_streams[i]->good()) - errors = true; - } - setp(data, data, data + m_buf.size()); - return errors ? -1 : 0; + int r = 0; + for (size_t i = 0, n = m_streams.size(); i < n; ++i) + if (m_streams[i]->sync() < 0) + r = -1; + return r; } protected: std::vector m_streams; - std::vector<_Elem> m_buf; - }; - - /// - /// Diagnostic output stream - /// - /// Writes to multiple output streams the same data. - /// - template - class basic_odiagstream : public std::basic_ostream<_Elem, _Traits> - { - public: - using guest_stream = std::basic_ostream<_Elem, _Traits>; - - basic_odiagstream(_In_reads_(count) const guest_stream** streams, _In_ size_t count, _In_ size_t buf_size = 2048) : - m_buf(streams, count, buf_size), - std::basic_ostream<_Elem, _Traits>(&m_buf) - {} - - template - basic_odiagstream(_In_ const _Iter first, _In_ const _Iter last, _In_ size_t buf_size = 2048) : - m_buf(first, last, buf_size), - std::basic_ostream<_Elem, _Traits>(&m_buf) - {} - - protected: - basic_odiagstreambuf<_Elem, _Traits> m_buf; - }; - - using odiagstream = basic_odiagstream>; - using wodiagstream = basic_odiagstream>; - - /// - /// Diagnostic input/output stream buffer - /// - /// Verifies multiple input streams read the same data. - /// Writes to multiple output streams the same data. - /// - template - class basic_diagstreambuf : - public basic_idiagstreambuf<_Elem, _Traits>, - public basic_odiagstreambuf<_Elem, _Traits> - { - public: - using guest_stream = std::basic_iostream<_Elem, _Traits>; - - basic_diagstreambuf(_In_reads_(count) const guest_stream** streams, _In_ size_t count, _In_ size_t buf_sizeg = 2048, _In_ size_t buf_sizep = 2048) : - basic_idiagstreambuf<_Elem, _Traits>(streams, count, buf_sizeg), - basic_odiagstreambuf<_Elem, _Traits>(streams, count, buf_sizep) - {} - - template - basic_diagstreambuf(_In_ const _Iter first, _In_ const _Iter last, _In_ size_t buf_sizeg = 2048, _In_ size_t buf_sizep = 2048) : - basic_idiagstreambuf<_Elem, _Traits>(first, last, buf_sizeg), - basic_odiagstreambuf<_Elem, _Traits>(first, last, buf_sizep) - {} }; /// @@ -619,15 +444,14 @@ namespace stdex public: using guest_stream = std::basic_iostream<_Elem, _Traits>; - basic_diagstream(_In_reads_(count) const guest_stream** streams, _In_ size_t count, _In_ size_t buf_sizeg = 2048, _In_ size_t buf_sizep = 2048) : - m_buf(streams, count, buf_sizeg, buf_sizep), + template + basic_diagstream(_In_ const _Iter first, _In_ const _Iter last) : + m_buf(first, last), std::basic_iostream<_Elem, _Traits>(&m_buf) {} - template - basic_diagstream(_In_ const _Iter first, _In_ const _Iter last, _In_ size_t buf_sizeg = 2048, _In_ size_t buf_sizep = 2048) : - m_buf(first, last, buf_sizeg, buf_sizep), - std::basic_iostream<_Elem, _Traits>(&m_buf) + basic_diagstream(_In_reads_(count) guest_stream* const* streams, _In_ size_t count) : + basic_diagstream(streams, streams + count) {} protected: