• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright (c) 2012 Artyom Beilis (Tonkikh)
3 //
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)
7 //
8 #ifndef BOOST_NOWIDE_FSTREAM_HPP_INCLUDED
9 #define BOOST_NOWIDE_FSTREAM_HPP_INCLUDED
10 
11 #include <boost/nowide/config.hpp>
12 #include <boost/nowide/filebuf.hpp>
13 #include <istream>
14 #include <ostream>
15 
16 namespace boost {
17 namespace nowide {
18     /// \cond INTERNAL
19     namespace detail {
20         // clang-format off
21         struct StreamTypeIn
22         {
modeboost::nowide::detail::StreamTypeIn23             static std::ios_base::openmode mode() { return std::ios_base::in; }
mode_modifierboost::nowide::detail::StreamTypeIn24             static std::ios_base::openmode mode_modifier() { return mode(); }
25             template<typename CharType, typename Traits>
26             struct stream_base{
27                 typedef std::basic_istream<CharType, Traits> type;
28             };
29         };
30         struct StreamTypeOut
31         {
modeboost::nowide::detail::StreamTypeOut32             static std::ios_base::openmode mode() { return std::ios_base::out; }
mode_modifierboost::nowide::detail::StreamTypeOut33             static std::ios_base::openmode mode_modifier() { return mode(); }
34             template<typename CharType, typename Traits>
35             struct stream_base{
36                 typedef std::basic_ostream<CharType, Traits> type;
37             };
38         };
39         struct StreamTypeInOut
40         {
modeboost::nowide::detail::StreamTypeInOut41             static std::ios_base::openmode mode() { return std::ios_base::in | std::ios_base::out; }
mode_modifierboost::nowide::detail::StreamTypeInOut42             static std::ios_base::openmode mode_modifier() { return std::ios_base::openmode(); }
43             template<typename CharType, typename Traits>
44             struct stream_base{
45                 typedef std::basic_iostream<CharType, Traits> type;
46             };
47         };
48         // clang-format on
49 
50         /// Base class for all basic_*fstream classes
51         /// Contains basic_filebuf instance so its pointer can be used to construct basic_*stream
52         /// Provides common functions to reduce boilerplate code including inheriting from
53         /// the correct std::basic_[io]stream class and initializing it
54         /// \tparam T_StreamType One of StreamType* above.
55         ///         Class used instead of value, because openmode::operator| may not be constexpr
56         /// \tparam FileBufType Discriminator to force a differing ABI if depending on the contained filebuf
57         template<typename CharType,
58                  typename Traits,
59                  typename T_StreamType,
60                  int FileBufType = BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT>
61         class fstream_impl;
62 
63         template<typename Path, typename Result>
64         struct enable_if_path;
65     } // namespace detail
66     /// \endcond
67 
68     ///
69     /// \brief Same as std::basic_ifstream<char> but accepts UTF-8 strings under Windows
70     ///
71     template<typename CharType, typename Traits = std::char_traits<CharType> >
72     class basic_ifstream : public detail::fstream_impl<CharType, Traits, detail::StreamTypeIn>
73     {
74         typedef detail::fstream_impl<CharType, Traits, detail::StreamTypeIn> fstream_impl;
75 
76     public:
basic_ifstream()77         basic_ifstream()
78         {}
79 
basic_ifstream(const char * file_name,std::ios_base::openmode mode=std::ios_base::in)80         explicit basic_ifstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::in)
81         {
82             open(file_name, mode);
83         }
84 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
basic_ifstream(const wchar_t * file_name,std::ios_base::openmode mode=std::ios_base::in)85         explicit basic_ifstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::in)
86         {
87             open(file_name, mode);
88         }
89 #endif
90 
basic_ifstream(const std::string & file_name,std::ios_base::openmode mode=std::ios_base::in)91         explicit basic_ifstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::in)
92         {
93             open(file_name, mode);
94         }
95 
96         template<typename Path>
basic_ifstream(const Path & file_name,typename detail::enable_if_path<Path,std::ios_base::openmode>::type mode=std::ios_base::in)97         explicit basic_ifstream(
98           const Path& file_name,
99           typename detail::enable_if_path<Path, std::ios_base::openmode>::type mode = std::ios_base::in)
100         {
101             open(file_name, mode);
102         }
103         using fstream_impl::open;
104         using fstream_impl::is_open;
105         using fstream_impl::close;
106         using fstream_impl::rdbuf;
107         using fstream_impl::swap;
108         basic_ifstream(const basic_ifstream&) = delete;
109         basic_ifstream& operator=(const basic_ifstream&) = delete;
basic_ifstream(basic_ifstream && other)110         basic_ifstream(basic_ifstream&& other) noexcept : fstream_impl(std::move(other))
111         {}
operator =(basic_ifstream && rhs)112         basic_ifstream& operator=(basic_ifstream&& rhs) noexcept
113         {
114             fstream_impl::operator=(std::move(rhs));
115             return *this;
116         }
117     };
118 
119     ///
120     /// \brief Same as std::basic_ofstream<char> but accepts UTF-8 strings under Windows
121     ///
122 
123     template<typename CharType, typename Traits = std::char_traits<CharType> >
124     class basic_ofstream : public detail::fstream_impl<CharType, Traits, detail::StreamTypeOut>
125     {
126         typedef detail::fstream_impl<CharType, Traits, detail::StreamTypeOut> fstream_impl;
127 
128     public:
basic_ofstream()129         basic_ofstream()
130         {}
basic_ofstream(const char * file_name,std::ios_base::openmode mode=std::ios_base::out)131         explicit basic_ofstream(const char* file_name, std::ios_base::openmode mode = std::ios_base::out)
132         {
133             open(file_name, mode);
134         }
135 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
basic_ofstream(const wchar_t * file_name,std::ios_base::openmode mode=std::ios_base::out)136         explicit basic_ofstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::out)
137         {
138             open(file_name, mode);
139         }
140 #endif
basic_ofstream(const std::string & file_name,std::ios_base::openmode mode=std::ios_base::out)141         explicit basic_ofstream(const std::string& file_name, std::ios_base::openmode mode = std::ios_base::out)
142         {
143             open(file_name, mode);
144         }
145         template<typename Path>
basic_ofstream(const Path & file_name,typename detail::enable_if_path<Path,std::ios_base::openmode>::type mode=std::ios_base::out)146         explicit basic_ofstream(
147           const Path& file_name,
148           typename detail::enable_if_path<Path, std::ios_base::openmode>::type mode = std::ios_base::out)
149         {
150             open(file_name, mode);
151         }
152 
153         using fstream_impl::open;
154         using fstream_impl::is_open;
155         using fstream_impl::close;
156         using fstream_impl::rdbuf;
157         using fstream_impl::swap;
158         basic_ofstream(const basic_ofstream&) = delete;
159         basic_ofstream& operator=(const basic_ofstream&) = delete;
basic_ofstream(basic_ofstream && other)160         basic_ofstream(basic_ofstream&& other) noexcept : fstream_impl(std::move(other))
161         {}
operator =(basic_ofstream && rhs)162         basic_ofstream& operator=(basic_ofstream&& rhs)
163         {
164             fstream_impl::operator=(std::move(rhs));
165             return *this;
166         }
167     };
168 
169 #ifdef BOOST_MSVC
170 #pragma warning(push)
171 #pragma warning(disable : 4250) // <class> : inherits <method> via dominance
172 #endif
173     ///
174     /// \brief Same as std::basic_fstream<char> but accepts UTF-8 strings under Windows
175     ///
176     template<typename CharType, typename Traits = std::char_traits<CharType> >
177     class basic_fstream : public detail::fstream_impl<CharType, Traits, detail::StreamTypeInOut>
178     {
179         typedef detail::fstream_impl<CharType, Traits, detail::StreamTypeInOut> fstream_impl;
180 
181     public:
basic_fstream()182         basic_fstream()
183         {}
basic_fstream(const char * file_name,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)184         explicit basic_fstream(const char* file_name,
185                                std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
186         {
187             open(file_name, mode);
188         }
189 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
basic_fstream(const wchar_t * file_name,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)190         explicit basic_fstream(const wchar_t* file_name,
191                                std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
192         {
193             open(file_name, mode);
194         }
195 #endif
basic_fstream(const std::string & file_name,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)196         explicit basic_fstream(const std::string& file_name,
197                                std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
198         {
199             open(file_name, mode);
200         }
201         template<typename Path>
basic_fstream(const Path & file_name,typename detail::enable_if_path<Path,std::ios_base::openmode>::type mode=std::ios_base::in|std::ios_base::out)202         explicit basic_fstream(const Path& file_name,
203                                typename detail::enable_if_path<Path, std::ios_base::openmode>::type mode =
204                                  std::ios_base::in | std::ios_base::out)
205         {
206             open(file_name, mode);
207         }
208 
209         using fstream_impl::open;
210         using fstream_impl::is_open;
211         using fstream_impl::close;
212         using fstream_impl::rdbuf;
213         using fstream_impl::swap;
214         basic_fstream(const basic_fstream&) = delete;
215         basic_fstream& operator=(const basic_fstream&) = delete;
basic_fstream(basic_fstream && other)216         basic_fstream(basic_fstream&& other) noexcept : fstream_impl(std::move(other))
217         {}
operator =(basic_fstream && rhs)218         basic_fstream& operator=(basic_fstream&& rhs)
219         {
220             fstream_impl::operator=(std::move(rhs));
221             return *this;
222         }
223     };
224     template<typename CharType, typename Traits>
swap(basic_filebuf<CharType,Traits> & lhs,basic_filebuf<CharType,Traits> & rhs)225     void swap(basic_filebuf<CharType, Traits>& lhs, basic_filebuf<CharType, Traits>& rhs)
226     {
227         lhs.swap(rhs);
228     }
229     template<typename CharType, typename Traits>
swap(basic_ifstream<CharType,Traits> & lhs,basic_ifstream<CharType,Traits> & rhs)230     void swap(basic_ifstream<CharType, Traits>& lhs, basic_ifstream<CharType, Traits>& rhs)
231     {
232         lhs.swap(rhs);
233     }
234     template<typename CharType, typename Traits>
swap(basic_ofstream<CharType,Traits> & lhs,basic_ofstream<CharType,Traits> & rhs)235     void swap(basic_ofstream<CharType, Traits>& lhs, basic_ofstream<CharType, Traits>& rhs)
236     {
237         lhs.swap(rhs);
238     }
239     template<typename CharType, typename Traits>
swap(basic_fstream<CharType,Traits> & lhs,basic_fstream<CharType,Traits> & rhs)240     void swap(basic_fstream<CharType, Traits>& lhs, basic_fstream<CharType, Traits>& rhs)
241     {
242         lhs.swap(rhs);
243     }
244 
245     ///
246     /// Same as std::filebuf but accepts UTF-8 strings under Windows
247     ///
248     typedef basic_filebuf<char> filebuf;
249     ///
250     /// Same as std::ifstream but accepts UTF-8 strings under Windows
251     /// and *\::filesystem::path on all systems
252     ///
253     typedef basic_ifstream<char> ifstream;
254     ///
255     /// Same as std::ofstream but accepts UTF-8 strings under Windows
256     /// and *\::filesystem::path on all systems
257     ///
258     typedef basic_ofstream<char> ofstream;
259     ///
260     /// Same as std::fstream but accepts UTF-8 strings under Windows
261     /// and *\::filesystem::path on all systems
262     ///
263     typedef basic_fstream<char> fstream;
264 
265     // Implementation
266     namespace detail {
267         /// Holds an instance of T
268         /// Required to make sure this is constructed first before passing it to sibling classes
269         template<typename T>
270         struct buf_holder
271         {
272             T buf_;
273         };
274         template<typename CharType, typename Traits, typename T_StreamType, int>
275         class fstream_impl : private buf_holder<basic_filebuf<CharType, Traits> >, // must be first due to init order
276                              public T_StreamType::template stream_base<CharType, Traits>::type
277         {
278             typedef basic_filebuf<CharType, Traits> internal_buffer_type;
279             typedef buf_holder<internal_buffer_type> base_buf_holder;
280             typedef typename T_StreamType::template stream_base<CharType, Traits>::type stream_base;
281 
282         public:
283             using stream_base::setstate;
284             using stream_base::clear;
285 
286         protected:
287             using base_buf_holder::buf_;
288 
fstream_impl()289             fstream_impl() : stream_base(&buf_)
290             {}
291             fstream_impl(const fstream_impl&) = delete;
292             fstream_impl& operator=(const fstream_impl&) = delete;
293 
294             // coverity[exn_spec_violation]
fstream_impl(fstream_impl && other)295             fstream_impl(fstream_impl&& other) noexcept : base_buf_holder(std::move(other)),
296                                                           stream_base(std::move(other))
297             {
298                 this->set_rdbuf(rdbuf());
299             }
operator =(fstream_impl && rhs)300             fstream_impl& operator=(fstream_impl&& rhs) noexcept
301             {
302                 base_buf_holder::operator=(std::move(rhs));
303                 stream_base::operator=(std::move(rhs));
304                 return *this;
305             }
swap(fstream_impl & other)306             void swap(fstream_impl& other)
307             {
308                 stream_base::swap(other);
309                 rdbuf()->swap(*other.rdbuf());
310             }
311 
open(const std::string & file_name,std::ios_base::openmode mode=T_StreamType::mode ())312             void open(const std::string& file_name, std::ios_base::openmode mode = T_StreamType::mode())
313             {
314                 open(file_name.c_str(), mode);
315             }
316             template<typename Path>
open(const Path & file_name,std::ios_base::openmode mode=T_StreamType::mode ())317             typename detail::enable_if_path<Path, void>::type open(const Path& file_name,
318                                                                    std::ios_base::openmode mode = T_StreamType::mode())
319             {
320                 open(file_name.c_str(), mode);
321             }
open(const char * file_name,std::ios_base::openmode mode=T_StreamType::mode ())322             void open(const char* file_name, std::ios_base::openmode mode = T_StreamType::mode())
323             {
324                 if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier()))
325                     setstate(std::ios_base::failbit);
326                 else
327                     clear();
328             }
329 #if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
open(const wchar_t * file_name,std::ios_base::openmode mode=T_StreamType::mode ())330             void open(const wchar_t* file_name, std::ios_base::openmode mode = T_StreamType::mode())
331             {
332                 if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier()))
333                     setstate(std::ios_base::failbit);
334                 else
335                     clear();
336             }
337 #endif
is_open()338             bool is_open()
339             {
340                 return rdbuf()->is_open();
341             }
is_open() const342             bool is_open() const
343             {
344                 return rdbuf()->is_open();
345             }
close()346             void close()
347             {
348                 if(!rdbuf()->close())
349                     setstate(std::ios_base::failbit);
350             }
351 
rdbuf() const352             internal_buffer_type* rdbuf() const
353             {
354                 return const_cast<internal_buffer_type*>(&buf_);
355             }
356         };
357 #ifdef BOOST_MSVC
358 #pragma warning(pop)
359 #endif
360         /// Trait to heuristically check for a *\::filesystem::path
361         /// Done by checking for make_preferred and filename member functions with correct signature
362         template<typename T>
363         struct is_path
364         {
365             typedef char one;
366             struct two
367             {
368                 char dummy[2];
369             };
370 
371             template<typename U, U& (U::*)(), U (U::*)() const>
372             struct Check;
373             template<typename U>
374             static one test(Check<U, &U::make_preferred, &U::filename>*);
375             template<typename U>
376             static two test(...);
377 
378             enum
379             {
380                 value = sizeof(test<T>(0)) == sizeof(one)
381             };
382         };
383         template<bool B, typename T>
384         struct enable_if
385         {};
386         template<typename T>
387         struct enable_if<true, T>
388         {
389             typedef T type;
390         };
391         /// SFINAE trait which has a member "type = Result" if the Path is a *\::filesystem::path
392         template<typename Path, typename Result>
393         struct enable_if_path : enable_if<is_path<Path>::value, Result>
394         {};
395     } // namespace detail
396 } // namespace nowide
397 } // namespace boost
398 
399 #endif
400