fstream.hpp 13 KB

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