2 // Copyright (c) 2012 Artyom Beilis (Tonkikh)
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 #ifndef BOOST_NOWIDE_FSTREAM_HPP_INCLUDED
9 #define BOOST_NOWIDE_FSTREAM_HPP_INCLUDED
11 #include <boost/nowide/config.hpp>
12 #include <boost/nowide/detail/is_path.hpp>
13 #include <boost/nowide/filebuf.hpp>
25 static std::ios_base::openmode mode() { return std::ios_base::in; }
26 static std::ios_base::openmode mode_modifier() { return mode(); }
27 template<typename CharType, typename Traits>
29 using type = std::basic_istream<CharType, Traits>;
34 static std::ios_base::openmode mode() { return std::ios_base::out; }
35 static std::ios_base::openmode mode_modifier() { return mode(); }
36 template<typename CharType, typename Traits>
38 using type = std::basic_ostream<CharType, Traits>;
41 struct StreamTypeInOut
43 static std::ios_base::openmode mode() { return std::ios_base::in | std::ios_base::out; }
44 static std::ios_base::openmode mode_modifier() { return std::ios_base::openmode(); }
45 template<typename CharType, typename Traits>
47 using type = std::basic_iostream<CharType, Traits>;
52 /// Base class for all basic_*fstream classes
53 /// Contains basic_filebuf instance so its pointer can be used to construct basic_*stream
54 /// Provides common functions to reduce boilerplate code including inheriting from
55 /// the correct std::basic_[io]stream class and initializing it
56 /// \tparam T_StreamType One of StreamType* above.
57 /// Class used instead of value, because openmode::operator| may not be constexpr
58 /// \tparam FileBufType Discriminator to force a differing ABI if depending on the contained filebuf
59 template<typename CharType,
61 typename T_StreamType,
62 int FileBufType = BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT>
69 /// \brief Same as std::basic_ifstream<char> but accepts UTF-8 strings under Windows
71 template<typename CharType, typename Traits = std::char_traits<CharType>>
72 class basic_ifstream : public detail::fstream_impl<CharType, Traits, detail::StreamTypeIn>
74 using fstream_impl = detail::fstream_impl<CharType, Traits, detail::StreamTypeIn>;
80 explicit basic_ifstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::in)
82 open(file_name, mode);
84 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
85 explicit basic_ifstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::in)
87 open(file_name, mode);
91 explicit basic_ifstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::in)
93 open(file_name, mode);
96 template<typename Path>
97 explicit basic_ifstream(const Path& file_name,
98 detail::enable_if_path_t<Path, std::ios_base::openmode> mode = std::ios_base::in)
100 open(file_name, mode);
102 using fstream_impl::open;
103 using fstream_impl::is_open;
104 using fstream_impl::close;
105 using fstream_impl::rdbuf;
106 using fstream_impl::swap;
107 basic_ifstream(const basic_ifstream&) = delete;
108 basic_ifstream& operator=(const basic_ifstream&) = delete;
109 basic_ifstream(basic_ifstream&& other) noexcept : fstream_impl(std::move(other))
111 basic_ifstream& operator=(basic_ifstream&& rhs) noexcept
113 fstream_impl::operator=(std::move(rhs));
119 /// \brief Same as std::basic_ofstream<char> but accepts UTF-8 strings under Windows
122 template<typename CharType, typename Traits = std::char_traits<CharType>>
123 class basic_ofstream : public detail::fstream_impl<CharType, Traits, detail::StreamTypeOut>
125 using fstream_impl = detail::fstream_impl<CharType, Traits, detail::StreamTypeOut>;
130 explicit basic_ofstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::out)
132 open(file_name, mode);
134 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
135 explicit basic_ofstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::out)
137 open(file_name, mode);
140 explicit basic_ofstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::out)
142 open(file_name, mode);
144 template<typename Path>
145 explicit basic_ofstream(const Path& file_name,
146 detail::enable_if_path_t<Path, std::ios_base::openmode> mode = std::ios_base::out)
148 open(file_name, mode);
151 using fstream_impl::open;
152 using fstream_impl::is_open;
153 using fstream_impl::close;
154 using fstream_impl::rdbuf;
155 using fstream_impl::swap;
156 basic_ofstream(const basic_ofstream&) = delete;
157 basic_ofstream& operator=(const basic_ofstream&) = delete;
158 basic_ofstream(basic_ofstream&& other) noexcept : fstream_impl(std::move(other))
160 basic_ofstream& operator=(basic_ofstream&& rhs)
162 fstream_impl::operator=(std::move(rhs));
168 #pragma warning(push)
169 #pragma warning(disable : 4250) // <class> : inherits <method> via dominance
172 /// \brief Same as std::basic_fstream<char> but accepts UTF-8 strings under Windows
174 template<typename CharType, typename Traits = std::char_traits<CharType>>
175 class basic_fstream : public detail::fstream_impl<CharType, Traits, detail::StreamTypeInOut>
177 using fstream_impl = detail::fstream_impl<CharType, Traits, detail::StreamTypeInOut>;
182 explicit basic_fstream(const char* file_name,
183 std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
185 open(file_name, mode);
187 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
188 explicit basic_fstream(const wchar_t* file_name,
189 std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
191 open(file_name, mode);
194 explicit basic_fstream(const std::string& file_name,
195 std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
197 open(file_name, mode);
199 template<typename Path>
200 explicit basic_fstream(const Path& file_name,
201 detail::enable_if_path_t<Path, std::ios_base::openmode> mode = std::ios_base::in
202 | std::ios_base::out)
204 open(file_name, mode);
207 using fstream_impl::open;
208 using fstream_impl::is_open;
209 using fstream_impl::close;
210 using fstream_impl::rdbuf;
211 using fstream_impl::swap;
212 basic_fstream(const basic_fstream&) = delete;
213 basic_fstream& operator=(const basic_fstream&) = delete;
214 basic_fstream(basic_fstream&& other) noexcept : fstream_impl(std::move(other))
216 basic_fstream& operator=(basic_fstream&& rhs)
218 fstream_impl::operator=(std::move(rhs));
222 template<typename CharType, typename Traits>
223 void swap(basic_filebuf<CharType, Traits>& lhs, basic_filebuf<CharType, Traits>& rhs)
227 template<typename CharType, typename Traits>
228 void swap(basic_ifstream<CharType, Traits>& lhs, basic_ifstream<CharType, Traits>& rhs)
232 template<typename CharType, typename Traits>
233 void swap(basic_ofstream<CharType, Traits>& lhs, basic_ofstream<CharType, Traits>& rhs)
237 template<typename CharType, typename Traits>
238 void swap(basic_fstream<CharType, Traits>& lhs, basic_fstream<CharType, Traits>& rhs)
244 /// Same as std::filebuf but accepts UTF-8 strings under Windows
246 using filebuf = basic_filebuf<char>;
248 /// Same as std::ifstream but accepts UTF-8 strings under Windows
249 /// and *\::filesystem::path on all systems
251 using ifstream = basic_ifstream<char>;
253 /// Same as std::ofstream but accepts UTF-8 strings under Windows
254 /// and *\::filesystem::path on all systems
256 using ofstream = basic_ofstream<char>;
258 /// Same as std::fstream but accepts UTF-8 strings under Windows
259 /// and *\::filesystem::path on all systems
261 using fstream = basic_fstream<char>;
265 /// Holds an instance of T
266 /// Required to make sure this is constructed first before passing it to sibling classes
272 template<typename CharType, typename Traits, typename T_StreamType, int>
273 class fstream_impl : private buf_holder<basic_filebuf<CharType, Traits>>, // must be first due to init order
274 public T_StreamType::template stream_base<CharType, Traits>::type
276 using internal_buffer_type = basic_filebuf<CharType, Traits>;
277 using base_buf_holder = buf_holder<internal_buffer_type>;
278 using stream_base = typename T_StreamType::template stream_base<CharType, Traits>::type;
281 using stream_base::setstate;
282 using stream_base::clear;
285 using base_buf_holder::buf_;
287 fstream_impl() : stream_base(&buf_)
289 fstream_impl(const fstream_impl&) = delete;
290 fstream_impl& operator=(const fstream_impl&) = delete;
292 // coverity[exn_spec_violation]
293 fstream_impl(fstream_impl&& other) noexcept :
294 base_buf_holder(std::move(other)), stream_base(std::move(other))
296 this->set_rdbuf(rdbuf());
298 fstream_impl& operator=(fstream_impl&& rhs) noexcept
300 base_buf_holder::operator=(std::move(rhs));
301 stream_base::operator=(std::move(rhs));
304 void swap(fstream_impl& other)
306 stream_base::swap(other);
307 rdbuf()->swap(*other.rdbuf());
310 void open(const std::string& file_name, std::ios_base::openmode mode = T_StreamType::mode())
312 open(file_name.c_str(), mode);
314 template<typename Path>
315 detail::enable_if_path_t<Path, void> open(const Path& file_name,
316 std::ios_base::openmode mode = T_StreamType::mode())
318 open(file_name.c_str(), mode);
320 void open(const char* file_name, std::ios_base::openmode mode = T_StreamType::mode())
322 if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier()))
323 setstate(std::ios_base::failbit);
327 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
328 void open(const wchar_t* file_name, std::ios_base::openmode mode = T_StreamType::mode())
330 if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier()))
331 setstate(std::ios_base::failbit);
338 return rdbuf()->is_open();
342 return rdbuf()->is_open();
346 if(!rdbuf()->close())
347 setstate(std::ios_base::failbit);
350 internal_buffer_type* rdbuf() const
352 return const_cast<internal_buffer_type*>(&buf_);
358 } // namespace detail
359 } // namespace nowide