$search
00001 // 00002 // buffered_write_stream.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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; // For memcpy. 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; // For memcpy. 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 // The data in the buffer. 00361 detail::buffered_stream_storage storage_; 00362 }; 00363 00364 } // namespace asio 00365 00366 #include "asio/detail/pop_options.hpp" 00367 00368 #endif // ASIO_BUFFERED_WRITE_STREAM_HPP