Add support for dynamic buffer sequences. This commit adds: - New dynamic_string_buffer and dynamic_vector_buffer adapter classes that meet the DynamicBufferSequence type requirements. - New dynamic_buffer() factory functions for creating a dynamic buffer adapter for a vector or string. - New overloads for the read(), async_read(), write() and async_write(), read_until() and async_read_until() free functions. N.B. the read_at, async_read_at, write_at and async_write_at functions have not yet been updated to support dynamic buffer sequences.
diff --git a/asio/include/asio/basic_streambuf.hpp b/asio/include/asio/basic_streambuf.hpp index bacc485..b55c2f6 100644 --- a/asio/include/asio/basic_streambuf.hpp +++ b/asio/include/asio/basic_streambuf.hpp
@@ -155,7 +155,7 @@ * } * @endcode */ - std::size_t size() const + std::size_t size() const ASIO_NOEXCEPT { return pptr() - gptr(); } @@ -165,11 +165,21 @@ * @returns The allowed maximum of the sum of the sizes of the input sequence * and output sequence. */ - std::size_t max_size() const + std::size_t max_size() const ASIO_NOEXCEPT { return max_size_; } + /// Get the current capacity of the basic_streambuf. + /** + * @returns The current total capacity of the streambuf, i.e. for both the + * input sequence and output sequence. + */ + std::size_t capacity() const ASIO_NOEXCEPT + { + return buffer_.capacity(); + } + /// Get a list of buffers that represents the input sequence. /** * @returns An object of type @c const_buffers_type that satisfies @@ -179,7 +189,7 @@ * @note The returned object is invalidated by any @c basic_streambuf member * function that modifies the input sequence or output sequence. */ - const_buffers_type data() const + const_buffers_type data() const ASIO_NOEXCEPT { return asio::buffer(asio::const_buffer(gptr(), (pptr() - gptr()) * sizeof(char_type))); @@ -350,15 +360,89 @@ } }; -// Helper function to get the preferred size for reading data. Used for any -// user-provided specialisations of basic_streambuf. +/// Adapts basic_streambuf to the dynamic buffer sequence type requirements. +#if defined(GENERATING_DOCUMENTATION) +template <typename Allocator = std::allocator<char> > +#else template <typename Allocator> -inline std::size_t read_size_helper( - basic_streambuf<Allocator>& sb, std::size_t max_size) +#endif +class basic_streambuf_ref { - return std::min<std::size_t>(512, - std::min<std::size_t>(max_size, sb.max_size() - sb.size())); -} +public: + /// The type used to represent the input sequence as a list of buffers. + typedef typename basic_streambuf<Allocator>::const_buffers_type + const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef typename basic_streambuf<Allocator>::mutable_buffers_type + mutable_buffers_type; + + /// Construct a basic_streambuf_ref for the given basic_streambuf object. + explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb) + : sb_(sb) + { + } + + /// Copy construct a basic_streambuf_ref. + basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT + : sb_(other.sb_) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a basic_streambuf_ref. + basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT + : sb_(other.sb_) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const ASIO_NOEXCEPT + { + return sb_.size(); + } + + /// Get the maximum size of the dynamic buffer. + std::size_t max_size() const ASIO_NOEXCEPT + { + return sb_.max_size(); + } + + /// Get the current capacity of the dynamic buffer. + std::size_t capacity() const ASIO_NOEXCEPT + { + return sb_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + const_buffers_type data() const ASIO_NOEXCEPT + { + return sb_.data(); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + mutable_buffers_type prepare(std::size_t n) + { + return sb_.prepare(n); + } + + /// Move bytes from the output sequence to the input sequence. + void commit(std::size_t n) + { + return sb_.commit(n); + } + + /// Remove characters from the input sequence. + void consume(std::size_t n) + { + return sb_.consume(n); + } + +private: + basic_streambuf<Allocator>& sb_; +}; } // namespace asio
diff --git a/asio/include/asio/basic_streambuf_fwd.hpp b/asio/include/asio/basic_streambuf_fwd.hpp index 8fd0ae8..4ac3e42 100644 --- a/asio/include/asio/basic_streambuf_fwd.hpp +++ b/asio/include/asio/basic_streambuf_fwd.hpp
@@ -26,6 +26,9 @@ template <typename Allocator = std::allocator<char> > class basic_streambuf; +template <typename Allocator = std::allocator<char> > +class basic_streambuf_ref; + } // namespace asio #endif // !defined(ASIO_NO_IOSTREAM)
diff --git a/asio/include/asio/buffer.hpp b/asio/include/asio/buffer.hpp index 2cc06bb..b2da915 100644 --- a/asio/include/asio/buffer.hpp +++ b/asio/include/asio/buffer.hpp
@@ -18,10 +18,13 @@ #include "asio/detail/config.hpp" #include <cstddef> #include <cstring> +#include <limits> +#include <stdexcept> #include <string> #include <vector> #include "asio/detail/array_fwd.hpp" #include "asio/detail/is_buffer_sequence.hpp" +#include "asio/detail/throw_exception.hpp" #include "asio/detail/type_traits.hpp" #if defined(ASIO_MSVC) @@ -345,6 +348,18 @@ { }; +/// Trait to determine whether a type satisfies the DynamicBufferSequence +/// requirements. +template <typename T> +struct is_dynamic_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_dynamic_buffer_sequence<T> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + /// (Deprecated: Use the socket/descriptor wait() and async_wait() member /// functions.) An implementation of both the ConstBufferSequence and /// MutableBufferSequence concepts to represent a null buffer sequence. @@ -1324,6 +1339,356 @@ /*@}*/ +/// Adapt a basic_string to the DynamicBufferSequence requirements. +/** + * Requires that <tt>sizeof(Elem) == 1</tt>. + */ +template <typename Elem, typename Traits, typename Allocator> +class dynamic_string_buffer +{ +public: + /// The type used to represent the input sequence as a list of buffers. + typedef const_buffers_1 const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef mutable_buffers_1 mutable_buffers_type; + + /// Construct a dynamic buffer from a string. + /** + * @param s The string to be used as backing storage for the dynamic buffer. + * Any existing data in the string is treated as the dynamic buffer's input + * sequence. The object stores a reference to the string and the user is + * responsible for ensuring that the string object remains valid until the + * dynamic_string_buffer object is destroyed. + */ + explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s, + std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)()) + : string_(s), + size_(string_.size()), + max_size_(maximum_size) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_string_buffer(dynamic_string_buffer&& other) + : string_(other.string_), + size_(other.size_), + max_size_(other.max_size_) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const ASIO_NOEXCEPT + { + return size_; + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ + std::size_t max_size() const ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the current capacity of the dynamic buffer. + /** + * @returns The current total capacity of the buffer, i.e. for both the input + * sequence and output sequence. + */ + std::size_t capacity() const ASIO_NOEXCEPT + { + return string_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the basic_string memory in + * input sequence. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + const_buffers_type data() const ASIO_NOEXCEPT + { + return asio::buffer(string_, size_); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * basic_string object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing basic_string memory + * at the start of the output sequence of size @c n. + * + * @throws std::length_error If <tt>size() + n > max_size()</tt>. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size () > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + asio::detail::throw_exception(ex); + } + + string_.resize(size_ + n); + + return asio::buffer(asio::buffer(string_) + size_, n); + } + + /// Move bytes from the output sequence to the input sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, string_.size() - size_); + string_.resize(size_); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @note If @c n is greater than the size of the input sequence, the entire + * input sequence is consumed and no error is issued. + */ + void consume(std::size_t n) + { + std::size_t consume_length = (std::min)(n, size_); + string_.erase(consume_length); + size_ -= consume_length; + } + +private: + std::basic_string<Elem, Traits, Allocator>& string_; + std::size_t size_; + const std::size_t max_size_; +}; + +/// Adapt a vector to the DynamicBufferSequence requirements. +/** + * Requires that <tt>sizeof(Elem) == 1</tt>. + */ +template <typename Elem, typename Allocator> +class dynamic_vector_buffer +{ +public: + /// The type used to represent the input sequence as a list of buffers. + typedef const_buffers_1 const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef mutable_buffers_1 mutable_buffers_type; + + /// Construct a dynamic buffer from a string. + /** + * @param s The string to be used as backing storage for the dynamic buffer. + * Any existing data in the string is treated as the dynamic buffer's input + * sequence. The object stores a reference to the string and the user is + * responsible for ensuring that the string object remains valid until the + * dynamic_vector_buffer object is destroyed. + */ + explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v, + std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)()) + : vector_(v), + size_(vector_.size()), + max_size_(maximum_size) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_vector_buffer(dynamic_vector_buffer&& other) + : vector_(other.vector_), + size_(other.size_), + max_size_(other.max_size_) + { + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const ASIO_NOEXCEPT + { + return size_; + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ + std::size_t max_size() const ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the current capacity of the dynamic buffer. + /** + * @returns The current total capacity of the buffer, i.e. for both the input + * sequence and output sequence. + */ + std::size_t capacity() const ASIO_NOEXCEPT + { + return vector_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the basic_string memory in + * input sequence. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + const_buffers_type data() const ASIO_NOEXCEPT + { + return asio::buffer(vector_, size_); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * basic_string object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing basic_string memory + * at the start of the output sequence of size @c n. + * + * @throws std::length_error If <tt>size() + n > max_size()</tt>. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size () > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + asio::detail::throw_exception(ex); + } + + vector_.resize(size_ + n); + + return asio::buffer(asio::buffer(vector_) + size_, n); + } + + /// Move bytes from the output sequence to the input sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, vector_.size() - size_); + vector_.resize(size_); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @note If @c n is greater than the size of the input sequence, the entire + * input sequence is consumed and no error is issued. + */ + void consume(std::size_t n) + { + std::size_t consume_length = (std::min)(n, size_); + vector_.erase(consume_length); + size_ -= consume_length; + } + +private: + std::vector<Elem, Allocator>& vector_; + std::size_t size_; + const std::size_t max_size_; +}; + +/** @defgroup dynamic_buffer asio::dynamic_buffer + * + * @brief The asio::dynamic_buffer function is used to create a + * dynamically resized buffer from a @c std::basic_string or @c std::vector. + */ +/*@{*/ + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>. + */ +template <typename Elem, typename Traits, typename Allocator> +inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( + std::basic_string<Elem, Traits, Allocator>& data) +{ + return dynamic_string_buffer<Elem, Traits, Allocator>(data); +} + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data, + * max_size)</tt>. + */ +template <typename Elem, typename Traits, typename Allocator> +inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( + std::basic_string<Elem, Traits, Allocator>& data, std::size_t max_size) +{ + return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size); +} + +/// Create a new dynamic buffer that represents the given vector. +/** + * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>. + */ +template <typename Elem, typename Allocator> +inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( + std::vector<Elem, Allocator>& data) +{ + return dynamic_vector_buffer<Elem, Allocator>(data); +} + +/// Create a new dynamic buffer that represents the given vector. +/** + * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>. + */ +template <typename Elem, typename Allocator> +inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( + std::vector<Elem, Allocator>& data, std::size_t max_size) +{ + return dynamic_vector_buffer<Elem, Allocator>(data, max_size); +} + +/*@}*/ + /** @defgroup buffer_copy asio::buffer_copy * * @brief The asio::buffer_copy function is used to copy bytes from a @@ -1334,7 +1699,7 @@ * @li A 2-argument form: @c buffer_copy(target, source) * * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy) - + * * Both forms return the number of bytes actually copied. The number of bytes * copied is the lesser of: *
diff --git a/asio/include/asio/detail/is_buffer_sequence.hpp b/asio/include/asio/detail/is_buffer_sequence.hpp index 7d8c18f..e1049b2 100644 --- a/asio/include/asio/detail/is_buffer_sequence.hpp +++ b/asio/include/asio/detail/is_buffer_sequence.hpp
@@ -23,20 +23,27 @@ namespace asio { namespace detail { -struct begin_end_memfns_base +struct buffer_sequence_memfns_base { void begin(); void end(); + void size(); + void max_size(); + void capacity(); + void data(); + void prepare(); + void commit(); + void consume(); }; template <typename T> -struct begin_end_memfns_derived - : T, begin_end_memfns_base +struct buffer_sequence_memfns_derived + : T, buffer_sequence_memfns_base { }; template <typename T, T> -struct begin_end_memfns_check +struct buffer_sequence_memfns_check { }; @@ -45,18 +52,81 @@ template <typename T> char begin_memfn_helper( - begin_end_memfns_check< - void (begin_end_memfns_base::*)(), - &begin_end_memfns_derived<T>::begin>*); + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::begin>*); template <typename> char (&end_memfn_helper(...))[2]; template <typename T> char end_memfn_helper( - begin_end_memfns_check< - void (begin_end_memfns_base::*)(), - &begin_end_memfns_derived<T>::end>*); + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::end>*); + +template <typename> +char (&size_memfn_helper(...))[2]; + +template <typename T> +char size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::size>*); + +template <typename> +char (&max_size_memfn_helper(...))[2]; + +template <typename T> +char max_size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::max_size>*); + +template <typename> +char (&capacity_memfn_helper(...))[2]; + +template <typename T> +char capacity_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::capacity>*); + +template <typename> +char (&data_memfn_helper(...))[2]; + +template <typename T> +char data_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::data>*); + +template <typename> +char (&prepare_memfn_helper(...))[2]; + +template <typename T> +char prepare_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::data>*); + +template <typename> +char (&commit_memfn_helper(...))[2]; + +template <typename T> +char commit_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::commit>*); + +template <typename> +char (&consume_memfn_helper(...))[2]; + +template <typename T> +char consume_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::consume>*); template <typename, typename> char (&value_type_const_iterator_typedefs_helper(...))[2]; @@ -67,6 +137,20 @@ typename enable_if<is_convertible< typename T::value_type, Buffer>::value>::type*); +template <typename> +char (&const_buffers_type_typedef_helper(...))[2]; + +template <typename T> +char const_buffers_type_typedef_helper( + typename T::const_buffers_type*); + +template <typename> +char (&mutable_buffers_type_typedef_helper(...))[2]; + +template <typename T> +char mutable_buffers_type_typedef_helper( + typename T::mutable_buffers_type*); + template <typename T, typename Buffer> struct is_buffer_sequence_class : integral_constant<bool, @@ -84,6 +168,29 @@ { }; +template <typename T> +struct is_dynamic_buffer_sequence_class + : integral_constant<bool, + sizeof(size_memfn_helper<T>(0)) != 1 && + sizeof(max_size_memfn_helper<T>(0)) != 1 && + sizeof(capacity_memfn_helper<T>(0)) != 1 && + sizeof(data_memfn_helper<T>(0)) != 1 && + sizeof(consume_memfn_helper<T>(0)) != 1 && + sizeof(prepare_memfn_helper<T>(0)) != 1 && + sizeof(commit_memfn_helper<T>(0)) != 1 && + sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1> +{ +}; + +template <typename T> +struct is_dynamic_buffer_sequence + : conditional<is_class<T>::value, + is_dynamic_buffer_sequence_class<T>, + false_type>::type +{ +}; + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/impl/read.hpp b/asio/include/asio/impl/read.hpp index 2eaba11..99c2788 100644 --- a/asio/include/asio/impl/read.hpp +++ b/asio/include/asio/impl/read.hpp
@@ -39,7 +39,10 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, asio::error_code& ec) + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { ec = asio::error_code(); asio::detail::consuming_buffers< @@ -59,7 +62,10 @@ } template <typename SyncReadStream, typename MutableBufferSequence> -inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); @@ -69,7 +75,10 @@ template <typename SyncReadStream, typename MutableBufferSequence> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - asio::error_code& ec) + asio::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { return read(s, buffers, transfer_all(), ec); } @@ -77,7 +86,10 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition) + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); @@ -85,39 +97,98 @@ return bytes_transferred; } +template <typename SyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + typename decay<DynamicBufferSequence>::type b( + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers)); + + ec = asio::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); + while (bytes_available > 0) + { + std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); + b.commit(bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); + } + return total_transferred; +} + +template <typename SyncReadStream, typename DynamicBufferSequence> +inline std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), transfer_all(), ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBufferSequence> +inline std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + return read(s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + transfer_all(), ec); +} + +template <typename SyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + completion_condition, ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + #if !defined(ASIO_NO_IOSTREAM) template <typename SyncReadStream, typename Allocator, typename CompletionCondition> -std::size_t read(SyncReadStream& s, +inline std::size_t read(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, asio::error_code& ec) { - ec = asio::error_code(); - std::size_t total_transferred = 0; - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred)); - std::size_t bytes_available = read_size_helper(b, max_size); - while (bytes_available > 0) - { - std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); - b.commit(bytes_transferred); - total_transferred += bytes_transferred; - max_size = detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred)); - bytes_available = read_size_helper(b, max_size); - } - return total_transferred; + return read(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); } template <typename SyncReadStream, typename Allocator> inline std::size_t read(SyncReadStream& s, asio::basic_streambuf<Allocator>& b) { - asio::error_code ec; - std::size_t bytes_transferred = read(s, b, transfer_all(), ec); - asio::detail::throw_error(ec, "read"); - return bytes_transferred; + return read(s, basic_streambuf_ref<Allocator>(b)); } template <typename SyncReadStream, typename Allocator> @@ -125,7 +196,7 @@ asio::basic_streambuf<Allocator>& b, asio::error_code& ec) { - return read(s, b, transfer_all(), ec); + return read(s, basic_streambuf_ref<Allocator>(b), ec); } template <typename SyncReadStream, typename Allocator, @@ -134,10 +205,7 @@ asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - asio::error_code ec; - std::size_t bytes_transferred = read(s, b, completion_condition, ec); - asio::detail::throw_error(ec, "read"); - return bytes_transferred; + return read(s, basic_streambuf_ref<Allocator>(b), completion_condition); } #endif // !defined(ASIO_NO_IOSTREAM) @@ -562,7 +630,10 @@ void (asio::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. @@ -585,7 +656,10 @@ inline ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. @@ -603,23 +677,22 @@ return init.result.get(); } -#if !defined(ASIO_NO_IOSTREAM) - namespace detail { - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename CompletionCondition, typename ReadHandler> - class read_streambuf_op + class read_dynbuf_op : detail::base_from_completion_cond<CompletionCondition> { public: - read_streambuf_op(AsyncReadStream& stream, - basic_streambuf<Allocator>& streambuf, + template <typename BufferSequence> + read_dynbuf_op(AsyncReadStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, CompletionCondition completion_condition, ReadHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), - streambuf_(streambuf), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), start_(0), total_transferred_(0), handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) @@ -627,20 +700,20 @@ } #if defined(ASIO_HAS_MOVE) - read_streambuf_op(const read_streambuf_op& other) + read_dynbuf_op(const read_dynbuf_op& other) : detail::base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), start_(other.start_), total_transferred_(other.total_transferred_), handler_(other.handler_) { } - read_streambuf_op(read_streambuf_op&& other) + read_dynbuf_op(read_dynbuf_op&& other) : detail::base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(ASIO_MOVE_CAST(DynamicBufferSequence)(other.buffers_)), start_(other.start_), total_transferred_(other.total_transferred_), handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) @@ -656,16 +729,24 @@ { case 1: max_size = this->check_for_completion(ec, total_transferred_); - bytes_available = read_size_helper(streambuf_, max_size); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); for (;;) { - stream_.async_read_some(streambuf_.prepare(bytes_available), - ASIO_MOVE_CAST(read_streambuf_op)(*this)); + stream_.async_read_some(buffers_.prepare(bytes_available), + ASIO_MOVE_CAST(read_dynbuf_op)(*this)); return; default: total_transferred_ += bytes_transferred; - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); max_size = this->check_for_completion(ec, total_transferred_); - bytes_available = read_size_helper(streambuf_, max_size); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } @@ -676,36 +757,36 @@ //private: AsyncReadStream& stream_; - asio::basic_streambuf<Allocator>& streambuf_; + DynamicBufferSequence buffers_; int start_; std::size_t total_transferred_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename CompletionCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBufferSequence, CompletionCondition, ReadHandler>* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBufferSequence, CompletionCondition, ReadHandler>* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBufferSequence, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -714,9 +795,10 @@ } template <typename Function, typename AsyncReadStream, - typename Allocator, typename CompletionCondition, typename ReadHandler> + typename DynamicBufferSequence, typename CompletionCondition, + typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBufferSequence, CompletionCondition, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( @@ -724,9 +806,10 @@ } template <typename Function, typename AsyncReadStream, - typename Allocator, typename CompletionCondition, typename ReadHandler> + typename DynamicBufferSequence, typename CompletionCondition, + typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBufferSequence, CompletionCondition, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( @@ -736,52 +819,71 @@ #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, - typename CompletionCondition, typename ReadHandler, typename Allocator1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_streambuf_op<AsyncReadStream, - Allocator, CompletionCondition, ReadHandler>, - Allocator1> + detail::read_dynbuf_op<AsyncReadStream, + DynamicBufferSequence, CompletionCondition, ReadHandler>, + Allocator> { - typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_streambuf_op<AsyncReadStream, Allocator, - CompletionCondition, ReadHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + const detail::read_dynbuf_op<AsyncReadStream, + DynamicBufferSequence, CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT { - return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename Executor, - typename CompletionCondition, typename ReadHandler, typename Executor1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_streambuf_op<AsyncReadStream, - Executor, CompletionCondition, ReadHandler>, - Executor1> + detail::read_dynbuf_op<AsyncReadStream, + DynamicBufferSequence, CompletionCondition, ReadHandler>, + Executor> { - typedef typename associated_executor<ReadHandler, Executor1>::type type; + typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_streambuf_op<AsyncReadStream, Executor, - CompletionCondition, ReadHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + const detail::read_dynbuf_op<AsyncReadStream, + DynamicBufferSequence, CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT { - return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + return async_read(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename DynamicBufferSequence, typename CompletionCondition, typename ReadHandler> inline ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. @@ -790,36 +892,39 @@ async_completion<ReadHandler, void (asio::error_code, std::size_t)> init(handler); - detail::read_streambuf_op<AsyncReadStream, Allocator, - CompletionCondition, ASIO_HANDLER_TYPE( - ReadHandler, void (asio::error_code, std::size_t))>( - s, b, completion_condition, init.handler)( - asio::error_code(), 0, 1); + detail::read_dynbuf_op<AsyncReadStream, + typename decay<DynamicBufferSequence>::type, + CompletionCondition, ASIO_HANDLER_TYPE( + ReadHandler, void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + completion_condition, init.handler)( + asio::error_code(), 0, 1); return init.result.get(); } +#if !defined(ASIO_NO_IOSTREAM) + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> inline ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, +async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + return async_read(s, basic_streambuf_ref<Allocator>(b), + ASIO_MOVE_CAST(ReadHandler)(handler)); +} - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_streambuf_op<AsyncReadStream, Allocator, - detail::transfer_all_t, ASIO_HANDLER_TYPE( - ReadHandler, void (asio::error_code, std::size_t))>( - s, b, transfer_all(), init.handler)( - asio::error_code(), 0, 1); - - return init.result.get(); +template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read(s, basic_streambuf_ref<Allocator>(b), + completion_condition, ASIO_MOVE_CAST(ReadHandler)(handler)); } #endif // !defined(ASIO_NO_IOSTREAM)
diff --git a/asio/include/asio/impl/read_until.hpp b/asio/include/asio/impl/read_until.hpp index a27353e..cdada8a 100644 --- a/asio/include/asio/impl/read_until.hpp +++ b/asio/include/asio/impl/read_until.hpp
@@ -35,32 +35,35 @@ namespace asio { -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBufferSequence> inline std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, char delim) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, char delim) { asio::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), delim, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBufferSequence> std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, char delim, - asio::error_code& ec) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + char delim, asio::error_code& ec) { + typename decay<DynamicBufferSequence>::type b( + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBufferSequence::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. iterator iter = std::find(start_pos, end, delim); @@ -84,19 +87,23 @@ } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBufferSequence> inline std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const std::string& delim) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const std::string& delim) { asio::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), delim, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } @@ -136,22 +143,24 @@ } } // namespace detail -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBufferSequence> std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const std::string& delim, - asio::error_code& ec) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const std::string& delim, asio::error_code& ec) { + typename decay<DynamicBufferSequence>::type b( + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBufferSequence::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. std::pair<iterator, bool> result = detail::partial_search( @@ -184,7 +193,9 @@ } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; @@ -193,29 +204,33 @@ #if defined(ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBufferSequence> inline std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const boost::regex& expr) { asio::error_code ec; - std::size_t bytes_transferred = read_until(s, b, expr, ec); + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), expr, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBufferSequence> std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr, - asio::error_code& ec) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const boost::regex& expr, asio::error_code& ec) { + typename decay<DynamicBufferSequence>::type b( + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); + typedef typename DynamicBufferSequence::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position; iterator end = iterator::end(buffers); @@ -262,23 +277,41 @@ #endif // defined(ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename Allocator, typename MatchCondition> +template <typename SyncReadStream, + typename DynamicBufferSequence, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + MatchCondition match_condition, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + match_condition, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, + typename DynamicBufferSequence, typename MatchCondition> std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, MatchCondition match_condition, asio::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { + typename decay<DynamicBufferSequence>::type b( + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBufferSequence::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. std::pair<iterator, bool> result = match_condition(start_pos, end); @@ -307,35 +340,98 @@ } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } +#if !defined(ASIO_NO_IOSTREAM) + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim, + asio::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const std::string& delim) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const std::string& delim, + asio::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); +} + +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), expr); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + asio::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec); +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + template <typename SyncReadStream, typename Allocator, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { - asio::error_code ec; - std::size_t bytes_transferred = read_until(s, b, match_condition, ec); - asio::detail::throw_error(ec, "read_until"); - return bytes_transferred; + return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition); } +template <typename SyncReadStream, typename Allocator, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, asio::error_code& ec, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec); +} + +#endif // !defined(ASIO_NO_IOSTREAM) + namespace detail { - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> class read_until_delim_op { public: + template <typename BufferSequence> read_until_delim_op(AsyncReadStream& stream, - asio::basic_streambuf<Allocator>& streambuf, + ASIO_MOVE_ARG(BufferSequence) buffers, char delim, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), delim_(delim), start_(0), search_position_(0), @@ -346,7 +442,7 @@ #if defined(ASIO_HAS_MOVE) read_until_delim_op(const read_until_delim_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -356,7 +452,7 @@ read_until_delim_op(read_until_delim_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(ASIO_MOVE_CAST(DynamicBufferSequence)(other.buffers_)), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -377,10 +473,10 @@ { { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); + typedef typename DynamicBufferSequence::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type buffers = buffers_.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position_; iterator end = iterator::end(buffers); @@ -395,7 +491,7 @@ } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -406,7 +502,11 @@ { // Next search can start with the new data. search_position_ = end - begin; - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -415,10 +515,10 @@ break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), ASIO_MOVE_CAST(read_until_delim_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -437,56 +537,59 @@ //private: AsyncReadStream& stream_; - asio::basic_streambuf<Allocator>& streambuf_; + DynamicBufferSequence buffers_; char delim_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); @@ -495,48 +598,51 @@ #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, - typename ReadHandler, typename Allocator1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_delim_op<AsyncReadStream, Allocator, ReadHandler>, - Allocator1> + detail::read_until_delim_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>, + Allocator> { - typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_until_delim_op< - AsyncReadStream, Allocator, ReadHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + const detail::read_until_delim_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT { - return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename Executor, - typename ReadHandler, typename Executor1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_delim_op<AsyncReadStream, Executor, ReadHandler>, - Executor1> + detail::read_until_delim_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>, + Executor> { - typedef typename associated_executor<ReadHandler, Executor1>::type type; + typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_until_delim_op< - AsyncReadStream, Executor, ReadHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + const detail::read_until_delim_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT { - return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, char delim, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + char delim, ASIO_MOVE_ARG(ReadHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. @@ -546,25 +652,28 @@ void (asio::error_code, std::size_t)> init(handler); detail::read_until_delim_op<AsyncReadStream, - Allocator, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, b, delim, init.handler)( - asio::error_code(), 0, 1); + typename decay<DynamicBufferSequence>::type, + ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + delim, init.handler)(asio::error_code(), 0, 1); return init.result.get(); } namespace detail { - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> class read_until_delim_string_op { public: + template <typename BufferSequence> read_until_delim_string_op(AsyncReadStream& stream, - asio::basic_streambuf<Allocator>& streambuf, + ASIO_MOVE_ARG(BufferSequence) buffers, const std::string& delim, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), delim_(delim), start_(0), search_position_(0), @@ -575,7 +684,7 @@ #if defined(ASIO_HAS_MOVE) read_until_delim_string_op(const read_until_delim_string_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -585,7 +694,7 @@ read_until_delim_string_op(read_until_delim_string_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(ASIO_MOVE_CAST(DynamicBufferSequence)(other.buffers_)), delim_(ASIO_MOVE_CAST(std::string)(other.delim_)), start_(other.start_), search_position_(other.search_position_), @@ -606,10 +715,10 @@ { { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); + typedef typename DynamicBufferSequence::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type buffers = buffers_.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position_; iterator end = iterator::end(buffers); @@ -625,7 +734,7 @@ } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -646,7 +755,11 @@ search_position_ = end - begin; } - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -655,10 +768,10 @@ break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), ASIO_MOVE_CAST(read_until_delim_string_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -677,35 +790,38 @@ //private: AsyncReadStream& stream_; - asio::basic_streambuf<Allocator>& streambuf_; + DynamicBufferSequence buffers_; std::string delim_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( @@ -713,20 +829,20 @@ } template <typename Function, typename AsyncReadStream, - typename Allocator, typename ReadHandler> + typename DynamicBufferSequence, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncReadStream, - typename Allocator, typename ReadHandler> + typename DynamicBufferSequence, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBufferSequence, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); @@ -735,50 +851,51 @@ #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, - typename ReadHandler, typename Allocator1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_delim_string_op< - AsyncReadStream, Allocator, ReadHandler>, - Allocator1> + detail::read_until_delim_string_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>, + Allocator> { - typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_until_delim_string_op< - AsyncReadStream, Allocator, ReadHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + const detail::read_until_delim_string_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT { - return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename Executor, - typename ReadHandler, typename Executor1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_delim_string_op< - AsyncReadStream, Executor, ReadHandler>, - Executor1> + detail::read_until_delim_string_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>, + Executor> { - typedef typename associated_executor<ReadHandler, Executor1>::type type; + typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_until_delim_string_op< - AsyncReadStream, Executor, ReadHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + const detail::read_until_delim_string_op<AsyncReadStream, + DynamicBufferSequence, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT { - return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const std::string& delim, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const std::string& delim, ASIO_MOVE_ARG(ReadHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. @@ -788,10 +905,11 @@ void (asio::error_code, std::size_t)> init(handler); detail::read_until_delim_string_op<AsyncReadStream, - Allocator, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, b, delim, init.handler)( - asio::error_code(), 0, 1); + typename decay<DynamicBufferSequence>::type, + ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + delim, init.handler)(asio::error_code(), 0, 1); return init.result.get(); } @@ -800,16 +918,17 @@ namespace detail { - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename RegEx, typename ReadHandler> class read_until_expr_op { public: + template <typename BufferSequence> read_until_expr_op(AsyncReadStream& stream, - asio::basic_streambuf<Allocator>& streambuf, + ASIO_MOVE_ARG(BufferSequence) buffers, const boost::regex& expr, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), expr_(expr), start_(0), search_position_(0), @@ -820,7 +939,7 @@ #if defined(ASIO_HAS_MOVE) read_until_expr_op(const read_until_expr_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), expr_(other.expr_), start_(other.start_), search_position_(other.search_position_), @@ -830,7 +949,7 @@ read_until_expr_op(read_until_expr_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(ASIO_MOVE_CAST(DynamicBufferSequence)(other.buffers)), expr_(other.expr_), start_(other.start_), search_position_(other.search_position_), @@ -851,10 +970,10 @@ { { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); + typedef typename DynamicBufferSequence::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type buffers = buffers_.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position_; iterator end = iterator::end(buffers); @@ -873,7 +992,7 @@ } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -894,7 +1013,11 @@ search_position_ = end - begin; } - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -903,10 +1026,10 @@ break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), ASIO_MOVE_CAST(read_until_expr_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -925,59 +1048,59 @@ //private: AsyncReadStream& stream_; - asio::basic_streambuf<Allocator>& streambuf_; + DynamicBufferSequence buffers_; RegEx expr_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename RegEx, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBufferSequence, RegEx, ReadHandler>* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename RegEx, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBufferSequence, RegEx, ReadHandler>* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename RegEx, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBufferSequence, RegEx, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename RegEx, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBufferSequence, typename RegEx, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBufferSequence, RegEx, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename RegEx, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBufferSequence, typename RegEx, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBufferSequence, RegEx, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); @@ -986,47 +1109,51 @@ #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, - typename RegEx, typename ReadHandler, typename Allocator1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename RegEx, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_expr_op<AsyncReadStream, Allocator, RegEx, ReadHandler>, - Allocator1> + detail::read_until_expr_op<AsyncReadStream, + DynamicBufferSequence, RegEx, ReadHandler>, + Allocator> { - typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + DynamicBufferSequence, RegEx, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT { - return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename Executor, - typename RegEx, typename ReadHandler, typename Executor1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename RegEx, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_expr_op<AsyncReadStream, Executor, RegEx, ReadHandler>, - Executor1> + detail::read_until_expr_op<AsyncReadStream, + DynamicBufferSequence, RegEx, ReadHandler>, + Executor> { - typedef typename associated_executor<ReadHandler, Executor1>::type type; + typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_expr_op<AsyncReadStream, - Executor, RegEx, ReadHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + DynamicBufferSequence, RegEx, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT { - return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const boost::regex& expr, ASIO_MOVE_ARG(ReadHandler) handler) { // If you get an error on the following line it means that your handler does @@ -1036,11 +1163,12 @@ async_completion<ReadHandler, void (asio::error_code, std::size_t)> init(handler); - detail::read_until_expr_op<AsyncReadStream, Allocator, - boost::regex, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, b, expr, init.handler)( - asio::error_code(), 0, 1); + detail::read_until_expr_op<AsyncReadStream, + typename decay<DynamicBufferSequence>::type, + boost::regex, ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + expr, init.handler)(asio::error_code(), 0, 1); return init.result.get(); } @@ -1049,16 +1177,17 @@ namespace detail { - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename MatchCondition, typename ReadHandler> class read_until_match_op { public: + template <typename BufferSequence> read_until_match_op(AsyncReadStream& stream, - asio::basic_streambuf<Allocator>& streambuf, + ASIO_MOVE_ARG(BufferSequence) buffers, MatchCondition match_condition, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), match_condition_(match_condition), start_(0), search_position_(0), @@ -1069,7 +1198,7 @@ #if defined(ASIO_HAS_MOVE) read_until_match_op(const read_until_match_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), match_condition_(other.match_condition_), start_(other.start_), search_position_(other.search_position_), @@ -1079,7 +1208,7 @@ read_until_match_op(read_until_match_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(ASIO_MOVE_CAST(DynamicBufferSequence)(other.buffers_)), match_condition_(other.match_condition_), start_(other.start_), search_position_(other.search_position_), @@ -1100,10 +1229,10 @@ { { // Determine the range of the data to be searched. - typedef typename asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); + typedef typename DynamicBufferSequence::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type buffers = buffers_.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position_; iterator end = iterator::end(buffers); @@ -1118,7 +1247,7 @@ } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -1139,7 +1268,11 @@ search_position_ = end - begin; } - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -1148,10 +1281,10 @@ break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), ASIO_MOVE_CAST(read_until_match_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -1170,59 +1303,61 @@ //private: AsyncReadStream& stream_; - asio::basic_streambuf<Allocator>& streambuf_; + DynamicBufferSequence buffers_; MatchCondition match_condition_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename MatchCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBufferSequence, + MatchCondition, ReadHandler>* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename MatchCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBufferSequence, + MatchCondition, ReadHandler>* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBufferSequence, typename MatchCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBufferSequence, + MatchCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBufferSequence, typename MatchCondition, + typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBufferSequence, + MatchCondition, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBufferSequence, typename MatchCondition, + typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBufferSequence, + MatchCondition, ReadHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); @@ -1231,50 +1366,50 @@ #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler, typename Allocator1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename MatchCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>, - Allocator1> + DynamicBufferSequence, MatchCondition, ReadHandler>, + Allocator> { - typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + DynamicBufferSequence, MatchCondition, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT { - return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename Executor, - typename MatchCondition, typename ReadHandler, typename Executor1> +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename MatchCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_match_op<AsyncReadStream, - Executor, MatchCondition, ReadHandler>, - Executor1> + DynamicBufferSequence, MatchCondition, ReadHandler>, + Executor> { - typedef typename associated_executor<ReadHandler, Executor1>::type type; + typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_match_op<AsyncReadStream, - Executor, MatchCondition, ReadHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + DynamicBufferSequence, MatchCondition, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT { - return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, +template <typename AsyncReadStream, typename DynamicBufferSequence, typename MatchCondition, typename ReadHandler> ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { @@ -1285,15 +1420,70 @@ async_completion<ReadHandler, void (asio::error_code, std::size_t)> init(handler); - detail::read_until_match_op<AsyncReadStream, Allocator, - MatchCondition, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, b, match_condition, init.handler)( - asio::error_code(), 0, 1); + detail::read_until_match_op<AsyncReadStream, + typename decay<DynamicBufferSequence>::type, + MatchCondition, ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + match_condition, init.handler)(asio::error_code(), 0, 1); return init.result.get(); } +#if !defined(ASIO_NO_IOSTREAM) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + char delim, ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + delim, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const std::string& delim, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + delim, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + expr, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + match_condition, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // !defined(ASIO_NO_IOSTREAM) + } // namespace asio #include "asio/detail/pop_options.hpp"
diff --git a/asio/include/asio/impl/write.hpp b/asio/include/asio/impl/write.hpp index d1ce449..da87fe9 100644 --- a/asio/include/asio/impl/write.hpp +++ b/asio/include/asio/impl/write.hpp
@@ -37,7 +37,10 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, asio::error_code& ec) + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { ec = asio::error_code(); asio::detail::consuming_buffers< @@ -57,7 +60,10 @@ } template <typename SyncWriteStream, typename ConstBufferSequence> -inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); @@ -67,7 +73,10 @@ template <typename SyncWriteStream, typename ConstBufferSequence> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - asio::error_code& ec) + asio::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { return write(s, buffers, transfer_all(), ec); } @@ -75,7 +84,10 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition) + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); @@ -83,27 +95,83 @@ return bytes_transferred; } +template <typename SyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + typename decay<DynamicBufferSequence>::type b( + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers)); + + std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBufferSequence> +inline std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + transfer_all(), ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBufferSequence> +inline std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + return write(s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + transfer_all(), ec); +} + +template <typename SyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + completion_condition, ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + #if !defined(ASIO_NO_IOSTREAM) template <typename SyncWriteStream, typename Allocator, typename CompletionCondition> -std::size_t write(SyncWriteStream& s, +inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, asio::error_code& ec) { - std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); - b.consume(bytes_transferred); - return bytes_transferred; + return write(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); } template <typename SyncWriteStream, typename Allocator> inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf<Allocator>& b) { - asio::error_code ec; - std::size_t bytes_transferred = write(s, b, transfer_all(), ec); - asio::detail::throw_error(ec, "write"); - return bytes_transferred; + return write(s, basic_streambuf_ref<Allocator>(b)); } template <typename SyncWriteStream, typename Allocator> @@ -111,7 +179,7 @@ asio::basic_streambuf<Allocator>& b, asio::error_code& ec) { - return write(s, b, transfer_all(), ec); + return write(s, basic_streambuf_ref<Allocator>(b), ec); } template <typename SyncWriteStream, typename Allocator, @@ -120,10 +188,7 @@ asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - asio::error_code ec; - std::size_t bytes_transferred = write(s, b, completion_condition, ec); - asio::detail::throw_error(ec, "write"); - return bytes_transferred; + return write(s, basic_streambuf_ref<Allocator>(b), completion_condition); } #endif // !defined(ASIO_NO_IOSTREAM) @@ -625,7 +690,10 @@ void (asio::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler) + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a WriteHandler. @@ -648,7 +716,10 @@ inline ASIO_INITFN_RESULT_TYPE(WriteHandler, void (asio::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a WriteHandler. @@ -666,82 +737,112 @@ return init.result.get(); } -#if !defined(ASIO_NO_IOSTREAM) - namespace detail { - template <typename Allocator, typename WriteHandler> - class write_streambuf_handler + template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler> + class write_dynbuf_op { public: - write_streambuf_handler(asio::basic_streambuf<Allocator>& streambuf, - WriteHandler& handler) - : streambuf_(streambuf), + template <typename BufferSequence> + write_dynbuf_op(AsyncWriteStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + completion_condition_( + ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) { } #if defined(ASIO_HAS_MOVE) - write_streambuf_handler(const write_streambuf_handler& other) - : streambuf_(other.streambuf_), + write_dynbuf_op(const write_dynbuf_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), handler_(other.handler_) { } - write_streambuf_handler(write_streambuf_handler&& other) - : streambuf_(other.streambuf_), + write_dynbuf_op(write_dynbuf_op&& other) + : stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBufferSequence)(other.buffers_)), + completion_condition_( + ASIO_MOVE_CAST(CompletionCondition)(other.completion_condition_)), handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) { } #endif // defined(ASIO_HAS_MOVE) void operator()(const asio::error_code& ec, - const std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - streambuf_.consume(bytes_transferred); - handler_(ec, bytes_transferred); + switch (start) + { + case 1: + async_write(stream_, buffers_.data(), completion_condition_, + ASIO_MOVE_CAST(write_dynbuf_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + handler_(ec, static_cast<const std::size_t&>(bytes_transferred)); + } } //private: - asio::basic_streambuf<Allocator>& streambuf_; + AsyncWriteStream& stream_; + DynamicBufferSequence buffers_; + CompletionCondition completion_condition_; WriteHandler handler_; }; - template <typename Allocator, typename WriteHandler> + template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler> inline void* asio_handler_allocate(std::size_t size, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBufferSequence, + CompletionCondition, WriteHandler>* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename Allocator, typename WriteHandler> + template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBufferSequence, + CompletionCondition, WriteHandler>* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename Allocator, typename WriteHandler> + template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBufferSequence, + CompletionCondition, WriteHandler>* this_handler) { return asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Allocator, typename WriteHandler> + template <typename Function, typename AsyncWriteStream, + typename DynamicBufferSequence, typename CompletionCondition, + typename WriteHandler> inline void asio_handler_invoke(Function& function, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBufferSequence, + CompletionCondition, WriteHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename Allocator, typename WriteHandler> + template <typename Function, typename AsyncWriteStream, + typename DynamicBufferSequence, typename CompletionCondition, + typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBufferSequence, + CompletionCondition, WriteHandler>* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); @@ -750,38 +851,103 @@ #if !defined(GENERATING_DOCUMENTATION) -template <typename Allocator, typename WriteHandler, typename Allocator1> +template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler, typename Allocator> struct associated_allocator< - detail::write_streambuf_handler<Allocator, WriteHandler>, - Allocator1> + detail::write_dynbuf_op<AsyncWriteStream, + DynamicBufferSequence, CompletionCondition, WriteHandler>, + Allocator> { - typedef typename associated_allocator<WriteHandler, Allocator1>::type type; + typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get( - const detail::write_streambuf_handler<Allocator, WriteHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + const detail::write_dynbuf_op<AsyncWriteStream, + DynamicBufferSequence, CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT { - return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a); + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; -template <typename Executor, typename WriteHandler, typename Executor1> +template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler, typename Executor> struct associated_executor< - detail::write_streambuf_handler<Executor, WriteHandler>, - Executor1> + detail::write_dynbuf_op<AsyncWriteStream, + DynamicBufferSequence, CompletionCondition, WriteHandler>, + Executor> { - typedef typename associated_executor<WriteHandler, Executor1>::type type; + typedef typename associated_executor<WriteHandler, Executor>::type type; static type get( - const detail::write_streambuf_handler<Executor, WriteHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + const detail::write_dynbuf_op<AsyncWriteStream, + DynamicBufferSequence, CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT { - return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex); + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) +template <typename AsyncWriteStream, + typename DynamicBufferSequence, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + return async_write(s, + ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type*) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::write_dynbuf_op<AsyncWriteStream, + typename decay<DynamicBufferSequence>::type, + CompletionCondition, ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBufferSequence)(buffers), + completion_condition, init.handler)( + asio::error_code(), 0, 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_IOSTREAM) + +template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_write(s, basic_streambuf_ref<Allocator>(b), + ASIO_MOVE_CAST(WriteHandler)(handler)); +} + template <typename AsyncWriteStream, typename Allocator, typename CompletionCondition, typename WriteHandler> inline ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -791,41 +957,8 @@ CompletionCondition completion_condition, ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - async_write(s, b.data(), completion_condition, - detail::write_streambuf_handler<Allocator, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - b, init.handler)); - - return init.result.get(); -} - -template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, - asio::basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(WriteHandler) handler) -{ - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - async_write(s, b.data(), transfer_all(), - detail::write_streambuf_handler<Allocator, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - b, init.handler)); - - return init.result.get(); + return async_write(s, basic_streambuf_ref<Allocator>(b), + completion_condition, ASIO_MOVE_CAST(WriteHandler)(handler)); } #endif // !defined(ASIO_NO_IOSTREAM)
diff --git a/asio/include/asio/read.hpp b/asio/include/asio/read.hpp index 12c7653..7de90cc 100644 --- a/asio/include/asio/read.hpp +++ b/asio/include/asio/read.hpp
@@ -19,6 +19,7 @@ #include <cstddef> #include "asio/async_result.hpp" #include "asio/basic_streambuf_fwd.hpp" +#include "asio/buffer.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" @@ -70,7 +71,10 @@ * asio::transfer_all()); @endcode */ template <typename SyncReadStream, typename MutableBufferSequence> -std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -110,7 +114,10 @@ */ template <typename SyncReadStream, typename MutableBufferSequence> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - asio::error_code& ec); + asio::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -161,7 +168,10 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition); + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -205,7 +215,169 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, asio::error_code& ec); + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code asio::read( + * s, buffers, + * asio::transfer_all()); @endcode + */ +template <typename SyncReadStream, typename DynamicBufferSequence> +std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code asio::read( + * s, buffers, + * asio::transfer_all(), ec); @endcode + */ +template <typename SyncReadStream, typename DynamicBufferSequence> +std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + */ +template <typename SyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template <typename SyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); #if !defined(ASIO_NO_IOSTREAM) @@ -425,7 +597,10 @@ ASIO_INITFN_RESULT_TYPE(ReadHandler, void (asio::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler); + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Start an asynchronous operation to read a certain amount of data from a /// stream. @@ -496,7 +671,141 @@ void (asio::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler); + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note This overload is equivalent to calling: + * @code asio::async_read( + * s, buffers, + * asio::transfer_all(), + * handler); @endcode + */ +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename CompletionCondition, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); #if !defined(ASIO_NO_IOSTREAM)
diff --git a/asio/include/asio/read_until.hpp b/asio/include/asio/read_until.hpp index 212b6f5..083acac 100644 --- a/asio/include/asio/read_until.hpp +++ b/asio/include/asio/read_until.hpp
@@ -17,12 +17,10 @@ #include "asio/detail/config.hpp" -#if !defined(ASIO_NO_IOSTREAM) - #include <cstddef> #include <string> #include "asio/async_result.hpp" -#include "asio/basic_streambuf.hpp" +#include "asio/basic_streambuf_fwd.hpp" #include "asio/detail/regex_fwd.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" @@ -66,11 +64,483 @@ /** * @defgroup read_until asio::read_until * - * @brief Read data into a streambuf until it contains a delimiter, matches a - * regular expression, or a function object indicates a match. + * @brief Read data into a dynamic buffer sequence, or into a streambuf, until + * it contains a delimiter, matches a regular expression, or a function object + * indicates a match. */ /*@{*/ +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @throws asio::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a newline is encountered: + * @code std::string data; + * std::string n = asio::read_until(s, + * asio::dynamic_buffer(data), '\n'); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBufferSequence> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, char delim); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBufferSequence> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + char delim, asio::error_code& ec); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = asio::read_until(s, + * asio::dynamic_buffer(data), "\r\n"); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, + typename DynamicBufferSequence, typename Allocator> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const std::basic_string<char, std::char_traits<char>, Allocator>& delim); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template <typename SyncReadStream, + typename DynamicBufferSequence, typename Allocator> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const std::basic_string<char, std::char_traits<char>, Allocator>& delim, + asio::error_code& ec); + +#if defined(ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. + * + * @throws asio::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = asio::read_until(s, + * asio::dynamic_buffer(data), boost::regex("\r\n")); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBufferSequence> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const boost::regex& expr); + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. Returns 0 + * if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBufferSequence> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const boost::regex& expr, asio::error_code& ec); + +#endif // defined(ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. + +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<typename DynamicBufferSequence::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @returns The number of bytes in the dynamic_buffer_sequence's get area that + * have been fully consumed by the match function. + * + * @throws asio::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To read data into a dynamic buffer sequence until whitespace is encountered: + * @code typedef asio::buffers_iterator< + * asio::const_buffers_1> iterator; + * + * std::pair<iterator, bool> + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * std::string data; + * asio::read_until(s, data, match_whitespace); + * @endcode + * + * To read data into a @c std::string until a matching character is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template <typename Iterator> + * std::pair<Iterator, bool> operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition<match_char> + * : public boost::true_type {}; + * } // namespace asio + * ... + * std::string data; + * asio::read_until(s, data, match_char('a')); + * @endcode + */ +template <typename SyncReadStream, + typename DynamicBufferSequence, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + MatchCondition match_condition, + typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<DynamicBufferSequence::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area that + * have been fully consumed by the match function. Returns 0 if an error + * occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + */ +template <typename SyncReadStream, + typename DynamicBufferSequence, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + MatchCondition match_condition, asio::error_code& ec, + typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + +#if !defined(ASIO_NO_IOSTREAM) + /// Read data into a streambuf until it contains a specified delimiter. /** * This function is used to read data into the specified streambuf until the @@ -386,7 +856,8 @@ * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the function object. An application - * will typically leave that data in the streambuf for a subsequent + * will typically leave that data in the streambuf for a subsequent read_until + * operation to examine. * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a @@ -490,7 +961,8 @@ * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the function object. An application - * will typically leave that data in the streambuf for a subsequent + * will typically leave that data in the streambuf for a subsequent read_until + * operation to examine. * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a @@ -503,16 +975,438 @@ MatchCondition match_condition, asio::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); +#endif // !defined(ASIO_NO_IOSTREAM) + /*@}*/ /** * @defgroup async_read_until asio::async_read_until * - * @brief Start an asynchronous operation to read data into a streambuf until it - * contains a delimiter, matches a regular expression, or a function object - * indicates a match. + * @brief Start an asynchronous operation to read data into a dynamic buffer + * sequence, or into a streambuf, until it contains a delimiter, matches a + * regular expression, or a function object indicates a match. */ /*@{*/ +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter character. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a newline is + * encountered: + * @code std::string data; + * ... + * void handler(const asio::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * ... + * } + * } + * ... + * asio::async_read_until(s, data, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + char delim, ASIO_MOVE_ARG(ReadHandler) handler); + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter string. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const asio::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * asio::async_read_until(s, data, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const std::string& delim, + ASIO_MOVE_ARG(ReadHandler) handler); + +#if defined(ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until some part of its data matches a regular expression. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains some + * data that matches a regular expression. The function call always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the regular + * expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains data that matches + * the regular expression, this asynchronous operation completes immediately. + * The program must ensure that the stream performs no other read operations + * (such as async_read, async_read_until, the stream's async_read_some + * function, or any other composed operations that perform reads) until this + * operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param expr The regular expression. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer + * // sequence's get area up to and including the + * // substring that matches the regular expression. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const asio::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * asio::async_read_until(s, data, + * boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the match, + * so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template <typename AsyncReadStream, + typename DynamicBufferSequence, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + const boost::regex& expr, + ASIO_MOVE_ARG(ReadHandler) handler); + +#endif // defined(ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until a function object indicates a match. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until a user-defined match condition function object, when + * applied to the data contained in the dynamic buffer sequence, indicates a + * successful match. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<typename DynamicBufferSequence::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area that have been fully consumed by the match + * // function. O if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the function + * object. An application will typically leave that data in the dynamic buffer + * sequence for a subsequent async_read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To asynchronously read data into a @c std::string until whitespace is + * encountered: + * @code typedef asio::buffers_iterator< + * asio::const_buffers_1> iterator; + * + * std::pair<iterator, bool> + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * void handler(const asio::error_code& e, std::size_t size); + * ... + * std::string data; + * asio::async_read_until(s, data, match_whitespace, handler); + * @endcode + * + * To asynchronously read data into a @c std::string until a matching character + * is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template <typename Iterator> + * std::pair<Iterator, bool> operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition<match_char> + * : public boost::true_type {}; + * } // namespace asio + * ... + * void handler(const asio::error_code& e, std::size_t size); + * ... + * std::string data; + * asio::async_read_until(s, data, match_char('a'), handler); + * @endcode + */ +template <typename AsyncReadStream, typename DynamicBufferSequence, + typename MatchCondition, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + +#if !defined(ASIO_NO_IOSTREAM) + /// Start an asynchronous operation to read data into a streambuf until it /// contains a specified delimiter. /** @@ -910,6 +1804,8 @@ MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); +#endif // !defined(ASIO_NO_IOSTREAM) + /*@}*/ } // namespace asio @@ -918,6 +1814,4 @@ #include "asio/impl/read_until.hpp" -#endif // !defined(ASIO_NO_IOSTREAM) - #endif // ASIO_READ_UNTIL_HPP
diff --git a/asio/include/asio/write.hpp b/asio/include/asio/write.hpp index 6799179..968c550 100644 --- a/asio/include/asio/write.hpp +++ b/asio/include/asio/write.hpp
@@ -19,6 +19,7 @@ #include <cstddef> #include "asio/async_result.hpp" #include "asio/basic_streambuf_fwd.hpp" +#include "asio/buffer.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" @@ -69,7 +70,10 @@ * asio::transfer_all()); @endcode */ template <typename SyncWriteStream, typename ConstBufferSequence> -std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Write all of the supplied data to a stream before returning. /** @@ -109,7 +113,10 @@ */ template <typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - asio::error_code& ec); + asio::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Write a certain amount of data to a stream before returning. /** @@ -160,7 +167,10 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition); + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Write a certain amount of data to a stream before returning. /** @@ -204,7 +214,170 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, asio::error_code& ec); + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code asio::write( + * s, buffers, + * asio::transfer_all()); @endcode + */ +template <typename SyncWriteStream, typename DynamicBufferSequence> +std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code asio::write( + * s, buffers, + * asio::transfer_all(), ec); @endcode + */ +template <typename SyncWriteStream, typename DynamicBufferSequence> +std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + */ +template <typename SyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template <typename SyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); #if !defined(ASIO_NO_IOSTREAM) @@ -416,7 +589,10 @@ ASIO_INITFN_RESULT_TYPE(WriteHandler, void (asio::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler); + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Start an asynchronous operation to write a certain amount of data to a /// stream. @@ -491,7 +667,133 @@ void (asio::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler); + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ +template <typename AsyncWriteStream, + typename DynamicBufferSequence, typename WriteHandler> +ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation of + * the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ +template <typename AsyncWriteStream, typename DynamicBufferSequence, + typename CompletionCondition, typename WriteHandler> +ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBufferSequence) buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_sequence<DynamicBufferSequence>::value + >::type* = 0); #if !defined(ASIO_NO_IOSTREAM)
diff --git a/asio/src/tests/unit/buffer.cpp b/asio/src/tests/unit/buffer.cpp index 0ba4317..44d7779 100644 --- a/asio/src/tests/unit/buffer.cpp +++ b/asio/src/tests/unit/buffer.cpp
@@ -232,6 +232,21 @@ std::size_t size36 = buffer_copy( mutable_buffer_sequence, const_buffer_sequence, 128); (void)size36; + + // dynamic_buffer function overloads. + + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> db1 = dynamic_buffer(string_data); + (void)db1; + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> db2 = dynamic_buffer(string_data, 1024); + (void)db2; + dynamic_vector_buffer<char, std::allocator<char> > + db3 = dynamic_buffer(vector_data); + (void)db3; + dynamic_vector_buffer<char, std::allocator<char> > + db4 = dynamic_buffer(vector_data, 1024); + (void)db4; } catch (std::exception&) {