Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r84346 - in trunk: boost boost/asio libs/asio/doc libs/asio/example/cpp03/http/server4 libs/asio/test
From: chris_at_[hidden]
Date: 2013-05-18 07:55:01


Author: chris_kohlhoff
Date: 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
New Revision: 84346
URL: http://svn.boost.org/trac/boost/changeset/84346

Log:
Remove the stackless coroutine class and macros from the HTTP server 4
example, and instead make them a part of Asio's documented interface.

Added:
   trunk/boost/asio/coroutine.hpp (contents, props changed)
   trunk/boost/asio/unyield.hpp (contents, props changed)
   trunk/boost/asio/yield.hpp (contents, props changed)
   trunk/libs/asio/test/coroutine.cpp (contents, props changed)
Removed:
   trunk/libs/asio/example/cpp03/http/server4/coroutine.hpp
   trunk/libs/asio/example/cpp03/http/server4/unyield.hpp
   trunk/libs/asio/example/cpp03/http/server4/yield.hpp
Text files modified:
   trunk/boost/asio.hpp | 1 +
   trunk/libs/asio/doc/examples.qbk | 3 ---
   trunk/libs/asio/doc/reference.xsl | 5 ++++-
   trunk/libs/asio/example/cpp03/http/server4/request_parser.cpp | 6 ++++--
   trunk/libs/asio/example/cpp03/http/server4/request_parser.hpp | 4 ++--
   trunk/libs/asio/example/cpp03/http/server4/server.cpp | 6 ++++--
   trunk/libs/asio/example/cpp03/http/server4/server.hpp | 3 +--
   trunk/libs/asio/test/Jamfile | 1 +
   trunk/libs/asio/test/Jamfile.v2 | 2 ++
   9 files changed, 19 insertions(+), 12 deletions(-)

Modified: trunk/boost/asio.hpp
==============================================================================
--- trunk/boost/asio.hpp (original)
+++ trunk/boost/asio.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -41,6 +41,7 @@
 #include <boost/asio/buffers_iterator.hpp>
 #include <boost/asio/completion_condition.hpp>
 #include <boost/asio/connect.hpp>
+#include <boost/asio/coroutine.hpp>
 #include <boost/asio/datagram_socket_service.hpp>
 #include <boost/asio/deadline_timer_service.hpp>
 #include <boost/asio/deadline_timer.hpp>

Added: trunk/boost/asio/coroutine.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/coroutine.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -0,0 +1,330 @@
+//
+// coroutine.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_COROUTINE_HPP
+#define BOOST_ASIO_COROUTINE_HPP
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class coroutine_ref;
+
+} // namespace detail
+
+/// Provides support for implementing stackless coroutines.
+/**
+ * The @c coroutine class may be used to implement stackless coroutines. The
+ * class itself is used to store the current state of the coroutine.
+ *
+ * Coroutines are copy-constructible and assignable, and the space overhead is
+ * a single int. They can be used as a base class:
+ *
+ * @code class session : coroutine
+ * {
+ * ...
+ * }; @endcode
+ *
+ * or as a data member:
+ *
+ * @code class session
+ * {
+ * ...
+ * coroutine coro_;
+ * }; @endcode
+ *
+ * or even bound in as a function argument using lambdas or @c bind(). The
+ * important thing is that as the application maintains a copy of the object
+ * for as long as the coroutine must be kept alive.
+ *
+ * @par Pseudo-keywords
+ *
+ * A coroutine is used in conjunction with certain "pseudo-keywords", which
+ * are implemented as macros. These macros are defined by a header file:
+ *
+ * @code #include <boost/asio/yield.hpp>@endcode
+ *
+ * and may conversely be undefined as follows:
+ *
+ * @code #include <boost/asio/unyield.hpp>@endcode
+ *
+ * <b>reenter</b>
+ *
+ * The @c reenter macro is used to define the body of a coroutine. It takes a
+ * single argument: a pointer or reference to a coroutine object. For example,
+ * if the base class is a coroutine object you may write:
+ *
+ * @code reenter (this)
+ * {
+ * ... coroutine body ...
+ * } @endcode
+ *
+ * and if a data member or other variable you can write:
+ *
+ * @code reenter (coro_)
+ * {
+ * ... coroutine body ...
+ * } @endcode
+ *
+ * When @c reenter is executed at runtime, control jumps to the location of the
+ * last @c yield or @c fork.
+ *
+ * The coroutine body may also be a single statement, such as:
+ *
+ * @code reenter (this) for (;;)
+ * {
+ * ...
+ * } @endcode
+ *
+ * @b Limitation: The @c reenter macro is implemented using a switch. This
+ * means that you must take care when using local variables within the
+ * coroutine body. The local variable is not allowed in a position where
+ * reentering the coroutine could bypass the variable definition.
+ *
+ * <b>yield <em>statement</em></b>
+ *
+ * This form of the @c yield keyword is often used with asynchronous operations:
+ *
+ * @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode
+ *
+ * This divides into four logical steps:
+ *
+ * @li @c yield saves the current state of the coroutine.
+ * @li The statement initiates the asynchronous operation.
+ * @li The resume point is defined immediately following the statement.
+ * @li Control is transferred to the end of the coroutine body.
+ *
+ * When the asynchronous operation completes, the function object is invoked
+ * and @c reenter causes control to transfer to the resume point. It is
+ * important to remember to carry the coroutine state forward with the
+ * asynchronous operation. In the above snippet, the current class is a
+ * function object object with a coroutine object as base class or data member.
+ *
+ * The statement may also be a compound statement, and this permits us to
+ * define local variables with limited scope:
+ *
+ * @code yield
+ * {
+ * mutable_buffers_1 b = buffer(*buffer_);
+ * socket_->async_read_some(b, *this);
+ * } @endcode
+ *
+ * <b>yield return <em>expression</em> ;</b>
+ *
+ * This form of @c yield is often used in generators or coroutine-based parsers.
+ * For example, the function object:
+ *
+ * @code struct interleave : coroutine
+ * {
+ * istream& is1;
+ * istream& is2;
+ * char operator()(char c)
+ * {
+ * reenter (this) for (;;)
+ * {
+ * yield return is1.get();
+ * yield return is2.get();
+ * }
+ * }
+ * }; @endcode
+ *
+ * defines a trivial coroutine that interleaves the characters from two input
+ * streams.
+ *
+ * This type of @c yield divides into three logical steps:
+ *
+ * @li @c yield saves the current state of the coroutine.
+ * @li The resume point is defined immediately following the semicolon.
+ * @li The value of the expression is returned from the function.
+ *
+ * <b>yield ;</b>
+ *
+ * This form of @c yield is equivalent to the following steps:
+ *
+ * @li @c yield saves the current state of the coroutine.
+ * @li The resume point is defined immediately following the semicolon.
+ * @li Control is transferred to the end of the coroutine body.
+ *
+ * This form might be applied when coroutines are used for cooperative
+ * threading and scheduling is explicitly managed. For example:
+ *
+ * @code struct task : coroutine
+ * {
+ * ...
+ * void operator()()
+ * {
+ * reenter (this)
+ * {
+ * while (... not finished ...)
+ * {
+ * ... do something ...
+ * yield;
+ * ... do some more ...
+ * yield;
+ * }
+ * }
+ * }
+ * ...
+ * };
+ * ...
+ * task t1, t2;
+ * for (;;)
+ * {
+ * t1();
+ * t2();
+ * } @endcode
+ *
+ * <b>yield break ;</b>
+ *
+ * The final form of @c yield is used to explicitly terminate the coroutine.
+ * This form is comprised of two steps:
+ *
+ * @li @c yield sets the coroutine state to indicate termination.
+ * @li Control is transferred to the end of the coroutine body.
+ *
+ * Once terminated, calls to is_complete() return true and the coroutine cannot
+ * be reentered.
+ *
+ * Note that a coroutine may also be implicitly terminated if the coroutine
+ * body is exited without a yield, e.g. by return, throw or by running to the
+ * end of the body.
+ *
+ * <b>fork <em>statement</em></b>
+ *
+ * The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting
+ * it into two (or more) copies. One use of @c fork is in a server, where a new
+ * coroutine is created to handle each client connection:
+ *
+ * @code reenter (this)
+ * {
+ * do
+ * {
+ * socket_.reset(new tcp::socket(io_service_));
+ * yield acceptor->async_accept(*socket_, *this);
+ * fork server(*this)();
+ * } while (is_parent());
+ * ... client-specific handling follows ...
+ * } @endcode
+ *
+ * The logical steps involved in a @c fork are:
+ *
+ * @li @c fork saves the current state of the coroutine.
+ * @li The statement creates a copy of the coroutine and either executes it
+ * immediately or schedules it for later execution.
+ * @li The resume point is defined immediately following the semicolon.
+ * @li For the "parent", control immediately continues from the next line.
+ *
+ * The functions is_parent() and is_child() can be used to differentiate
+ * between parent and child. You would use these functions to alter subsequent
+ * control flow.
+ *
+ * Note that @c fork doesn't do the actual forking by itself. It is the
+ * application's responsibility to create a clone of the coroutine and call it.
+ * The clone can be called immediately, as above, or scheduled for delayed
+ * execution using something like io_service::post().
+ *
+ * @par Alternate macro names
+ *
+ * If preferred, an application can use macro names that follow a more typical
+ * naming convention, rather than the pseudo-keywords. These are:
+ *
+ * @li @c BOOST_ASIO_CORO_REENTER instead of @c reenter
+ * @li @c BOOST_ASIO_CORO_YIELD instead of @c yield
+ * @li @c BOOST_ASIO_CORO_FORK instead of @c fork
+ */
+class coroutine
+{
+public:
+ /// Constructs a coroutine in its initial state.
+ coroutine() : value_(0) {}
+
+ /// Returns true if the coroutine is the child of a fork.
+ bool is_child() const { return value_ < 0; }
+
+ /// Returns true if the coroutine is the parent of a fork.
+ bool is_parent() const { return !is_child(); }
+
+ /// Returns true if the coroutine has reached its terminal state.
+ bool is_complete() const { return value_ == -1; }
+
+private:
+ friend class detail::coroutine_ref;
+ int value_;
+};
+
+
+namespace detail {
+
+class coroutine_ref
+{
+public:
+ coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
+ coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
+ ~coroutine_ref() { if (!modified_) value_ = -1; }
+ operator int() const { return value_; }
+ int& operator=(int v) { modified_ = true; return value_ = v; }
+private:
+ void operator=(const coroutine_ref&);
+ int& value_;
+ bool modified_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#define BOOST_ASIO_CORO_REENTER(c) \
+ switch (::boost::asio::detail::coroutine_ref _coro_value = c) \
+ case -1: if (_coro_value) \
+ { \
+ goto terminate_coroutine; \
+ terminate_coroutine: \
+ _coro_value = -1; \
+ goto bail_out_of_coroutine; \
+ bail_out_of_coroutine: \
+ break; \
+ } \
+ else case 0:
+
+#define BOOST_ASIO_CORO_YIELD_IMPL(n) \
+ for (_coro_value = (n);;) \
+ if (_coro_value == 0) \
+ { \
+ case (n): ; \
+ break; \
+ } \
+ else \
+ switch (_coro_value ? 0 : 1) \
+ for (;;) \
+ case -1: if (_coro_value) \
+ goto terminate_coroutine; \
+ else for (;;) \
+ case 1: if (_coro_value) \
+ goto bail_out_of_coroutine; \
+ else case 0:
+
+#define BOOST_ASIO_CORO_FORK_IMPL(n) \
+ for (_coro_value = -(n);; _coro_value = (n)) \
+ if (_coro_value == (n)) \
+ { \
+ case -(n): ; \
+ break; \
+ } \
+ else
+
+#if defined(_MSC_VER)
+# define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)
+# define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)
+#else // defined(_MSC_VER)
+# define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__LINE__)
+# define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__LINE__)
+#endif // defined(_MSC_VER)
+
+#endif // BOOST_ASIO_COROUTINE_HPP

Added: trunk/boost/asio/unyield.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/unyield.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -0,0 +1,21 @@
+//
+// unyield.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifdef reenter
+# undef reenter
+#endif
+
+#ifdef yield
+# undef yield
+#endif
+
+#ifdef fork
+# undef fork
+#endif

Added: trunk/boost/asio/yield.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/yield.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -0,0 +1,23 @@
+//
+// yield.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "coroutine.hpp"
+
+#ifndef reenter
+# define reenter(c) BOOST_ASIO_CORO_REENTER(c)
+#endif
+
+#ifndef yield
+# define yield BOOST_ASIO_CORO_YIELD
+#endif
+
+#ifndef fork
+# define fork BOOST_ASIO_CORO_FORK
+#endif

Modified: trunk/libs/asio/doc/examples.qbk
==============================================================================
--- trunk/libs/asio/doc/examples.qbk (original)
+++ trunk/libs/asio/doc/examples.qbk 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -162,7 +162,6 @@
 
 A single-threaded HTTP server implemented using stackless coroutines.
 
-* [@boost_asio/example/cpp03/http/server4/coroutine.hpp]
 * [@boost_asio/example/cpp03/http/server4/file_handler.cpp]
 * [@boost_asio/example/cpp03/http/server4/file_handler.hpp]
 * [@boost_asio/example/cpp03/http/server4/header.hpp]
@@ -176,8 +175,6 @@
 * [@boost_asio/example/cpp03/http/server4/request_parser.hpp]
 * [@boost_asio/example/cpp03/http/server4/server.cpp]
 * [@boost_asio/example/cpp03/http/server4/server.hpp]
-* [@boost_asio/example/cpp03/http/server4/unyield.hpp]
-* [@boost_asio/example/cpp03/http/server4/yield.hpp]
 
 
 [heading ICMP]

Modified: trunk/libs/asio/doc/reference.xsl
==============================================================================
--- trunk/libs/asio/doc/reference.xsl (original)
+++ trunk/libs/asio/doc/reference.xsl 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -424,7 +424,10 @@
 </xsl:template>
 
 
-<xsl:template match="emphasis" mode="markup">[*<xsl:value-of select="."/>]</xsl:template>
+<xsl:template match="bold" mode="markup">[*<xsl:apply-templates mode="markup"/>]</xsl:template>
+
+
+<xsl:template match="emphasis" mode="markup">['<xsl:apply-templates mode="markup"/>]</xsl:template>
 
 
 <xsl:template match="parameterlist" mode="markup">

Deleted: trunk/libs/asio/example/cpp03/http/server4/coroutine.hpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/coroutine.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
+++ (empty file)
@@ -1,87 +0,0 @@
-//
-// coroutine.hpp
-// ~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef COROUTINE_HPP
-#define COROUTINE_HPP
-
-class coroutine
-{
-public:
- coroutine() : value_(0) {}
- bool is_child() const { return value_ < 0; }
- bool is_parent() const { return !is_child(); }
- bool is_complete() const { return value_ == -1; }
-private:
- friend class coroutine_ref;
- int value_;
-};
-
-class coroutine_ref
-{
-public:
- coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
- coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
- ~coroutine_ref() { if (!modified_) value_ = -1; }
- operator int() const { return value_; }
- int& operator=(int v) { modified_ = true; return value_ = v; }
-private:
- void operator=(const coroutine_ref&);
- int& value_;
- bool modified_;
-};
-
-#define CORO_REENTER(c) \
- switch (coroutine_ref _coro_value = c) \
- case -1: if (_coro_value) \
- { \
- goto terminate_coroutine; \
- terminate_coroutine: \
- _coro_value = -1; \
- goto bail_out_of_coroutine; \
- bail_out_of_coroutine: \
- break; \
- } \
- else case 0:
-
-#define CORO_YIELD_IMPL(n) \
- for (_coro_value = (n);;) \
- if (_coro_value == 0) \
- { \
- case (n): ; \
- break; \
- } \
- else \
- switch (_coro_value ? 0 : 1) \
- for (;;) \
- case -1: if (_coro_value) \
- goto terminate_coroutine; \
- else for (;;) \
- case 1: if (_coro_value) \
- goto bail_out_of_coroutine; \
- else case 0:
-
-#define CORO_FORK_IMPL(n) \
- for (_coro_value = -(n);; _coro_value = (n)) \
- if (_coro_value == (n)) \
- { \
- case -(n): ; \
- break; \
- } \
- else
-
-#if defined(_MSC_VER)
-# define CORO_YIELD CORO_YIELD_IMPL(__COUNTER__ + 1)
-# define CORO_FORK CORO_FORK_IMPL(__COUNTER__ + 1)
-#else // defined(_MSC_VER)
-# define CORO_YIELD CORO_YIELD_IMPL(__LINE__)
-# define CORO_FORK CORO_FORK_IMPL(__LINE__)
-#endif // defined(_MSC_VER)
-
-#endif // COROUTINE_HPP

Modified: trunk/libs/asio/example/cpp03/http/server4/request_parser.cpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/request_parser.cpp (original)
+++ trunk/libs/asio/example/cpp03/http/server4/request_parser.cpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -17,7 +17,8 @@
 namespace http {
 namespace server4 {
 
-#include "yield.hpp" // Enable the pseudo-keywords reenter, yield and fork.
+// Enable the pseudo-keywords reenter, yield and fork.
+#include <boost/asio/yield.hpp>
 
 std::string request_parser::content_length_name_ = "Content-Length";
 
@@ -175,7 +176,8 @@
   return true;
 }
 
-#include "unyield.hpp" // Disable the pseudo-keywords reenter, yield and fork.
+// Disable the pseudo-keywords reenter, yield and fork.
+#include <boost/asio/unyield.hpp>
 
 bool request_parser::is_char(int c)
 {

Modified: trunk/libs/asio/example/cpp03/http/server4/request_parser.hpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/request_parser.hpp (original)
+++ trunk/libs/asio/example/cpp03/http/server4/request_parser.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -14,7 +14,7 @@
 #include <string>
 #include <boost/logic/tribool.hpp>
 #include <boost/tuple/tuple.hpp>
-#include "coroutine.hpp"
+#include <boost/asio/coroutine.hpp>
 
 namespace http {
 namespace server4 {
@@ -22,7 +22,7 @@
 struct request;
 
 /// Parser for incoming requests.
-class request_parser : coroutine
+class request_parser : boost::asio::coroutine
 {
 public:
   /// Parse some data. The tribool return value is true when a complete request

Modified: trunk/libs/asio/example/cpp03/http/server4/server.cpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/server.cpp (original)
+++ trunk/libs/asio/example/cpp03/http/server4/server.cpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -25,7 +25,8 @@
   acceptor_.reset(new tcp::acceptor(io_service, *resolver.resolve(query)));
 }
 
-#include "yield.hpp" // Enable the pseudo-keywords reenter, yield and fork.
+// Enable the pseudo-keywords reenter, yield and fork.
+#include <boost/asio/yield.hpp>
 
 void server::operator()(boost::system::error_code ec, std::size_t length)
 {
@@ -113,7 +114,8 @@
   // will be destroyed automatically after this function call returns.
 }
 
-#include "unyield.hpp" // Disable the pseudo-keywords reenter, yield and fork.
+// Disable the pseudo-keywords reenter, yield and fork.
+#include <boost/asio/unyield.hpp>
 
 } // namespace server4
 } // namespace http

Modified: trunk/libs/asio/example/cpp03/http/server4/server.hpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/server.hpp (original)
+++ trunk/libs/asio/example/cpp03/http/server4/server.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -16,7 +16,6 @@
 #include <boost/array.hpp>
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
-#include "coroutine.hpp"
 #include "request_parser.hpp"
 
 namespace http {
@@ -26,7 +25,7 @@
 struct reply;
 
 /// The top-level coroutine of the HTTP server.
-class server : coroutine
+class server : boost::asio::coroutine
 {
 public:
   /// Construct the server to listen on the specified TCP address and port, and

Deleted: trunk/libs/asio/example/cpp03/http/server4/unyield.hpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/unyield.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
+++ (empty file)
@@ -1,21 +0,0 @@
-//
-// unyield.hpp
-// ~~~~~~~~~~~
-//
-// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifdef reenter
-# undef reenter
-#endif
-
-#ifdef yield
-# undef yield
-#endif
-
-#ifdef fork
-# undef fork
-#endif

Deleted: trunk/libs/asio/example/cpp03/http/server4/yield.hpp
==============================================================================
--- trunk/libs/asio/example/cpp03/http/server4/yield.hpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
+++ (empty file)
@@ -1,23 +0,0 @@
-//
-// yield.hpp
-// ~~~~~~~~~
-//
-// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#include "coroutine.hpp"
-
-#ifndef reenter
-# define reenter(c) CORO_REENTER(c)
-#endif
-
-#ifndef yield
-# define yield CORO_YIELD
-#endif
-
-#ifndef fork
-# define fork CORO_FORK
-#endif

Modified: trunk/libs/asio/test/Jamfile
==============================================================================
--- trunk/libs/asio/test/Jamfile (original)
+++ trunk/libs/asio/test/Jamfile 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -54,6 +54,7 @@
   [ run buffers_iterator.cpp <template>asio_unit_test ]
   [ run completion_condition.cpp <template>asio_unit_test ]
   [ run connect.cpp <template>asio_unit_test ]
+ [ run coroutine.cpp <template>asio_unit_test ]
   [ run datagram_socket_service.cpp <template>asio_unit_test ]
   [ run deadline_timer_service.cpp <template>asio_unit_test ]
   [ run deadline_timer.cpp <template>asio_unit_test ]

Modified: trunk/libs/asio/test/Jamfile.v2
==============================================================================
--- trunk/libs/asio/test/Jamfile.v2 (original)
+++ trunk/libs/asio/test/Jamfile.v2 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -93,6 +93,8 @@
   [ link completion_condition.cpp : $(USE_SELECT) : completion_condition_select ]
   [ link connect.cpp ]
   [ link connect.cpp : $(USE_SELECT) : connect_select ]
+ [ link coroutine.cpp ]
+ [ link coroutine.cpp : $(USE_SELECT) : coroutine_select ]
   [ link datagram_socket_service.cpp ]
   [ link datagram_socket_service.cpp : $(USE_SELECT) : datagram_socket_service_select ]
   [ link deadline_timer_service.cpp ]

Added: trunk/libs/asio/test/coroutine.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/coroutine.cpp 2013-05-18 07:54:59 EDT (Sat, 18 May 2013)
@@ -0,0 +1,112 @@
+//
+// coroutine.cpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/coroutine.hpp>
+
+#include "unit_test.hpp"
+
+// Must come after all other headers.
+#include <boost/asio/yield.hpp>
+
+//------------------------------------------------------------------------------
+
+// Coroutine completes via yield break.
+
+void yield_break_coro(boost::asio::coroutine& coro)
+{
+ reenter (coro)
+ {
+ yield return;
+ yield break;
+ }
+}
+
+void yield_break_test()
+{
+ boost::asio::coroutine coro;
+ BOOST_ASIO_CHECK(!coro.is_complete());
+ yield_break_coro(coro);
+ BOOST_ASIO_CHECK(!coro.is_complete());
+ yield_break_coro(coro);
+ BOOST_ASIO_CHECK(coro.is_complete());
+}
+
+//------------------------------------------------------------------------------
+
+// Coroutine completes via return.
+
+void return_coro(boost::asio::coroutine& coro)
+{
+ reenter (coro)
+ {
+ return;
+ }
+}
+
+void return_test()
+{
+ boost::asio::coroutine coro;
+ return_coro(coro);
+ BOOST_ASIO_CHECK(coro.is_complete());
+}
+
+//------------------------------------------------------------------------------
+
+// Coroutine completes via exception.
+
+void exception_coro(boost::asio::coroutine& coro)
+{
+ reenter (coro)
+ {
+ throw 1;
+ }
+}
+
+void exception_test()
+{
+ boost::asio::coroutine coro;
+ try { exception_coro(coro); } catch (int) {}
+ BOOST_ASIO_CHECK(coro.is_complete());
+}
+
+//------------------------------------------------------------------------------
+
+// Coroutine completes by falling off the end.
+
+void fall_off_end_coro(boost::asio::coroutine& coro)
+{
+ reenter (coro)
+ {
+ }
+}
+
+void fall_off_end_test()
+{
+ boost::asio::coroutine coro;
+ fall_off_end_coro(coro);
+ BOOST_ASIO_CHECK(coro.is_complete());
+}
+
+//------------------------------------------------------------------------------
+
+BOOST_ASIO_TEST_SUITE
+(
+ "coroutine",
+ BOOST_ASIO_TEST_CASE(yield_break_test)
+ BOOST_ASIO_TEST_CASE(return_test)
+ BOOST_ASIO_TEST_CASE(exception_test)
+ BOOST_ASIO_TEST_CASE(fall_off_end_test)
+)


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk