// // Copyright (c) 2012 Artyom Beilis (Tonkikh) // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_NOWIDE_FSTREAM_HPP_INCLUDED #define BOOST_NOWIDE_FSTREAM_HPP_INCLUDED #include #include #include #include #include #include namespace boost { namespace nowide { /// \cond INTERNAL namespace detail { // clang-format off struct StreamTypeIn { static std::ios_base::openmode mode() { return std::ios_base::in; } static std::ios_base::openmode mode_modifier() { return mode(); } template struct stream_base{ using type = std::basic_istream; }; }; struct StreamTypeOut { static std::ios_base::openmode mode() { return std::ios_base::out; } static std::ios_base::openmode mode_modifier() { return mode(); } template struct stream_base{ using type = std::basic_ostream; }; }; struct StreamTypeInOut { static std::ios_base::openmode mode() { return std::ios_base::in | std::ios_base::out; } static std::ios_base::openmode mode_modifier() { return std::ios_base::openmode(); } template struct stream_base{ using type = std::basic_iostream; }; }; // clang-format on /// Base class for all basic_*fstream classes /// Contains basic_filebuf instance so its pointer can be used to construct basic_*stream /// Provides common functions to reduce boilerplate code including inheriting from /// the correct std::basic_[io]stream class and initializing it /// \tparam T_StreamType One of StreamType* above. /// Class used instead of value, because openmode::operator| may not be constexpr /// \tparam FileBufType Discriminator to force a differing ABI if depending on the contained filebuf template class fstream_impl; } // namespace detail /// \endcond /// /// \brief Same as std::basic_ifstream but accepts UTF-8 strings under Windows /// template> class basic_ifstream : public detail::fstream_impl { using fstream_impl = detail::fstream_impl; public: basic_ifstream() {} explicit basic_ifstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::in) { open(file_name, mode); } #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS explicit basic_ifstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::in) { open(file_name, mode); } #endif explicit basic_ifstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::in) { open(file_name, mode); } template explicit basic_ifstream(const Path& file_name, detail::enable_if_path_t mode = std::ios_base::in) { open(file_name, mode); } using fstream_impl::open; using fstream_impl::is_open; using fstream_impl::close; using fstream_impl::rdbuf; using fstream_impl::swap; basic_ifstream(const basic_ifstream&) = delete; basic_ifstream& operator=(const basic_ifstream&) = delete; basic_ifstream(basic_ifstream&& other) noexcept : fstream_impl(std::move(other)) {} basic_ifstream& operator=(basic_ifstream&& rhs) noexcept { fstream_impl::operator=(std::move(rhs)); return *this; } }; /// /// \brief Same as std::basic_ofstream but accepts UTF-8 strings under Windows /// template> class basic_ofstream : public detail::fstream_impl { using fstream_impl = detail::fstream_impl; public: basic_ofstream() {} explicit basic_ofstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::out) { open(file_name, mode); } #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS explicit basic_ofstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::out) { open(file_name, mode); } #endif explicit basic_ofstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::out) { open(file_name, mode); } template explicit basic_ofstream(const Path& file_name, detail::enable_if_path_t mode = std::ios_base::out) { open(file_name, mode); } using fstream_impl::open; using fstream_impl::is_open; using fstream_impl::close; using fstream_impl::rdbuf; using fstream_impl::swap; basic_ofstream(const basic_ofstream&) = delete; basic_ofstream& operator=(const basic_ofstream&) = delete; basic_ofstream(basic_ofstream&& other) noexcept : fstream_impl(std::move(other)) {} basic_ofstream& operator=(basic_ofstream&& rhs) { fstream_impl::operator=(std::move(rhs)); return *this; } }; #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable : 4250) // : inherits via dominance #endif /// /// \brief Same as std::basic_fstream but accepts UTF-8 strings under Windows /// template> class basic_fstream : public detail::fstream_impl { using fstream_impl = detail::fstream_impl; public: basic_fstream() {} explicit basic_fstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { open(file_name, mode); } #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS explicit basic_fstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { open(file_name, mode); } #endif explicit basic_fstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { open(file_name, mode); } template explicit basic_fstream(const Path& file_name, detail::enable_if_path_t mode = std::ios_base::in | std::ios_base::out) { open(file_name, mode); } using fstream_impl::open; using fstream_impl::is_open; using fstream_impl::close; using fstream_impl::rdbuf; using fstream_impl::swap; basic_fstream(const basic_fstream&) = delete; basic_fstream& operator=(const basic_fstream&) = delete; basic_fstream(basic_fstream&& other) noexcept : fstream_impl(std::move(other)) {} basic_fstream& operator=(basic_fstream&& rhs) { fstream_impl::operator=(std::move(rhs)); return *this; } }; template void swap(basic_ifstream& lhs, basic_ifstream& rhs) { lhs.swap(rhs); } template void swap(basic_ofstream& lhs, basic_ofstream& rhs) { lhs.swap(rhs); } template void swap(basic_fstream& lhs, basic_fstream& rhs) { lhs.swap(rhs); } /// /// Same as std::filebuf but accepts UTF-8 strings under Windows /// using filebuf = basic_filebuf; /// /// Same as std::ifstream but accepts UTF-8 strings under Windows /// and *\::filesystem::path on all systems /// using ifstream = basic_ifstream; /// /// Same as std::ofstream but accepts UTF-8 strings under Windows /// and *\::filesystem::path on all systems /// using ofstream = basic_ofstream; /// /// Same as std::fstream but accepts UTF-8 strings under Windows /// and *\::filesystem::path on all systems /// using fstream = basic_fstream; // Implementation namespace detail { /// Holds an instance of T /// Required to make sure this is constructed first before passing it to sibling classes template struct buf_holder { T buf_; }; template class fstream_impl : private buf_holder>, // must be first due to init order public T_StreamType::template stream_base::type { using internal_buffer_type = basic_filebuf; using base_buf_holder = buf_holder; using stream_base = typename T_StreamType::template stream_base::type; public: using stream_base::setstate; using stream_base::clear; protected: using base_buf_holder::buf_; fstream_impl() : stream_base(&buf_) {} fstream_impl(const fstream_impl&) = delete; fstream_impl& operator=(const fstream_impl&) = delete; // coverity[exn_spec_violation] fstream_impl(fstream_impl&& other) noexcept : base_buf_holder(std::move(other)), stream_base(std::move(other)) { this->set_rdbuf(rdbuf()); } fstream_impl& operator=(fstream_impl&& rhs) noexcept { base_buf_holder::operator=(std::move(rhs)); stream_base::operator=(std::move(rhs)); return *this; } void swap(fstream_impl& other) { stream_base::swap(other); rdbuf()->swap(*other.rdbuf()); } void open(const std::string& file_name, std::ios_base::openmode mode = T_StreamType::mode()) { open(file_name.c_str(), mode); } template detail::enable_if_path_t open(const Path& file_name, std::ios_base::openmode mode = T_StreamType::mode()) { open(file_name.c_str(), mode); } void open(const char* file_name, std::ios_base::openmode mode = T_StreamType::mode()) { if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier())) setstate(std::ios_base::failbit); else clear(); } #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS void open(const wchar_t* file_name, std::ios_base::openmode mode = T_StreamType::mode()) { if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier())) setstate(std::ios_base::failbit); else clear(); } #endif bool is_open() { return rdbuf()->is_open(); } bool is_open() const { return rdbuf()->is_open(); } void close() { if(!rdbuf()->close()) setstate(std::ios_base::failbit); } internal_buffer_type* rdbuf() const { return const_cast(&buf_); } }; #ifdef BOOST_MSVC #pragma warning(pop) #endif } // namespace detail } // namespace nowide } // namespace boost #endif