tee.hpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. #ifndef BOOST_IOSTREAMS_TEE_HPP_INCLUDED
  7. #define BOOST_IOSTREAMS_TEE_HPP_INCLUDED
  8. #if defined(_MSC_VER)
  9. # pragma once
  10. #endif
  11. #include <boost/assert.hpp>
  12. #include <boost/config.hpp> // BOOST_DEDUCE_TYPENAME.
  13. #include <boost/iostreams/categories.hpp>
  14. #include <boost/iostreams/detail/adapter/device_adapter.hpp>
  15. #include <boost/iostreams/detail/adapter/filter_adapter.hpp>
  16. #include <boost/iostreams/detail/call_traits.hpp>
  17. #include <boost/iostreams/detail/execute.hpp>
  18. #include <boost/iostreams/detail/functional.hpp> // call_close_all
  19. #include <boost/iostreams/operations.hpp>
  20. #include <boost/iostreams/pipeline.hpp>
  21. #include <boost/iostreams/traits.hpp>
  22. #include <boost/static_assert.hpp>
  23. #include <boost/type_traits/is_convertible.hpp>
  24. #include <boost/type_traits/is_same.hpp>
  25. namespace boost { namespace iostreams {
  26. //
  27. // Template name: tee_filter.
  28. // Template parameters:
  29. // Device - A blocking Sink.
  30. //
  31. template<typename Device>
  32. class tee_filter : public detail::filter_adapter<Device> {
  33. public:
  34. typedef typename detail::param_type<Device>::type param_type;
  35. typedef typename char_type_of<Device>::type char_type;
  36. struct category
  37. : dual_use_filter_tag,
  38. multichar_tag,
  39. closable_tag,
  40. flushable_tag,
  41. localizable_tag,
  42. optimally_buffered_tag
  43. { };
  44. BOOST_STATIC_ASSERT(is_device<Device>::value);
  45. BOOST_STATIC_ASSERT((
  46. is_convertible< // Using mode_of causes failures on VC6-7.0.
  47. BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, output
  48. >::value
  49. ));
  50. explicit tee_filter(param_type dev)
  51. : detail::filter_adapter<Device>(dev)
  52. { }
  53. template<typename Source>
  54. std::streamsize read(Source& src, char_type* s, std::streamsize n)
  55. {
  56. std::streamsize result = iostreams::read(src, s, n);
  57. if (result != -1) {
  58. std::streamsize result2 = iostreams::write(this->component(), s, result);
  59. (void) result2; // Suppress 'unused variable' warning.
  60. BOOST_ASSERT(result == result2);
  61. }
  62. return result;
  63. }
  64. template<typename Sink>
  65. std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
  66. {
  67. std::streamsize result = iostreams::write(snk, s, n);
  68. std::streamsize result2 = iostreams::write(this->component(), s, result);
  69. (void) result2; // Suppress 'unused variable' warning.
  70. BOOST_ASSERT(result == result2);
  71. return result;
  72. }
  73. template<typename Next>
  74. void close(Next&, BOOST_IOS::openmode)
  75. {
  76. detail::close_all(this->component());
  77. }
  78. template<typename Sink>
  79. bool flush(Sink& snk)
  80. {
  81. bool r1 = iostreams::flush(snk);
  82. bool r2 = iostreams::flush(this->component());
  83. return r1 && r2;
  84. }
  85. };
  86. BOOST_IOSTREAMS_PIPABLE(tee_filter, 1)
  87. //
  88. // Template name: tee_device.
  89. // Template parameters:
  90. // Device - A blocking Device.
  91. // Sink - A blocking Sink.
  92. //
  93. template<typename Device, typename Sink>
  94. class tee_device {
  95. public:
  96. typedef typename detail::param_type<Device>::type device_param;
  97. typedef typename detail::param_type<Sink>::type sink_param;
  98. typedef typename detail::value_type<Device>::type device_value;
  99. typedef typename detail::value_type<Sink>::type sink_value;
  100. typedef typename char_type_of<Device>::type char_type;
  101. typedef typename
  102. mpl::if_<
  103. is_convertible<
  104. BOOST_DEDUCED_TYPENAME
  105. iostreams::category_of<Device>::type,
  106. output
  107. >,
  108. output,
  109. input
  110. >::type mode;
  111. BOOST_STATIC_ASSERT(is_device<Device>::value);
  112. BOOST_STATIC_ASSERT(is_device<Sink>::value);
  113. BOOST_STATIC_ASSERT((
  114. is_same<
  115. char_type,
  116. BOOST_DEDUCED_TYPENAME char_type_of<Sink>::type
  117. >::value
  118. ));
  119. BOOST_STATIC_ASSERT((
  120. is_convertible<
  121. BOOST_DEDUCED_TYPENAME iostreams::category_of<Sink>::type,
  122. output
  123. >::value
  124. ));
  125. struct category
  126. : mode,
  127. device_tag,
  128. closable_tag,
  129. flushable_tag,
  130. localizable_tag,
  131. optimally_buffered_tag
  132. { };
  133. tee_device(device_param device, sink_param sink)
  134. : dev_(device), sink_(sink)
  135. { }
  136. std::streamsize read(char_type* s, std::streamsize n)
  137. {
  138. BOOST_STATIC_ASSERT((
  139. is_convertible<
  140. BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, input
  141. >::value
  142. ));
  143. std::streamsize result1 = iostreams::read(dev_, s, n);
  144. if (result1 != -1) {
  145. std::streamsize result2 = iostreams::write(sink_, s, result1);
  146. (void) result1; // Suppress 'unused variable' warning.
  147. (void) result2;
  148. BOOST_ASSERT(result1 == result2);
  149. }
  150. return result1;
  151. }
  152. std::streamsize write(const char_type* s, std::streamsize n)
  153. {
  154. BOOST_STATIC_ASSERT((
  155. is_convertible<
  156. BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, output
  157. >::value
  158. ));
  159. std::streamsize result1 = iostreams::write(dev_, s, n);
  160. std::streamsize result2 = iostreams::write(sink_, s, n);
  161. (void) result1; // Suppress 'unused variable' warning.
  162. (void) result2;
  163. BOOST_ASSERT(result1 == n && result2 == n);
  164. return n;
  165. }
  166. void close()
  167. {
  168. detail::execute_all( detail::call_close_all(dev_),
  169. detail::call_close_all(sink_) );
  170. }
  171. bool flush()
  172. {
  173. bool r1 = iostreams::flush(dev_);
  174. bool r2 = iostreams::flush(sink_);
  175. return r1 && r2;
  176. }
  177. template<typename Locale>
  178. void imbue(const Locale& loc)
  179. {
  180. iostreams::imbue(dev_, loc);
  181. iostreams::imbue(sink_, loc);
  182. }
  183. std::streamsize optimal_buffer_size() const
  184. {
  185. return (std::max) ( iostreams::optimal_buffer_size(dev_),
  186. iostreams::optimal_buffer_size(sink_) );
  187. }
  188. private:
  189. device_value dev_;
  190. sink_value sink_;
  191. };
  192. template<typename Sink>
  193. tee_filter<Sink> tee(Sink& snk)
  194. { return tee_filter<Sink>(snk); }
  195. template<typename Sink>
  196. tee_filter<Sink> tee(const Sink& snk)
  197. { return tee_filter<Sink>(snk); }
  198. template<typename Device, typename Sink>
  199. tee_device<Device, Sink> tee(Device& dev, Sink& sink)
  200. { return tee_device<Device, Sink>(dev, sink); }
  201. template<typename Device, typename Sink>
  202. tee_device<Device, Sink> tee(const Device& dev, Sink& sink)
  203. { return tee_device<Device, Sink>(dev, sink); }
  204. template<typename Device, typename Sink>
  205. tee_device<Device, Sink> tee(Device& dev, const Sink& sink)
  206. { return tee_device<Device, Sink>(dev, sink); }
  207. template<typename Device, typename Sink>
  208. tee_device<Device, Sink> tee(const Device& dev, const Sink& sink)
  209. { return tee_device<Device, Sink>(dev, sink); }
  210. } } // End namespaces iostreams, boost.
  211. #endif // #ifndef BOOST_IOSTREAMS_TEE_HPP_INCLUDED