00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_BUFFERED_WRITE_STREAM_HPP
00012 #define ASIO_BUFFERED_WRITE_STREAM_HPP
00013
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017
00018 #include "asio/detail/push_options.hpp"
00019
00020 #include "asio/detail/push_options.hpp"
00021 #include <cstddef>
00022 #include <cstring>
00023 #include <boost/config.hpp>
00024 #include <boost/type_traits.hpp>
00025 #include "asio/detail/pop_options.hpp"
00026
00027 #include "asio/buffered_write_stream_fwd.hpp"
00028 #include "asio/buffer.hpp"
00029 #include "asio/completion_condition.hpp"
00030 #include "asio/error.hpp"
00031 #include "asio/io_service.hpp"
00032 #include "asio/write.hpp"
00033 #include "asio/detail/bind_handler.hpp"
00034 #include "asio/detail/buffered_stream_storage.hpp"
00035 #include "asio/detail/noncopyable.hpp"
00036
00037 namespace asio {
00038
00040
00051 template <typename Stream>
00052 class buffered_write_stream
00053 : private noncopyable
00054 {
00055 public:
00057 typedef typename boost::remove_reference<Stream>::type next_layer_type;
00058
00060 typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
00061
00062 #if defined(GENERATING_DOCUMENTATION)
00064 static const std::size_t default_buffer_size = implementation_defined;
00065 #else
00066 BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
00067 #endif
00068
00070 template <typename Arg>
00071 explicit buffered_write_stream(Arg& a)
00072 : next_layer_(a),
00073 storage_(default_buffer_size)
00074 {
00075 }
00076
00078 template <typename Arg>
00079 buffered_write_stream(Arg& a, std::size_t buffer_size)
00080 : next_layer_(a),
00081 storage_(buffer_size)
00082 {
00083 }
00084
00086 next_layer_type& next_layer()
00087 {
00088 return next_layer_;
00089 }
00090
00092 lowest_layer_type& lowest_layer()
00093 {
00094 return next_layer_.lowest_layer();
00095 }
00096
00098 asio::io_service& io_service()
00099 {
00100 return next_layer_.io_service();
00101 }
00102
00104 void close()
00105 {
00106 next_layer_.close();
00107 }
00108
00110 asio::error_code close(asio::error_code& ec)
00111 {
00112 return next_layer_.close(ec);
00113 }
00114
00118 std::size_t flush()
00119 {
00120 std::size_t bytes_written = write(next_layer_,
00121 buffer(storage_.data(), storage_.size()));
00122 storage_.consume(bytes_written);
00123 return bytes_written;
00124 }
00125
00129 std::size_t flush(asio::error_code& ec)
00130 {
00131 std::size_t bytes_written = write(next_layer_,
00132 buffer(storage_.data(), storage_.size()),
00133 transfer_all(), ec);
00134 storage_.consume(bytes_written);
00135 return bytes_written;
00136 }
00137
00138 template <typename WriteHandler>
00139 class flush_handler
00140 {
00141 public:
00142 flush_handler(asio::io_service& io_service,
00143 detail::buffered_stream_storage& storage, WriteHandler handler)
00144 : io_service_(io_service),
00145 storage_(storage),
00146 handler_(handler)
00147 {
00148 }
00149
00150 void operator()(const asio::error_code& ec,
00151 std::size_t bytes_written)
00152 {
00153 storage_.consume(bytes_written);
00154 io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written));
00155 }
00156
00157 private:
00158 asio::io_service& io_service_;
00159 detail::buffered_stream_storage& storage_;
00160 WriteHandler handler_;
00161 };
00162
00164 template <typename WriteHandler>
00165 void async_flush(WriteHandler handler)
00166 {
00167 async_write(next_layer_, buffer(storage_.data(), storage_.size()),
00168 flush_handler<WriteHandler>(io_service(), storage_, handler));
00169 }
00170
00173 template <typename ConstBufferSequence>
00174 std::size_t write_some(const ConstBufferSequence& buffers)
00175 {
00176 if (storage_.size() == storage_.capacity())
00177 flush();
00178 return copy(buffers);
00179 }
00180
00183 template <typename ConstBufferSequence>
00184 std::size_t write_some(const ConstBufferSequence& buffers,
00185 asio::error_code& ec)
00186 {
00187 ec = asio::error_code();
00188 if (storage_.size() == storage_.capacity() && !flush(ec))
00189 return 0;
00190 return copy(buffers);
00191 }
00192
00193 template <typename ConstBufferSequence, typename WriteHandler>
00194 class write_some_handler
00195 {
00196 public:
00197 write_some_handler(asio::io_service& io_service,
00198 detail::buffered_stream_storage& storage,
00199 const ConstBufferSequence& buffers, WriteHandler handler)
00200 : io_service_(io_service),
00201 storage_(storage),
00202 buffers_(buffers),
00203 handler_(handler)
00204 {
00205 }
00206
00207 void operator()(const asio::error_code& ec, std::size_t)
00208 {
00209 if (ec)
00210 {
00211 std::size_t length = 0;
00212 io_service_.dispatch(detail::bind_handler(handler_, ec, length));
00213 }
00214 else
00215 {
00216 using namespace std;
00217
00218 std::size_t orig_size = storage_.size();
00219 std::size_t space_avail = storage_.capacity() - orig_size;
00220 std::size_t bytes_copied = 0;
00221
00222 typename ConstBufferSequence::const_iterator iter = buffers_.begin();
00223 typename ConstBufferSequence::const_iterator end = buffers_.end();
00224 for (; iter != end && space_avail > 0; ++iter)
00225 {
00226 std::size_t bytes_avail = buffer_size(*iter);
00227 std::size_t length = (bytes_avail < space_avail)
00228 ? bytes_avail : space_avail;
00229 storage_.resize(orig_size + bytes_copied + length);
00230 memcpy(storage_.data() + orig_size + bytes_copied,
00231 buffer_cast<const void*>(*iter), length);
00232 bytes_copied += length;
00233 space_avail -= length;
00234 }
00235
00236 io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
00237 }
00238 }
00239
00240 private:
00241 asio::io_service& io_service_;
00242 detail::buffered_stream_storage& storage_;
00243 ConstBufferSequence buffers_;
00244 WriteHandler handler_;
00245 };
00246
00249 template <typename ConstBufferSequence, typename WriteHandler>
00250 void async_write_some(const ConstBufferSequence& buffers,
00251 WriteHandler handler)
00252 {
00253 if (storage_.size() == storage_.capacity())
00254 {
00255 async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
00256 io_service(), storage_, buffers, handler));
00257 }
00258 else
00259 {
00260 std::size_t bytes_copied = copy(buffers);
00261 io_service().post(detail::bind_handler(
00262 handler, asio::error_code(), bytes_copied));
00263 }
00264 }
00265
00268 template <typename MutableBufferSequence>
00269 std::size_t read_some(const MutableBufferSequence& buffers)
00270 {
00271 return next_layer_.read_some(buffers);
00272 }
00273
00276 template <typename MutableBufferSequence>
00277 std::size_t read_some(const MutableBufferSequence& buffers,
00278 asio::error_code& ec)
00279 {
00280 return next_layer_.read_some(buffers, ec);
00281 }
00282
00285 template <typename MutableBufferSequence, typename ReadHandler>
00286 void async_read_some(const MutableBufferSequence& buffers,
00287 ReadHandler handler)
00288 {
00289 next_layer_.async_read_some(buffers, handler);
00290 }
00291
00294 template <typename MutableBufferSequence>
00295 std::size_t peek(const MutableBufferSequence& buffers)
00296 {
00297 return next_layer_.peek(buffers);
00298 }
00299
00302 template <typename MutableBufferSequence>
00303 std::size_t peek(const MutableBufferSequence& buffers,
00304 asio::error_code& ec)
00305 {
00306 return next_layer_.peek(buffers, ec);
00307 }
00308
00310 std::size_t in_avail()
00311 {
00312 return next_layer_.in_avail();
00313 }
00314
00316 std::size_t in_avail(asio::error_code& ec)
00317 {
00318 return next_layer_.in_avail(ec);
00319 }
00320
00321 private:
00324 template <typename ConstBufferSequence>
00325 std::size_t copy(const ConstBufferSequence& buffers)
00326 {
00327 using namespace std;
00328
00329 std::size_t orig_size = storage_.size();
00330 std::size_t space_avail = storage_.capacity() - orig_size;
00331 std::size_t bytes_copied = 0;
00332
00333 typename ConstBufferSequence::const_iterator iter = buffers.begin();
00334 typename ConstBufferSequence::const_iterator end = buffers.end();
00335 for (; iter != end && space_avail > 0; ++iter)
00336 {
00337 std::size_t bytes_avail = buffer_size(*iter);
00338 std::size_t length = (bytes_avail < space_avail)
00339 ? bytes_avail : space_avail;
00340 storage_.resize(orig_size + bytes_copied + length);
00341 memcpy(storage_.data() + orig_size + bytes_copied,
00342 buffer_cast<const void*>(*iter), length);
00343 bytes_copied += length;
00344 space_avail -= length;
00345 }
00346
00347 return bytes_copied;
00348 }
00349
00351 Stream next_layer_;
00352
00353
00354 detail::buffered_stream_storage storage_;
00355 };
00356
00357 }
00358
00359 #include "asio/detail/pop_options.hpp"
00360
00361 #endif // ASIO_BUFFERED_WRITE_STREAM_HPP