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)
00063
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
00099 asio::io_service& io_service()
00100 {
00101 return next_layer_.get_io_service();
00102 }
00103
00105 asio::io_service& get_io_service()
00106 {
00107 return next_layer_.get_io_service();
00108 }
00109
00111 void close()
00112 {
00113 next_layer_.close();
00114 }
00115
00117 asio::error_code close(asio::error_code& ec)
00118 {
00119 return next_layer_.close(ec);
00120 }
00121
00125 std::size_t flush()
00126 {
00127 std::size_t bytes_written = write(next_layer_,
00128 buffer(storage_.data(), storage_.size()));
00129 storage_.consume(bytes_written);
00130 return bytes_written;
00131 }
00132
00136 std::size_t flush(asio::error_code& ec)
00137 {
00138 std::size_t bytes_written = write(next_layer_,
00139 buffer(storage_.data(), storage_.size()),
00140 transfer_all(), ec);
00141 storage_.consume(bytes_written);
00142 return bytes_written;
00143 }
00144
00145 template <typename WriteHandler>
00146 class flush_handler
00147 {
00148 public:
00149 flush_handler(asio::io_service& io_service,
00150 detail::buffered_stream_storage& storage, WriteHandler handler)
00151 : io_service_(io_service),
00152 storage_(storage),
00153 handler_(handler)
00154 {
00155 }
00156
00157 void operator()(const asio::error_code& ec,
00158 std::size_t bytes_written)
00159 {
00160 storage_.consume(bytes_written);
00161 io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written));
00162 }
00163
00164 private:
00165 asio::io_service& io_service_;
00166 detail::buffered_stream_storage& storage_;
00167 WriteHandler handler_;
00168 };
00169
00171 template <typename WriteHandler>
00172 void async_flush(WriteHandler handler)
00173 {
00174 async_write(next_layer_, buffer(storage_.data(), storage_.size()),
00175 flush_handler<WriteHandler>(get_io_service(), storage_, handler));
00176 }
00177
00180 template <typename ConstBufferSequence>
00181 std::size_t write_some(const ConstBufferSequence& buffers)
00182 {
00183 if (storage_.size() == storage_.capacity())
00184 flush();
00185 return copy(buffers);
00186 }
00187
00190 template <typename ConstBufferSequence>
00191 std::size_t write_some(const ConstBufferSequence& buffers,
00192 asio::error_code& ec)
00193 {
00194 ec = asio::error_code();
00195 if (storage_.size() == storage_.capacity() && !flush(ec))
00196 return 0;
00197 return copy(buffers);
00198 }
00199
00200 template <typename ConstBufferSequence, typename WriteHandler>
00201 class write_some_handler
00202 {
00203 public:
00204 write_some_handler(asio::io_service& io_service,
00205 detail::buffered_stream_storage& storage,
00206 const ConstBufferSequence& buffers, WriteHandler handler)
00207 : io_service_(io_service),
00208 storage_(storage),
00209 buffers_(buffers),
00210 handler_(handler)
00211 {
00212 }
00213
00214 void operator()(const asio::error_code& ec, std::size_t)
00215 {
00216 if (ec)
00217 {
00218 std::size_t length = 0;
00219 io_service_.dispatch(detail::bind_handler(handler_, ec, length));
00220 }
00221 else
00222 {
00223 using namespace std;
00224
00225 std::size_t orig_size = storage_.size();
00226 std::size_t space_avail = storage_.capacity() - orig_size;
00227 std::size_t bytes_copied = 0;
00228
00229 typename ConstBufferSequence::const_iterator iter = buffers_.begin();
00230 typename ConstBufferSequence::const_iterator end = buffers_.end();
00231 for (; iter != end && space_avail > 0; ++iter)
00232 {
00233 std::size_t bytes_avail = buffer_size(*iter);
00234 std::size_t length = (bytes_avail < space_avail)
00235 ? bytes_avail : space_avail;
00236 storage_.resize(orig_size + bytes_copied + length);
00237 memcpy(storage_.data() + orig_size + bytes_copied,
00238 buffer_cast<const void*>(*iter), length);
00239 bytes_copied += length;
00240 space_avail -= length;
00241 }
00242
00243 io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
00244 }
00245 }
00246
00247 private:
00248 asio::io_service& io_service_;
00249 detail::buffered_stream_storage& storage_;
00250 ConstBufferSequence buffers_;
00251 WriteHandler handler_;
00252 };
00253
00256 template <typename ConstBufferSequence, typename WriteHandler>
00257 void async_write_some(const ConstBufferSequence& buffers,
00258 WriteHandler handler)
00259 {
00260 if (storage_.size() == storage_.capacity())
00261 {
00262 async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
00263 get_io_service(), storage_, buffers, handler));
00264 }
00265 else
00266 {
00267 std::size_t bytes_copied = copy(buffers);
00268 get_io_service().post(detail::bind_handler(
00269 handler, asio::error_code(), bytes_copied));
00270 }
00271 }
00272
00275 template <typename MutableBufferSequence>
00276 std::size_t read_some(const MutableBufferSequence& buffers)
00277 {
00278 return next_layer_.read_some(buffers);
00279 }
00280
00283 template <typename MutableBufferSequence>
00284 std::size_t read_some(const MutableBufferSequence& buffers,
00285 asio::error_code& ec)
00286 {
00287 return next_layer_.read_some(buffers, ec);
00288 }
00289
00292 template <typename MutableBufferSequence, typename ReadHandler>
00293 void async_read_some(const MutableBufferSequence& buffers,
00294 ReadHandler handler)
00295 {
00296 next_layer_.async_read_some(buffers, handler);
00297 }
00298
00301 template <typename MutableBufferSequence>
00302 std::size_t peek(const MutableBufferSequence& buffers)
00303 {
00304 return next_layer_.peek(buffers);
00305 }
00306
00309 template <typename MutableBufferSequence>
00310 std::size_t peek(const MutableBufferSequence& buffers,
00311 asio::error_code& ec)
00312 {
00313 return next_layer_.peek(buffers, ec);
00314 }
00315
00317 std::size_t in_avail()
00318 {
00319 return next_layer_.in_avail();
00320 }
00321
00323 std::size_t in_avail(asio::error_code& ec)
00324 {
00325 return next_layer_.in_avail(ec);
00326 }
00327
00328 private:
00331 template <typename ConstBufferSequence>
00332 std::size_t copy(const ConstBufferSequence& buffers)
00333 {
00334 using namespace std;
00335
00336 std::size_t orig_size = storage_.size();
00337 std::size_t space_avail = storage_.capacity() - orig_size;
00338 std::size_t bytes_copied = 0;
00339
00340 typename ConstBufferSequence::const_iterator iter = buffers.begin();
00341 typename ConstBufferSequence::const_iterator end = buffers.end();
00342 for (; iter != end && space_avail > 0; ++iter)
00343 {
00344 std::size_t bytes_avail = buffer_size(*iter);
00345 std::size_t length = (bytes_avail < space_avail)
00346 ? bytes_avail : space_avail;
00347 storage_.resize(orig_size + bytes_copied + length);
00348 memcpy(storage_.data() + orig_size + bytes_copied,
00349 buffer_cast<const void*>(*iter), length);
00350 bytes_copied += length;
00351 space_avail -= length;
00352 }
00353
00354 return bytes_copied;
00355 }
00356
00358 Stream next_layer_;
00359
00360
00361 detail::buffered_stream_storage storage_;
00362 };
00363
00364 }
00365
00366 #include "asio/detail/pop_options.hpp"
00367
00368 #endif // ASIO_BUFFERED_WRITE_STREAM_HPP