copy.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. // Contains: The function template copy, which reads data from a Source
  7. // and writes it to a Sink until the end of the sequence is reached, returning
  8. // the number of characters transfered.
  9. // The implementation is complicated by the need to handle smart adapters
  10. // and direct devices.
  11. #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED
  12. #define BOOST_IOSTREAMS_COPY_HPP_INCLUDED
  13. #if defined(_MSC_VER)
  14. # pragma once
  15. #endif
  16. #include <boost/config.hpp> // Make sure ptrdiff_t is in std.
  17. #include <algorithm> // copy, min.
  18. #include <cstddef> // ptrdiff_t.
  19. #include <utility> // pair.
  20. #include <boost/bind.hpp>
  21. #include <boost/detail/workaround.hpp>
  22. #include <boost/iostreams/chain.hpp>
  23. #include <boost/iostreams/constants.hpp>
  24. #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>
  25. #include <boost/iostreams/detail/buffer.hpp>
  26. #include <boost/iostreams/detail/enable_if_stream.hpp>
  27. #include <boost/iostreams/detail/execute.hpp>
  28. #include <boost/iostreams/detail/functional.hpp>
  29. #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
  30. #include <boost/iostreams/detail/resolve.hpp>
  31. #include <boost/iostreams/detail/wrap_unwrap.hpp>
  32. #include <boost/iostreams/operations.hpp> // read, write, close.
  33. #include <boost/iostreams/pipeline.hpp>
  34. #include <boost/static_assert.hpp>
  35. #include <boost/type_traits/is_same.hpp>
  36. namespace boost { namespace iostreams {
  37. namespace detail {
  38. // The following four overloads of copy_impl() optimize
  39. // copying in the case that one or both of the two devices
  40. // models Direct (see
  41. // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4)
  42. // Copy from a direct source to a direct sink
  43. template<typename Source, typename Sink>
  44. std::streamsize copy_impl( Source& src, Sink& snk,
  45. std::streamsize /* buffer_size */,
  46. mpl::true_, mpl::true_ )
  47. {
  48. using namespace std;
  49. typedef typename char_type_of<Source>::type char_type;
  50. typedef std::pair<char_type*, char_type*> pair_type;
  51. pair_type p1 = iostreams::input_sequence(src);
  52. pair_type p2 = iostreams::output_sequence(snk);
  53. std::streamsize total =
  54. static_cast<std::streamsize>(
  55. (std::min)(p1.second - p1.first, p2.second - p2.first)
  56. );
  57. std::copy(p1.first, p1.first + total, p2.first);
  58. return total;
  59. }
  60. // Copy from a direct source to an indirect sink
  61. template<typename Source, typename Sink>
  62. std::streamsize copy_impl( Source& src, Sink& snk,
  63. std::streamsize /* buffer_size */,
  64. mpl::true_, mpl::false_ )
  65. {
  66. using namespace std;
  67. typedef typename char_type_of<Source>::type char_type;
  68. typedef std::pair<char_type*, char_type*> pair_type;
  69. pair_type p = iostreams::input_sequence(src);
  70. std::streamsize size, total;
  71. for ( total = 0, size = static_cast<std::streamsize>(p.second - p.first);
  72. total < size; )
  73. {
  74. std::streamsize amt =
  75. iostreams::write(snk, p.first + total, size - total);
  76. total += amt;
  77. }
  78. return total;
  79. }
  80. // Copy from an indirect source to a direct sink
  81. template<typename Source, typename Sink>
  82. std::streamsize copy_impl( Source& src, Sink& snk,
  83. std::streamsize buffer_size,
  84. mpl::false_, mpl::true_ )
  85. {
  86. typedef typename char_type_of<Source>::type char_type;
  87. typedef std::pair<char_type*, char_type*> pair_type;
  88. detail::basic_buffer<char_type> buf(buffer_size);
  89. pair_type p = snk.output_sequence();
  90. std::streamsize total = 0;
  91. std::ptrdiff_t capacity = p.second - p.first;
  92. while (true) {
  93. std::streamsize amt =
  94. iostreams::read(
  95. src,
  96. buf.data(),
  97. buffer_size < capacity - total ?
  98. buffer_size :
  99. static_cast<std::streamsize>(capacity - total)
  100. );
  101. if (amt == -1)
  102. break;
  103. std::copy(buf.data(), buf.data() + amt, p.first + total);
  104. total += amt;
  105. }
  106. return total;
  107. }
  108. // Copy from an indirect source to an indirect sink
  109. template<typename Source, typename Sink>
  110. std::streamsize copy_impl( Source& src, Sink& snk,
  111. std::streamsize buffer_size,
  112. mpl::false_, mpl::false_ )
  113. {
  114. typedef typename char_type_of<Source>::type char_type;
  115. detail::basic_buffer<char_type> buf(buffer_size);
  116. non_blocking_adapter<Sink> nb(snk);
  117. std::streamsize total = 0;
  118. bool done = false;
  119. while (!done) {
  120. std::streamsize amt;
  121. done = (amt = iostreams::read(src, buf.data(), buffer_size)) == -1;
  122. if (amt != -1) {
  123. iostreams::write(nb, buf.data(), amt);
  124. total += amt;
  125. }
  126. }
  127. return total;
  128. }
  129. // The following function object is used with
  130. // boost::iostreams::detail::execute() in the primary
  131. // overload of copy_impl(), below
  132. // Function object that delegates to one of the above four
  133. // overloads of compl_impl()
  134. template<typename Source, typename Sink>
  135. class copy_operation {
  136. public:
  137. typedef std::streamsize result_type;
  138. copy_operation(Source& src, Sink& snk, std::streamsize buffer_size)
  139. : src_(src), snk_(snk), buffer_size_(buffer_size)
  140. { }
  141. std::streamsize operator()()
  142. {
  143. return copy_impl( src_, snk_, buffer_size_,
  144. is_direct<Source>(), is_direct<Sink>() );
  145. }
  146. private:
  147. copy_operation& operator=(const copy_operation&);
  148. Source& src_;
  149. Sink& snk_;
  150. std::streamsize buffer_size_;
  151. };
  152. // Primary overload of copy_impl. Delegates to one of the above four
  153. // overloads of compl_impl(), depending on which of the two given
  154. // devices, if any, models Direct (see
  155. // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4)
  156. template<typename Source, typename Sink>
  157. std::streamsize copy_impl(Source src, Sink snk, std::streamsize buffer_size)
  158. {
  159. using namespace std;
  160. typedef typename char_type_of<Source>::type src_char;
  161. typedef typename char_type_of<Sink>::type snk_char;
  162. BOOST_STATIC_ASSERT((is_same<src_char, snk_char>::value));
  163. return detail::execute_all(
  164. copy_operation<Source, Sink>(src, snk, buffer_size),
  165. detail::call_close_all(src),
  166. detail::call_close_all(snk)
  167. );
  168. }
  169. } // End namespace detail.
  170. //------------------Definition of copy----------------------------------------//
  171. // Overload of copy() for the case where neither the source nor the sink is
  172. // a standard stream or stream buffer
  173. template<typename Source, typename Sink>
  174. std::streamsize
  175. copy( const Source& src, const Sink& snk,
  176. std::streamsize buffer_size = default_device_buffer_size
  177. BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source)
  178. BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) )
  179. {
  180. typedef typename char_type_of<Source>::type char_type;
  181. return detail::copy_impl( detail::resolve<input, char_type>(src),
  182. detail::resolve<output, char_type>(snk),
  183. buffer_size );
  184. }
  185. // Overload of copy() for the case where the source, but not the sink, is
  186. // a standard stream or stream buffer
  187. template<typename Source, typename Sink>
  188. std::streamsize
  189. copy( Source& src, const Sink& snk,
  190. std::streamsize buffer_size = default_device_buffer_size
  191. BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source)
  192. BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) )
  193. {
  194. typedef typename char_type_of<Source>::type char_type;
  195. return detail::copy_impl( detail::wrap(src),
  196. detail::resolve<output, char_type>(snk),
  197. buffer_size );
  198. }
  199. // Overload of copy() for the case where the sink, but not the source, is
  200. // a standard stream or stream buffer
  201. template<typename Source, typename Sink>
  202. std::streamsize
  203. copy( const Source& src, Sink& snk,
  204. std::streamsize buffer_size = default_device_buffer_size
  205. BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source)
  206. BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) )
  207. {
  208. typedef typename char_type_of<Source>::type char_type;
  209. return detail::copy_impl( detail::resolve<input, char_type>(src),
  210. detail::wrap(snk), buffer_size );
  211. }
  212. // Overload of copy() for the case where neither the source nor the sink is
  213. // a standard stream or stream buffer
  214. template<typename Source, typename Sink>
  215. std::streamsize
  216. copy( Source& src, Sink& snk,
  217. std::streamsize buffer_size = default_device_buffer_size
  218. BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source)
  219. BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) )
  220. {
  221. return detail::copy_impl(detail::wrap(src), detail::wrap(snk), buffer_size);
  222. }
  223. } } // End namespaces iostreams, boost.
  224. #endif // #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED