indirect_streambuf.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
  2. // (C) Copyright 2003-2007 Jonathan Turkanis
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
  5. // See http://www.boost.org/libs/iostreams for documentation.
  6. // This material is heavily indebted to the discussion and code samples in
  7. // A. Langer and K. Kreft, "Standard C++ IOStreams and Locales",
  8. // Addison-Wesley, 2000, pp. 228-43.
  9. // User "GMSB" provided an optimization for small seeks.
  10. #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
  11. #define BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED
  12. #include <algorithm> // min, max.
  13. #include <cassert>
  14. #include <exception>
  15. #include <boost/config.hpp> // Member template friends.
  16. #include <boost/detail/workaround.hpp>
  17. #include <boost/core/typeinfo.hpp>
  18. #include <boost/iostreams/constants.hpp>
  19. #include <boost/iostreams/detail/adapter/concept_adapter.hpp>
  20. #include <boost/iostreams/detail/buffer.hpp>
  21. #include <boost/iostreams/detail/config/wide_streams.hpp>
  22. #include <boost/iostreams/detail/double_object.hpp>
  23. #include <boost/iostreams/detail/execute.hpp>
  24. #include <boost/iostreams/detail/functional.hpp>
  25. #include <boost/iostreams/detail/ios.hpp>
  26. #include <boost/iostreams/detail/optional.hpp>
  27. #include <boost/iostreams/detail/push.hpp>
  28. #include <boost/iostreams/detail/streambuf/linked_streambuf.hpp>
  29. #include <boost/iostreams/operations.hpp>
  30. #include <boost/iostreams/positioning.hpp>
  31. #include <boost/iostreams/traits.hpp>
  32. #include <boost/iostreams/operations.hpp>
  33. #include <boost/mpl/if.hpp>
  34. #include <boost/throw_exception.hpp>
  35. #include <boost/type_traits/is_convertible.hpp>
  36. // Must come last.
  37. #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC, BCC 5.x
  38. namespace boost { namespace iostreams { namespace detail {
  39. //
  40. // Description: The implementation of basic_streambuf used by chains.
  41. //
  42. template<typename T, typename Tr, typename Alloc, typename Mode>
  43. class indirect_streambuf
  44. : public linked_streambuf<BOOST_DEDUCED_TYPENAME char_type_of<T>::type, Tr>
  45. {
  46. public:
  47. typedef typename char_type_of<T>::type char_type;
  48. BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr)
  49. private:
  50. typedef typename category_of<T>::type category;
  51. typedef concept_adapter<T> wrapper;
  52. typedef detail::basic_buffer<char_type, Alloc> buffer_type;
  53. typedef indirect_streambuf<T, Tr, Alloc, Mode> my_type;
  54. typedef detail::linked_streambuf<char_type, traits_type> base_type;
  55. typedef linked_streambuf<char_type, Tr> streambuf_type;
  56. public:
  57. indirect_streambuf();
  58. void open(const T& t BOOST_IOSTREAMS_PUSH_PARAMS());
  59. bool is_open() const;
  60. void close();
  61. bool auto_close() const;
  62. void set_auto_close(bool close);
  63. bool strict_sync();
  64. // Declared in linked_streambuf.
  65. T* component() { return &*obj(); }
  66. protected:
  67. BOOST_IOSTREAMS_USING_PROTECTED_STREAMBUF_MEMBERS(base_type)
  68. //----------virtual functions---------------------------------------------//
  69. #ifndef BOOST_IOSTREAMS_NO_LOCALE
  70. void imbue(const std::locale& loc);
  71. #endif
  72. #ifdef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES
  73. public:
  74. #endif
  75. int_type underflow();
  76. int_type pbackfail(int_type c);
  77. int_type overflow(int_type c);
  78. int sync();
  79. pos_type seekoff( off_type off, BOOST_IOS::seekdir way,
  80. BOOST_IOS::openmode which );
  81. pos_type seekpos(pos_type sp, BOOST_IOS::openmode which);
  82. // Declared in linked_streambuf.
  83. void set_next(streambuf_type* next);
  84. void close_impl(BOOST_IOS::openmode m);
  85. const boost::core::typeinfo& component_type() const { return BOOST_CORE_TYPEID(T); }
  86. void* component_impl() { return component(); }
  87. private:
  88. //----------Accessor functions--------------------------------------------//
  89. wrapper& obj() { return *storage_; }
  90. streambuf_type* next() const { return next_; }
  91. buffer_type& in() { return buffer_.first(); }
  92. buffer_type& out() { return buffer_.second(); }
  93. bool can_read() const { return is_convertible<Mode, input>::value; }
  94. bool can_write() const { return is_convertible<Mode, output>::value; }
  95. bool output_buffered() const { return (flags_ & f_output_buffered) != 0; }
  96. bool shared_buffer() const { return is_convertible<Mode, seekable>::value || is_convertible<Mode, dual_seekable>::value; }
  97. void set_flags(int f) { flags_ = f; }
  98. //----------State changing functions--------------------------------------//
  99. virtual void init_get_area();
  100. virtual void init_put_area();
  101. //----------Utility function----------------------------------------------//
  102. pos_type seek_impl( stream_offset off, BOOST_IOS::seekdir way,
  103. BOOST_IOS::openmode which );
  104. void sync_impl();
  105. enum flag_type {
  106. f_open = 1,
  107. f_output_buffered = f_open << 1,
  108. f_auto_close = f_output_buffered << 1
  109. };
  110. optional<wrapper> storage_;
  111. streambuf_type* next_;
  112. double_object<
  113. buffer_type,
  114. is_convertible<
  115. Mode,
  116. two_sequence
  117. >
  118. > buffer_;
  119. std::streamsize pback_size_;
  120. int flags_;
  121. };
  122. //--------------Implementation of indirect_streambuf--------------------------//
  123. template<typename T, typename Tr, typename Alloc, typename Mode>
  124. indirect_streambuf<T, Tr, Alloc, Mode>::indirect_streambuf()
  125. : next_(0), pback_size_(0), flags_(f_auto_close) { }
  126. //--------------Implementation of open, is_open and close---------------------//
  127. template<typename T, typename Tr, typename Alloc, typename Mode>
  128. void indirect_streambuf<T, Tr, Alloc, Mode>::open
  129. (const T& t, std::streamsize buffer_size, std::streamsize pback_size)
  130. {
  131. using namespace std;
  132. // Normalize buffer sizes.
  133. buffer_size =
  134. (buffer_size != -1) ?
  135. buffer_size :
  136. iostreams::optimal_buffer_size(t);
  137. pback_size =
  138. (pback_size != -1) ?
  139. pback_size :
  140. default_pback_buffer_size;
  141. // Construct input buffer.
  142. if (can_read()) {
  143. pback_size_ = (std::max)(std::streamsize(2), pback_size); // STLPort needs 2.
  144. std::streamsize size =
  145. pback_size_ +
  146. ( buffer_size ? buffer_size: std::streamsize(1) );
  147. in().resize(static_cast<int>(size));
  148. if (!shared_buffer())
  149. init_get_area();
  150. }
  151. // Construct output buffer.
  152. if (can_write() && !shared_buffer()) {
  153. if (buffer_size != std::streamsize(0))
  154. out().resize(static_cast<int>(buffer_size));
  155. init_put_area();
  156. }
  157. storage_.reset(wrapper(t));
  158. flags_ |= f_open;
  159. if (can_write() && buffer_size > 1)
  160. flags_ |= f_output_buffered;
  161. this->set_true_eof(false);
  162. this->set_needs_close();
  163. }
  164. template<typename T, typename Tr, typename Alloc, typename Mode>
  165. inline bool indirect_streambuf<T, Tr, Alloc, Mode>::is_open() const
  166. { return (flags_ & f_open) != 0; }
  167. template<typename T, typename Tr, typename Alloc, typename Mode>
  168. void indirect_streambuf<T, Tr, Alloc, Mode>::close()
  169. {
  170. using namespace std;
  171. base_type* self = this;
  172. detail::execute_all(
  173. detail::call_member_close(*self, BOOST_IOS::in),
  174. detail::call_member_close(*self, BOOST_IOS::out),
  175. detail::call_reset(storage_),
  176. detail::clear_flags(flags_)
  177. );
  178. }
  179. template<typename T, typename Tr, typename Alloc, typename Mode>
  180. bool indirect_streambuf<T, Tr, Alloc, Mode>::auto_close() const
  181. { return (flags_ & f_auto_close) != 0; }
  182. template<typename T, typename Tr, typename Alloc, typename Mode>
  183. void indirect_streambuf<T, Tr, Alloc, Mode>::set_auto_close(bool close)
  184. { flags_ = (flags_ & ~f_auto_close) | (close ? f_auto_close : 0); }
  185. //--------------Implementation virtual functions------------------------------//
  186. #ifndef BOOST_IOSTREAMS_NO_LOCALE
  187. template<typename T, typename Tr, typename Alloc, typename Mode>
  188. void indirect_streambuf<T, Tr, Alloc, Mode>::imbue(const std::locale& loc)
  189. {
  190. if (is_open()) {
  191. obj().imbue(loc);
  192. if (next_)
  193. next_->pubimbue(loc);
  194. }
  195. }
  196. #endif
  197. template<typename T, typename Tr, typename Alloc, typename Mode>
  198. typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
  199. indirect_streambuf<T, Tr, Alloc, Mode>::underflow()
  200. {
  201. using namespace std;
  202. if (!gptr()) init_get_area();
  203. buffer_type& buf = in();
  204. if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
  205. // Fill putback buffer.
  206. std::streamsize keep =
  207. (std::min)( static_cast<std::streamsize>(gptr() - eback()),
  208. pback_size_ );
  209. if (keep)
  210. traits_type::move( buf.data() + (pback_size_ - keep),
  211. gptr() - keep, keep );
  212. // Set pointers to reasonable values in case read throws.
  213. setg( buf.data() + pback_size_ - keep,
  214. buf.data() + pback_size_,
  215. buf.data() + pback_size_ );
  216. // Read from source.
  217. std::streamsize chars =
  218. obj().read(buf.data() + pback_size_, buf.size() - pback_size_, next_);
  219. if (chars == -1) {
  220. this->set_true_eof(true);
  221. chars = 0;
  222. }
  223. setg(eback(), gptr(), buf.data() + pback_size_ + chars);
  224. return chars != 0 ?
  225. traits_type::to_int_type(*gptr()) :
  226. traits_type::eof();
  227. }
  228. template<typename T, typename Tr, typename Alloc, typename Mode>
  229. typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
  230. indirect_streambuf<T, Tr, Alloc, Mode>::pbackfail(int_type c)
  231. {
  232. if (gptr() != eback()) {
  233. gbump(-1);
  234. if (!traits_type::eq_int_type(c, traits_type::eof()))
  235. *gptr() = traits_type::to_char_type(c);
  236. return traits_type::not_eof(c);
  237. } else {
  238. boost::throw_exception(bad_putback());
  239. }
  240. }
  241. template<typename T, typename Tr, typename Alloc, typename Mode>
  242. typename indirect_streambuf<T, Tr, Alloc, Mode>::int_type
  243. indirect_streambuf<T, Tr, Alloc, Mode>::overflow(int_type c)
  244. {
  245. if ( (output_buffered() && pptr() == 0) ||
  246. (shared_buffer() && gptr() != 0) )
  247. {
  248. init_put_area();
  249. }
  250. if (!traits_type::eq_int_type(c, traits_type::eof())) {
  251. if (output_buffered()) {
  252. if (pptr() == epptr()) {
  253. sync_impl();
  254. if (pptr() == epptr())
  255. return traits_type::eof();
  256. }
  257. *pptr() = traits_type::to_char_type(c);
  258. pbump(1);
  259. } else {
  260. char_type d = traits_type::to_char_type(c);
  261. if (obj().write(&d, 1, next_) != 1)
  262. return traits_type::eof();
  263. }
  264. }
  265. return traits_type::not_eof(c);
  266. }
  267. template<typename T, typename Tr, typename Alloc, typename Mode>
  268. int indirect_streambuf<T, Tr, Alloc, Mode>::sync()
  269. {
  270. try { // sync() is no-throw.
  271. sync_impl();
  272. obj().flush(next_);
  273. return 0;
  274. } catch (...) { return -1; }
  275. }
  276. template<typename T, typename Tr, typename Alloc, typename Mode>
  277. bool indirect_streambuf<T, Tr, Alloc, Mode>::strict_sync()
  278. {
  279. try { // sync() is no-throw.
  280. sync_impl();
  281. return obj().flush(next_);
  282. } catch (...) { return false; }
  283. }
  284. template<typename T, typename Tr, typename Alloc, typename Mode>
  285. inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
  286. indirect_streambuf<T, Tr, Alloc, Mode>::seekoff
  287. (off_type off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
  288. { return seek_impl(off, way, which); }
  289. template<typename T, typename Tr, typename Alloc, typename Mode>
  290. inline typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
  291. indirect_streambuf<T, Tr, Alloc, Mode>::seekpos
  292. (pos_type sp, BOOST_IOS::openmode which)
  293. {
  294. return seek_impl(position_to_offset(sp), BOOST_IOS::beg, which);
  295. }
  296. template<typename T, typename Tr, typename Alloc, typename Mode>
  297. typename indirect_streambuf<T, Tr, Alloc, Mode>::pos_type
  298. indirect_streambuf<T, Tr, Alloc, Mode>::seek_impl
  299. (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
  300. {
  301. if ( gptr() != 0 && way == BOOST_IOS::cur && which == BOOST_IOS::in &&
  302. eback() - gptr() <= off && off <= egptr() - gptr() )
  303. { // Small seek optimization
  304. gbump(static_cast<int>(off));
  305. return obj().seek(stream_offset(0), BOOST_IOS::cur, BOOST_IOS::in, next_) -
  306. static_cast<off_type>(egptr() - gptr());
  307. }
  308. if (pptr() != 0)
  309. this->BOOST_IOSTREAMS_PUBSYNC(); // sync() confuses VisualAge 6.
  310. if (way == BOOST_IOS::cur && gptr())
  311. off -= static_cast<off_type>(egptr() - gptr());
  312. bool two_head = is_convertible<category, dual_seekable>::value ||
  313. is_convertible<category, bidirectional_seekable>::value;
  314. if (two_head) {
  315. BOOST_IOS::openmode both = BOOST_IOS::in | BOOST_IOS::out;
  316. if ((which & both) == both)
  317. boost::throw_exception(bad_seek());
  318. if (which & BOOST_IOS::in) {
  319. setg(0, 0, 0);
  320. }
  321. if (which & BOOST_IOS::out) {
  322. setp(0, 0);
  323. }
  324. }
  325. else {
  326. setg(0, 0, 0);
  327. setp(0, 0);
  328. }
  329. return obj().seek(off, way, which, next_);
  330. }
  331. template<typename T, typename Tr, typename Alloc, typename Mode>
  332. inline void indirect_streambuf<T, Tr, Alloc, Mode>::set_next
  333. (streambuf_type* next)
  334. { next_ = next; }
  335. template<typename T, typename Tr, typename Alloc, typename Mode>
  336. inline void indirect_streambuf<T, Tr, Alloc, Mode>::close_impl
  337. (BOOST_IOS::openmode which)
  338. {
  339. if (which == BOOST_IOS::in && is_convertible<Mode, input>::value) {
  340. setg(0, 0, 0);
  341. }
  342. if (which == BOOST_IOS::out && is_convertible<Mode, output>::value) {
  343. sync();
  344. setp(0, 0);
  345. }
  346. if ( !is_convertible<category, dual_use>::value ||
  347. is_convertible<Mode, input>::value == (which == BOOST_IOS::in) )
  348. {
  349. obj().close(which, next_);
  350. }
  351. }
  352. //----------State changing functions------------------------------------------//
  353. template<typename T, typename Tr, typename Alloc, typename Mode>
  354. void indirect_streambuf<T, Tr, Alloc, Mode>::sync_impl()
  355. {
  356. std::streamsize avail, amt;
  357. if ((avail = static_cast<std::streamsize>(pptr() - pbase())) > 0) {
  358. if ((amt = obj().write(pbase(), avail, next())) == avail)
  359. setp(out().begin(), out().end());
  360. else {
  361. const char_type* ptr = pptr();
  362. setp(out().begin() + amt, out().end());
  363. pbump(static_cast<int>(ptr - pptr()));
  364. }
  365. }
  366. }
  367. template<typename T, typename Tr, typename Alloc, typename Mode>
  368. void indirect_streambuf<T, Tr, Alloc, Mode>::init_get_area()
  369. {
  370. if (shared_buffer() && pptr() != 0) {
  371. sync_impl();
  372. setp(0, 0);
  373. }
  374. setg(in().begin(), in().begin(), in().begin());
  375. }
  376. template<typename T, typename Tr, typename Alloc, typename Mode>
  377. void indirect_streambuf<T, Tr, Alloc, Mode>::init_put_area()
  378. {
  379. using namespace std;
  380. if (shared_buffer() && gptr() != 0) {
  381. obj().seek(static_cast<off_type>(gptr() - egptr()), BOOST_IOS::cur, BOOST_IOS::in, next_);
  382. setg(0, 0, 0);
  383. }
  384. if (output_buffered())
  385. setp(out().begin(), out().end());
  386. else
  387. setp(0, 0);
  388. }
  389. //----------------------------------------------------------------------------//
  390. } } } // End namespaces detail, iostreams, boost.
  391. #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC, BCC 5.x
  392. #endif // #ifndef BOOST_IOSTREAMS_DETAIL_INDIRECT_STREAMBUF_HPP_INCLUDED