summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/fiber/examples/adapt_method_calls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/fiber/examples/adapt_method_calls.cpp')
-rw-r--r--src/boost/libs/fiber/examples/adapt_method_calls.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/boost/libs/fiber/examples/adapt_method_calls.cpp b/src/boost/libs/fiber/examples/adapt_method_calls.cpp
new file mode 100644
index 00000000..7cfd78df
--- /dev/null
+++ b/src/boost/libs/fiber/examples/adapt_method_calls.cpp
@@ -0,0 +1,167 @@
+// Copyright Nat Goodspeed 2015.
+// 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 <boost/fiber/all.hpp>
+#include <memory> // std::shared_ptr
+#include <thread>
+#include <chrono>
+#include <iostream>
+#include <sstream>
+#include <exception>
+#include <cassert>
+
+/*****************************************************************************
+* example async API
+*****************************************************************************/
+// introduce class-scope typedef
+struct AsyncAPIBase {
+ // error callback accepts an int error code; 0 == success
+ typedef int errorcode;
+};
+
+//[Response
+// every async operation receives a subclass instance of this abstract base
+// class through which to communicate its result
+struct Response {
+ typedef std::shared_ptr< Response > ptr;
+
+ // called if the operation succeeds
+ virtual void success( std::string const& data) = 0;
+
+ // called if the operation fails
+ virtual void error( AsyncAPIBase::errorcode ec) = 0;
+};
+//]
+
+// the actual async API
+class AsyncAPI: public AsyncAPIBase {
+public:
+ // constructor acquires some resource that can be read
+ AsyncAPI( std::string const& data);
+
+//[method_init_read
+ // derive Response subclass, instantiate, pass Response::ptr
+ void init_read( Response::ptr);
+//]
+
+ // ... other operations ...
+ void inject_error( errorcode ec);
+
+private:
+ std::string data_;
+ errorcode injected_;
+};
+
+/*****************************************************************************
+* fake AsyncAPI implementation... pay no attention to the little man behind
+* the curtain...
+*****************************************************************************/
+AsyncAPI::AsyncAPI( std::string const& data) :
+ data_( data),
+ injected_( 0) {
+}
+
+void AsyncAPI::inject_error( errorcode ec) {
+ injected_ = ec;
+}
+
+void AsyncAPI::init_read( Response::ptr response) {
+ // make a local copy of injected_
+ errorcode injected( injected_);
+ // reset it synchronously with caller
+ injected_ = 0;
+ // local copy of data_ so we can capture in lambda
+ std::string data( data_);
+ // Simulate an asynchronous I/O operation by launching a detached thread
+ // that sleeps a bit before calling either completion method.
+ std::thread( [injected, response, data](){
+ std::this_thread::sleep_for( std::chrono::milliseconds(100) );
+ if ( ! injected) {
+ // no error, call success()
+ response->success( data);
+ } else {
+ // injected error, call error()
+ response->error( injected);
+ }
+ }).detach();
+}
+
+/*****************************************************************************
+* adapters
+*****************************************************************************/
+// helper function
+std::runtime_error make_exception( std::string const& desc, AsyncAPI::errorcode);
+
+//[PromiseResponse
+class PromiseResponse: public Response {
+public:
+ // called if the operation succeeds
+ virtual void success( std::string const& data) {
+ promise_.set_value( data);
+ }
+
+ // called if the operation fails
+ virtual void error( AsyncAPIBase::errorcode ec) {
+ promise_.set_exception(
+ std::make_exception_ptr(
+ make_exception("read", ec) ) );
+ }
+
+ boost::fibers::future< std::string > get_future() {
+ return promise_.get_future();
+ }
+
+private:
+ boost::fibers::promise< std::string > promise_;
+};
+//]
+
+//[method_read
+std::string read( AsyncAPI & api) {
+ // Because init_read() requires a shared_ptr, we must allocate our
+ // ResponsePromise on the heap, even though we know its lifespan.
+ auto promisep( std::make_shared< PromiseResponse >() );
+ boost::fibers::future< std::string > future( promisep->get_future() );
+ // Both 'promisep' and 'future' will survive until our lambda has been
+ // called.
+ api.init_read( promisep);
+ return future.get();
+}
+//]
+
+/*****************************************************************************
+* helpers
+*****************************************************************************/
+std::runtime_error make_exception( std::string const& desc, AsyncAPI::errorcode ec) {
+ std::ostringstream buffer;
+ buffer << "Error in AsyncAPI::" << desc << "(): " << ec;
+ return std::runtime_error( buffer.str() );
+}
+
+/*****************************************************************************
+* driving logic
+*****************************************************************************/
+int main(int argc, char *argv[]) {
+ // prime AsyncAPI with some data
+ AsyncAPI api("abcd");
+
+ // successful read(): retrieve it
+ std::string data( read( api) );
+ assert(data == "abcd");
+
+ // read() with error
+ std::string thrown;
+ api.inject_error(1);
+ try {
+ data = read( api);
+ } catch ( std::exception const& e) {
+ thrown = e.what();
+ }
+ assert(thrown == make_exception("read", 1).what() );
+
+ std::cout << "done." << std::endl;
+
+ return EXIT_SUCCESS;
+}