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