// // 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 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{ typedef std::basic_istream type; }; }; 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{ typedef std::basic_ostream type; }; }; 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{ typedef std::basic_iostream type; }; }; // 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; template struct enable_if_path; } // namespace detail /// \endcond /// /// \brief Same as std::basic_ifstream but accepts UTF-8 strings under Windows /// template > class basic_ifstream : public detail::fstream_impl { typedef detail::fstream_impl 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, typename detail::enable_if_path::type 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 { typedef detail::fstream_impl 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, typename detail::enable_if_path::type 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 { typedef detail::fstream_impl 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, typename detail::enable_if_path::type 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_filebuf& lhs, basic_filebuf& rhs) { lhs.swap(rhs); } 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 /// typedef basic_filebuf filebuf; /// /// Same as std::ifstream but accepts UTF-8 strings under Windows /// and *\::filesystem::path on all systems /// typedef basic_ifstream ifstream; /// /// Same as std::ofstream but accepts UTF-8 strings under Windows /// and *\::filesystem::path on all systems /// typedef basic_ofstream ofstream; /// /// Same as std::fstream but accepts UTF-8 strings under Windows /// and *\::filesystem::path on all systems /// typedef basic_fstream 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 { typedef basic_filebuf internal_buffer_type; typedef buf_holder base_buf_holder; typedef typename T_StreamType::template stream_base::type stream_base; 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 typename detail::enable_if_path::type 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 /// Trait to heuristically check for a *\::filesystem::path /// Done by checking for make_preferred and filename member functions with correct signature template struct is_path { typedef char one; struct two { char dummy[2]; }; template struct Check; template static one test(Check*); template static two test(...); enum { value = sizeof(test(0)) == sizeof(one) }; }; template struct enable_if {}; template struct enable_if { typedef T type; }; /// SFINAE trait which has a member "type = Result" if the Path is a *\::filesystem::path template struct enable_if_path : enable_if::value, Result> {}; } // namespace detail } // namespace nowide } // namespace boost #endif