compose.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
  2. // (C) Copyright 2005-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. // Note: bidirectional streams are not supported.
  7. #ifndef BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED
  8. #define BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED
  9. #if defined(_MSC_VER)
  10. # pragma once
  11. #endif
  12. #include <algorithm> // min.
  13. #include <utility> // pair.
  14. #include <boost/config.hpp> // DEDUCED_TYPENAME.
  15. #include <boost/iostreams/categories.hpp>
  16. #include <boost/iostreams/detail/adapter/direct_adapter.hpp>
  17. #include <boost/iostreams/detail/call_traits.hpp>
  18. #include <boost/iostreams/detail/enable_if_stream.hpp>
  19. #include <boost/iostreams/detail/execute.hpp>
  20. #include <boost/iostreams/detail/functional.hpp>
  21. #include <boost/iostreams/operations.hpp>
  22. #include <boost/iostreams/traits.hpp> // mode_of, is_direct.
  23. #include <boost/mpl/if.hpp>
  24. #include <boost/ref.hpp>
  25. #include <boost/static_assert.hpp>
  26. #include <boost/type_traits/is_convertible.hpp>
  27. // Must come last.
  28. #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC.
  29. namespace boost { namespace iostreams {
  30. namespace detail {
  31. template< typename First,
  32. typename Second,
  33. typename FirstMode =
  34. BOOST_DEDUCED_TYPENAME mode_of<First>::type,
  35. typename SecondMode =
  36. BOOST_DEDUCED_TYPENAME mode_of<Second>::type >
  37. struct composite_mode
  38. : select<
  39. is_convertible<SecondMode, FirstMode>, FirstMode,
  40. is_convertible<FirstMode, SecondMode>, SecondMode,
  41. is_convertible<SecondMode, input>, input,
  42. else_, output
  43. >
  44. { };
  45. //
  46. // Template name: composite_device.
  47. // Description: Provides a Device view of a Filter, Device pair.
  48. // Template parameters:
  49. // Filter - A model of Filter.
  50. // Device - An indirect model of Device.
  51. //
  52. template< typename Filter,
  53. typename Device,
  54. typename Mode =
  55. BOOST_DEDUCED_TYPENAME composite_mode<Filter, Device>::type >
  56. class composite_device {
  57. private:
  58. typedef typename detail::param_type<Device>::type param_type;
  59. typedef typename mode_of<Filter>::type filter_mode;
  60. typedef typename mode_of<Device>::type device_mode;
  61. typedef typename
  62. iostreams::select< // Disambiguation for Tru64.
  63. is_direct<Device>, direct_adapter<Device>,
  64. is_std_io<Device>, Device&,
  65. else_, Device
  66. >::type value_type;
  67. BOOST_STATIC_ASSERT(is_filter<Filter>::value);
  68. BOOST_STATIC_ASSERT(is_device<Device>::value);
  69. public:
  70. typedef typename char_type_of<Filter>::type char_type;
  71. struct category
  72. : Mode,
  73. device_tag,
  74. closable_tag,
  75. flushable_tag,
  76. localizable_tag,
  77. optimally_buffered_tag
  78. { };
  79. composite_device(const Filter& flt, param_type dev);
  80. std::streamsize read(char_type* s, std::streamsize n);
  81. std::streamsize write(const char_type* s, std::streamsize n);
  82. std::streampos seek( stream_offset off, BOOST_IOS::seekdir way,
  83. BOOST_IOS::openmode which =
  84. BOOST_IOS::in | BOOST_IOS::out );
  85. void close();
  86. void close(BOOST_IOS::openmode which);
  87. bool flush();
  88. std::streamsize optimal_buffer_size() const;
  89. template<typename Locale> // Avoid dependency on <locale>
  90. void imbue(const Locale& loc)
  91. {
  92. iostreams::imbue(filter_, loc);
  93. iostreams::imbue(device_, loc);
  94. }
  95. Filter& first() { return filter_; }
  96. Device& second() { return device_; }
  97. private:
  98. Filter filter_;
  99. value_type device_;
  100. };
  101. //
  102. // Template name: composite_device.
  103. // Description: Provides a Device view of a Filter, Device pair.
  104. // Template parameters:
  105. // Filter - A model of Filter.
  106. // Device - An indirect model of Device.
  107. //
  108. template< typename Filter1,
  109. typename Filter2,
  110. typename Mode =
  111. BOOST_DEDUCED_TYPENAME composite_mode<Filter1, Filter2>::type >
  112. class composite_filter {
  113. private:
  114. typedef reference_wrapper<Filter2> filter_ref;
  115. typedef typename mode_of<Filter1>::type first_mode;
  116. typedef typename mode_of<Filter2>::type second_mode;
  117. // A dual-use filter cannot be composed with a read-write filter
  118. BOOST_STATIC_ASSERT(
  119. !(is_convertible<first_mode, dual_use>::value) ||
  120. !(is_convertible<second_mode, input>::value) ||
  121. !(is_convertible<second_mode, output>::value) ||
  122. (is_convertible<second_mode, dual_use>::value)
  123. );
  124. BOOST_STATIC_ASSERT(
  125. !(is_convertible<second_mode, dual_use>::value) ||
  126. !(is_convertible<first_mode, input>::value) ||
  127. !(is_convertible<first_mode, output>::value) ||
  128. (is_convertible<first_mode, dual_use>::value)
  129. );
  130. BOOST_STATIC_ASSERT(is_filter<Filter1>::value);
  131. BOOST_STATIC_ASSERT(is_filter<Filter2>::value);
  132. public:
  133. typedef typename char_type_of<Filter1>::type char_type;
  134. struct category
  135. : Mode,
  136. filter_tag,
  137. multichar_tag,
  138. closable_tag,
  139. flushable_tag,
  140. localizable_tag,
  141. optimally_buffered_tag
  142. { };
  143. composite_filter(const Filter1& filter1, const Filter2& filter2)
  144. : filter1_(filter1), filter2_(filter2)
  145. { }
  146. template<typename Source>
  147. std::streamsize read(Source& src, char_type* s, std::streamsize n)
  148. {
  149. composite_device<filter_ref, Source> cmp(boost::ref(filter2_), src);
  150. return iostreams::read(filter1_, cmp, s, n);
  151. }
  152. template<typename Sink>
  153. std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
  154. {
  155. composite_device<filter_ref, Sink> cmp(boost::ref(filter2_), snk);
  156. return iostreams::write(filter1_, cmp, s, n);
  157. }
  158. template<typename Device>
  159. std::streampos seek( Device& dev, stream_offset off, BOOST_IOS::seekdir way,
  160. BOOST_IOS::openmode which =
  161. BOOST_IOS::in | BOOST_IOS::out )
  162. {
  163. composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev);
  164. return iostreams::seek(filter1_, cmp, off, way, which);
  165. }
  166. template<typename Device>
  167. void close(Device& dev)
  168. {
  169. BOOST_STATIC_ASSERT((!is_convertible<category, two_sequence>::value));
  170. BOOST_STATIC_ASSERT((!is_convertible<category, dual_use>::value));
  171. // Create a new device by composing the second filter2_ with dev.
  172. composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev);
  173. // Close input sequences in reverse order and output sequences in
  174. // forward order
  175. if (!is_convertible<first_mode, dual_use>::value) {
  176. detail::execute_all(
  177. detail::call_close(filter2_, dev, BOOST_IOS::in),
  178. detail::call_close(filter1_, cmp, BOOST_IOS::in),
  179. detail::call_close(filter1_, cmp, BOOST_IOS::out),
  180. detail::call_close(filter2_, dev, BOOST_IOS::out)
  181. );
  182. } else if (is_convertible<second_mode, input>::value) {
  183. detail::execute_all(
  184. detail::call_close(filter2_, dev, BOOST_IOS::in),
  185. detail::call_close(filter1_, cmp, BOOST_IOS::in)
  186. );
  187. } else {
  188. detail::execute_all(
  189. detail::call_close(filter1_, cmp, BOOST_IOS::out),
  190. detail::call_close(filter2_, dev, BOOST_IOS::out)
  191. );
  192. }
  193. }
  194. template<typename Device>
  195. void close(Device& dev, BOOST_IOS::openmode which)
  196. {
  197. BOOST_STATIC_ASSERT(
  198. (is_convertible<category, two_sequence>::value) ||
  199. (is_convertible<category, dual_use>::value)
  200. );
  201. // Create a new device by composing the second filter2_ with dev.
  202. composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev);
  203. // Close input sequences in reverse order
  204. if ( which == BOOST_IOS::in &&
  205. ( !is_convertible<first_mode, dual_use>::value ||
  206. is_convertible<second_mode, input>::value ) )
  207. {
  208. detail::execute_all(
  209. detail::call_close(filter2_, dev, BOOST_IOS::in),
  210. detail::call_close(filter1_, cmp, BOOST_IOS::in)
  211. );
  212. }
  213. // Close output sequences in forward order
  214. if ( which == BOOST_IOS::out &&
  215. ( !is_convertible<first_mode, dual_use>::value ||
  216. is_convertible<second_mode, output>::value ) )
  217. {
  218. detail::execute_all(
  219. detail::call_close(filter1_, cmp, BOOST_IOS::out),
  220. detail::call_close(filter2_, dev, BOOST_IOS::out)
  221. );
  222. }
  223. }
  224. template<typename Device>
  225. bool flush(Device& dev)
  226. {
  227. composite_device<Filter2, Device> cmp(filter2_, dev);
  228. return iostreams::flush(filter1_, cmp);
  229. }
  230. std::streamsize optimal_buffer_size() const
  231. {
  232. std::streamsize first = iostreams::optimal_buffer_size(filter1_);
  233. std::streamsize second = iostreams::optimal_buffer_size(filter2_);
  234. return first < second ? second : first;
  235. }
  236. template<typename Locale> // Avoid dependency on <locale>
  237. void imbue(const Locale& loc)
  238. { // To do: consider using RAII.
  239. iostreams::imbue(filter1_, loc);
  240. iostreams::imbue(filter2_, loc);
  241. }
  242. Filter1& first() { return filter1_; }
  243. Filter2& second() { return filter2_; }
  244. private:
  245. Filter1 filter1_;
  246. Filter2 filter2_;
  247. };
  248. template<typename Filter, typename FilterOrDevice>
  249. struct composite_traits
  250. : mpl::if_<
  251. is_device<FilterOrDevice>,
  252. composite_device<Filter, FilterOrDevice>,
  253. composite_filter<Filter, FilterOrDevice>
  254. >
  255. { };
  256. } // End namespace detail.
  257. template<typename Filter, typename FilterOrDevice>
  258. struct composite : detail::composite_traits<Filter, FilterOrDevice>::type {
  259. typedef typename detail::param_type<FilterOrDevice>::type param_type;
  260. typedef typename detail::composite_traits<Filter, FilterOrDevice>::type base;
  261. composite(const Filter& flt, param_type dev)
  262. : base(flt, dev)
  263. { }
  264. };
  265. //--------------Implementation of compose-------------------------------------//
  266. // Note: The following workarounds are patterned after resolve.hpp. It has not
  267. // yet been confirmed that they are necessary.
  268. #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //-------------------------//
  269. # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //-------------------------------//
  270. template<typename Filter, typename FilterOrDevice>
  271. composite<Filter, FilterOrDevice>
  272. compose( const Filter& filter, const FilterOrDevice& fod
  273. BOOST_IOSTREAMS_DISABLE_IF_STREAM(FilterOrDevice) )
  274. { return composite<Filter, FilterOrDevice>(filter, fod); }
  275. template<typename Filter, typename Ch, typename Tr>
  276. composite< Filter, std::basic_streambuf<Ch, Tr> >
  277. compose(const Filter& filter, std::basic_streambuf<Ch, Tr>& sb)
  278. { return composite< Filter, std::basic_streambuf<Ch, Tr> >(filter, sb); }
  279. template<typename Filter, typename Ch, typename Tr>
  280. composite< Filter, std::basic_istream<Ch, Tr> >
  281. compose(const Filter& filter, std::basic_istream<Ch, Tr>& is)
  282. { return composite< Filter, std::basic_istream<Ch, Tr> >(filter, is); }
  283. template<typename Filter, typename Ch, typename Tr>
  284. composite< Filter, std::basic_ostream<Ch, Tr> >
  285. compose(const Filter& filter, std::basic_ostream<Ch, Tr>& os)
  286. { return composite< Filter, std::basic_ostream<Ch, Tr> >(filter, os); }
  287. template<typename Filter, typename Ch, typename Tr>
  288. composite< Filter, std::basic_iostream<Ch, Tr> >
  289. compose(const Filter& filter, std::basic_iostream<Ch, Tr>& io)
  290. { return composite< Filter, std::basic_iostream<Ch, Tr> >(filter, io); }
  291. # else // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //---------------------//
  292. template<typename Filter, typename FilterOrDevice>
  293. composite<Filter, FilterOrDevice>
  294. compose( const Filter& filter, const FilterOrDevice& fod
  295. BOOST_IOSTREAMS_DISABLE_IF_STREAM(FilterOrDevice) )
  296. { return composite<Filter, FilterOrDevice>(filter, fod); }
  297. template<typename Filter>
  298. composite<Filter, std::streambuf>
  299. compose(const Filter& filter, std::streambuf& sb)
  300. { return composite<Filter, std::streambuf>(filter, sb); }
  301. template<typename Filter>
  302. composite<Filter, std::istream>
  303. compose(const Filter& filter, std::istream& is)
  304. { return composite<Filter, std::istream>(filter, is); }
  305. template<typename Filter>
  306. composite<Filter, std::ostream>
  307. compose(const Filter& filter, std::ostream& os)
  308. { return composite<Filter, std::ostream>(filter, os); }
  309. template<typename Filter>
  310. composite<Filter, std::iostream>
  311. compose(const Filter& filter, std::iostream& io)
  312. { return composite<Filter, std::iostream>(filter, io); }
  313. # endif // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //--------------------//
  314. #else // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //----------------//
  315. template<typename Filter, typename Stream>
  316. composite<Filter, Stream>
  317. compose(const Filter& flt, const Stream& strm, mpl::true_)
  318. { // Bad overload resolution.
  319. return composite<Filter, Stream>(flt, const_cast<Stream&>(strm));
  320. }
  321. template<typename Filter, typename FilterOrDevice>
  322. composite<Filter, FilterOrDevice>
  323. compose(const Filter& flt, const FilterOrDevice& fod, mpl::false_)
  324. { return composite<Filter, FilterOrDevice>(flt, fod); }
  325. template<typename Filter, typename FilterOrDevice>
  326. composite<Filter, FilterOrDevice>
  327. compose( const Filter& flt, const FilterOrDevice& fod
  328. BOOST_IOSTREAMS_DISABLE_IF_STREAM(T) )
  329. { return compose(flt, fod, is_std_io<FilterOrDevice>()); }
  330. # if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \
  331. !defined(__GNUC__) // ---------------------------------------------------//
  332. template<typename Filter, typename FilterOrDevice>
  333. composite<Filter, FilterOrDevice>
  334. compose (const Filter& filter, FilterOrDevice& fod)
  335. { return composite<Filter, FilterOrDevice>(filter, fod); }
  336. # endif // Borland 5.x or GCC //--------------------------------//
  337. #endif // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //---------------//
  338. //----------------------------------------------------------------------------//
  339. namespace detail {
  340. //--------------Implementation of composite_device---------------------------//
  341. template<typename Filter, typename Device, typename Mode>
  342. composite_device<Filter, Device, Mode>::composite_device
  343. (const Filter& flt, param_type dev)
  344. : filter_(flt), device_(dev)
  345. { }
  346. template<typename Filter, typename Device, typename Mode>
  347. inline std::streamsize composite_device<Filter, Device, Mode>::read
  348. (char_type* s, std::streamsize n)
  349. { return iostreams::read(filter_, device_, s, n); }
  350. template<typename Filter, typename Device, typename Mode>
  351. inline std::streamsize composite_device<Filter, Device, Mode>::write
  352. (const char_type* s, std::streamsize n)
  353. { return iostreams::write(filter_, device_, s, n); }
  354. template<typename Filter, typename Device, typename Mode>
  355. std::streampos composite_device<Filter, Device, Mode>::seek
  356. (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which)
  357. { return iostreams::seek(filter_, device_, off, way, which); }
  358. template<typename Filter, typename Device, typename Mode>
  359. void composite_device<Filter, Device, Mode>::close()
  360. {
  361. BOOST_STATIC_ASSERT((!is_convertible<Mode, two_sequence>::value));
  362. BOOST_STATIC_ASSERT(
  363. !(is_convertible<filter_mode, dual_use>::value) ||
  364. !(is_convertible<device_mode, input>::value) ||
  365. !(is_convertible<device_mode, output>::value)
  366. );
  367. // Close input sequences in reverse order and output sequences
  368. // in forward order
  369. if (!is_convertible<filter_mode, dual_use>::value) {
  370. detail::execute_all(
  371. detail::call_close(device_, BOOST_IOS::in),
  372. detail::call_close(filter_, device_, BOOST_IOS::in),
  373. detail::call_close(filter_, device_, BOOST_IOS::out),
  374. detail::call_close(device_, BOOST_IOS::out)
  375. );
  376. } else if (is_convertible<device_mode, input>::value) {
  377. detail::execute_all(
  378. detail::call_close(device_, BOOST_IOS::in),
  379. detail::call_close(filter_, device_, BOOST_IOS::in)
  380. );
  381. } else {
  382. detail::execute_all(
  383. detail::call_close(filter_, device_, BOOST_IOS::out),
  384. detail::call_close(device_, BOOST_IOS::out)
  385. );
  386. }
  387. }
  388. template<typename Filter, typename Device, typename Mode>
  389. void composite_device<Filter, Device, Mode>::close(BOOST_IOS::openmode which)
  390. {
  391. BOOST_STATIC_ASSERT((is_convertible<Mode, two_sequence>::value));
  392. BOOST_STATIC_ASSERT(!(is_convertible<filter_mode, dual_use>::value));
  393. // Close input sequences in reverse order
  394. if (which == BOOST_IOS::in) {
  395. detail::execute_all(
  396. detail::call_close(device_, BOOST_IOS::in),
  397. detail::call_close(filter_, device_, BOOST_IOS::in)
  398. );
  399. }
  400. // Close output sequences in forward order
  401. if (which == BOOST_IOS::out) {
  402. detail::execute_all(
  403. detail::call_close(filter_, device_, BOOST_IOS::out),
  404. detail::call_close(device_, BOOST_IOS::out)
  405. );
  406. }
  407. }
  408. template<typename Filter, typename Device, typename Mode>
  409. bool composite_device<Filter, Device, Mode>::flush()
  410. {
  411. bool r1 = iostreams::flush(filter_, device_);
  412. bool r2 = iostreams::flush(device_);
  413. return r1 && r2;
  414. }
  415. template<typename Filter, typename Device, typename Mode>
  416. std::streamsize
  417. composite_device<Filter, Device, Mode>::optimal_buffer_size() const
  418. { return iostreams::optimal_buffer_size(device_); }
  419. } // End namespace detail.
  420. } } // End namespaces iostreams, boost.
  421. #include <boost/iostreams/detail/config/enable_warnings.hpp>
  422. #endif // #ifndef BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED