fstream.hpp 14 KB

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