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&)
{