summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/coroutine2
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/coroutine2')
-rw-r--r--src/boost/libs/coroutine2/README.md14
-rw-r--r--src/boost/libs/coroutine2/example/Jamfile.v245
-rw-r--r--src/boost/libs/coroutine2/example/fibonacci.cpp30
-rw-r--r--src/boost/libs/coroutine2/example/layout.cpp50
-rw-r--r--src/boost/libs/coroutine2/example/parser.cpp122
-rw-r--r--src/boost/libs/coroutine2/example/same_fringe.cpp172
-rw-r--r--src/boost/libs/coroutine2/example/segmented.cpp48
-rw-r--r--src/boost/libs/coroutine2/example/tree.h97
-rw-r--r--src/boost/libs/coroutine2/index.html14
-rw-r--r--src/boost/libs/coroutine2/meta/libraries.json14
-rw-r--r--src/boost/libs/coroutine2/performance/Jamfile.v267
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor.hpp12
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor_aix.cpp25
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor_freebsd.cpp29
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor_hpux.cpp31
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor_linux.cpp30
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor_solaris.cpp26
-rw-r--r--src/boost/libs/coroutine2/performance/bind_processor_windows.cpp24
-rw-r--r--src/boost/libs/coroutine2/performance/clock.hpp45
-rw-r--r--src/boost/libs/coroutine2/performance/cycle.hpp26
-rw-r--r--src/boost/libs/coroutine2/performance/cycle_i386.hpp83
-rw-r--r--src/boost/libs/coroutine2/performance/cycle_x86-64.hpp79
-rw-r--r--src/boost/libs/coroutine2/performance/performance.cpp98
-rw-r--r--src/boost/libs/coroutine2/performance/segmented/Jamfile.v273
-rw-r--r--src/boost/libs/coroutine2/performance/segmented/performance_create_segmented.cpp105
-rw-r--r--src/boost/libs/coroutine2/performance/segmented/performance_switch.cpp202
-rw-r--r--src/boost/libs/coroutine2/test/Jamfile.v288
-rw-r--r--src/boost/libs/coroutine2/test/test_coroutine.cpp679
28 files changed, 2328 insertions, 0 deletions
diff --git a/src/boost/libs/coroutine2/README.md b/src/boost/libs/coroutine2/README.md
new file mode 100644
index 000000000..784164a3d
--- /dev/null
+++ b/src/boost/libs/coroutine2/README.md
@@ -0,0 +1,14 @@
+boost.coroutine2
+===============
+
+boost.coroutine2 provides templates for generalized subroutines which allow multiple entry points for
+suspending and resuming execution at certain locations. It preserves the local state of execution and
+allows re-entering subroutines more than once (useful if state must be kept across function calls).
+
+Coroutines can be viewed as a language-level construct providing a special kind of control flow.
+
+In contrast to threads, which are pre-emptive, coroutines switches are cooperative (programmer controls
+when a switch will happen). The kernel is not involved in the coroutine switches.
+
+boost.coroutine2 requires C++11!
+Note that boost.coroutine2 is the successor of the deprectated boost.coroutine.
diff --git a/src/boost/libs/coroutine2/example/Jamfile.v2 b/src/boost/libs/coroutine2/example/Jamfile.v2
new file mode 100644
index 000000000..67bd232eb
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/Jamfile.v2
@@ -0,0 +1,45 @@
+
+# Copyright Oliver Kowalke 2014.
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine2/example
+ : requirements
+ <library>/boost/context//boost_context
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ ;
+
+exe fibonacci
+ : fibonacci.cpp
+ ;
+
+exe same_fringe
+ : same_fringe.cpp
+ ;
+
+exe layout
+ : layout.cpp
+ ;
+
+exe parser
+ : parser.cpp
+ ;
+
+exe segmented
+ : segmented.cpp
+ ;
diff --git a/src/boost/libs/coroutine2/example/fibonacci.cpp b/src/boost/libs/coroutine2/example/fibonacci.cpp
new file mode 100644
index 000000000..547342cb2
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/fibonacci.cpp
@@ -0,0 +1,30 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <cstdlib>
+#include <iostream>
+
+#include <boost/coroutine2/all.hpp>
+
+int main() {
+ boost::coroutines2::coroutine< int >::pull_type source(
+ []( boost::coroutines2::coroutine< int >::push_type & sink) {
+ int first = 1, second = 1;
+ sink( first);
+ sink( second);
+ for ( int i = 0; i < 8; ++i) {
+ int third = first + second;
+ first = second;
+ second = third;
+ sink( third);
+ }
+ });
+ for ( auto i : source) {
+ std::cout << i << " ";
+ }
+ std::cout << "\nDone" << std::endl;
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine2/example/layout.cpp b/src/boost/libs/coroutine2/example/layout.cpp
new file mode 100644
index 000000000..e8f69e01b
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/layout.cpp
@@ -0,0 +1,50 @@
+
+// Copyright Nat Goodspeed 2013.
+// 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 <iostream>
+#include <iomanip>
+#include <vector>
+#include <string>
+#include <utility>
+
+#include <boost/coroutine2/all.hpp>
+
+struct FinalEOL{
+ ~FinalEOL(){
+ std::cout << std::endl;
+ }
+};
+
+int main(int argc,char* argv[]){
+ using std::begin;
+ using std::end;
+ std::vector<std::string> words{
+ "peas", "porridge", "hot", "peas",
+ "porridge", "cold", "peas", "porridge",
+ "in", "the", "pot", "nine",
+ "days", "old" };
+ int num=5,width=15;
+ boost::coroutines2::coroutine<std::string>::push_type writer(
+ [&](boost::coroutines2::coroutine<std::string>::pull_type& in){
+ // finish the last line when we leave by whatever means
+ FinalEOL eol;
+ // pull values from upstream, lay them out 'num' to a line
+ for (;;){
+ for(int i=0;i<num;++i){
+ // when we exhaust the input, stop
+ if(!in) return;
+ std::cout << std::setw(width) << in.get();
+ // now that we've handled this item, advance to next
+ in();
+ }
+ // after 'num' items, line break
+ std::cout << std::endl;
+ }
+ });
+ std::copy(begin(words),end(words),begin(writer));
+ std::cout << "\nDone";
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine2/example/parser.cpp b/src/boost/libs/coroutine2/example/parser.cpp
new file mode 100644
index 000000000..7aef477eb
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/parser.cpp
@@ -0,0 +1,122 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <cctype>
+#include <cstdio>
+#include <exception>
+#include <functional>
+#include <iostream>
+#include <sstream>
+
+#include <boost/coroutine2/all.hpp>
+
+class parser_error : public std::runtime_error {
+public:
+ parser_error() :
+ std::runtime_error("parsing failed") {
+ }
+};
+
+/*
+ * grammar:
+ * P ---> E '\0'
+ * E ---> T {('+'|'-') T}
+ * T ---> S {('*'|'/') S}
+ * S ---> digit | '(' E ')'
+ */
+class Parser{
+ char next;
+ std::istream& is;
+ std::function<void(char)> cb;
+
+ char pull(){
+ return std::char_traits<char>::to_char_type(is.get());
+ }
+
+ void scan(){
+ do{
+ next=pull();
+ }
+ while(isspace(next));
+ }
+
+public:
+ Parser(std::istream& is_,std::function<void(char)> cb_) :
+ next(), is(is_), cb(cb_)
+ {}
+
+ void run() {
+ scan();
+ E();
+ }
+
+private:
+ void E(){
+ T();
+ while (next=='+'||next=='-'){
+ cb(next);
+ scan();
+ T();
+ }
+ }
+
+ void T(){
+ S();
+ while (next=='*'||next=='/'){
+ cb(next);
+ scan();
+ S();
+ }
+ }
+
+ void S(){
+ if (std::isdigit(next)){
+ cb(next);
+ scan();
+ }
+ else if(next=='('){
+ cb(next);
+ scan();
+ E();
+ if (next==')'){
+ cb(next);
+ scan();
+ }else{
+ throw parser_error();
+ }
+ }
+ else{
+ throw parser_error();
+ }
+ }
+};
+
+typedef boost::coroutines2::coroutine< char > coro_t;
+
+int main() {
+ try {
+ std::istringstream is("1+1");
+ // invert control flow
+ coro_t::pull_type seq(
+ [&is]( coro_t::push_type & yield) {
+ Parser p( is,
+ [&yield](char ch){
+ yield(ch);
+ });
+ p.run();
+ });
+ // user-code pulls parsed data from parser
+ for(char c:seq){
+ printf("Parsed: %c\n",c);
+ }
+ std::cout << "\nDone" << std::endl;
+ return EXIT_SUCCESS;
+ } catch ( std::exception const& ex) {
+ std::cerr << "exception: " << ex.what() << std::endl;
+ }
+ return EXIT_FAILURE;
+}
+
diff --git a/src/boost/libs/coroutine2/example/same_fringe.cpp b/src/boost/libs/coroutine2/example/same_fringe.cpp
new file mode 100644
index 000000000..a056105bd
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/same_fringe.cpp
@@ -0,0 +1,172 @@
+
+// Copyright Nat Goodspeed 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSEstd::placeholders::_1_0.txt or copy at
+// http://www.boost.org/LICENSEstd::placeholders::_1_0.txt)
+
+#include <cstddef>
+#include <cstdlib>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <utility>
+
+#include <boost/coroutine2/all.hpp>
+
+struct node {
+ typedef std::shared_ptr< node > ptr_t;
+
+ // Each tree node has an optional left subtree, an optional right subtree
+ // and a value of its own. The value is considered to be between the left
+ // subtree and the right.
+ ptr_t left, right;
+ std::string value;
+
+ // construct leaf
+ node(const std::string& v):
+ left(),right(),value(v) {
+ }
+
+ // construct nonleaf
+ node(ptr_t l, const std::string& v, ptr_t r):
+ left(l),right(r),value(v) {
+ }
+
+ static ptr_t create(const std::string& v) {
+ return ptr_t(new node(v));
+ }
+
+ static ptr_t create(ptr_t l, const std::string& v, ptr_t r) {
+ return ptr_t(new node(l, v, r));
+ }
+};
+
+node::ptr_t create_left_tree_from(const std::string& root) {
+ /* --------
+ root
+ / \
+ b e
+ / \
+ a c
+ -------- */
+
+ return node::create(
+ node::create(
+ node::create("a"),
+ "b",
+ node::create("c")),
+ root,
+ node::create("e"));
+}
+
+node::ptr_t create_right_tree_from(const std::string& root) {
+ /* --------
+ root
+ / \
+ a d
+ / \
+ c e
+ -------- */
+
+ return node::create(
+ node::create("a"),
+ root,
+ node::create(
+ node::create("c"),
+ "d",
+ node::create("e")));
+}
+
+// recursively walk the tree, delivering values in order
+void traverse(node::ptr_t n, boost::coroutines2::coroutine<std::string>::push_type& out) {
+ if (n->left)
+ traverse(n->left,out);
+ out(n->value);
+ if (n->right)
+ traverse(n->right,out);
+}
+
+int main() {
+ {
+ node::ptr_t left_d(create_left_tree_from("d"));
+ node::ptr_t right_b(create_right_tree_from("b"));
+ node::ptr_t right_x(create_right_tree_from("x"));
+ {
+ boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(left_d,out);
+ });
+ std::cout << "left tree from d:\n";
+ std::copy(begin(left_d_reader),
+ end(left_d_reader),
+ std::ostream_iterator<std::string>(std::cout, " "));
+ std::cout << std::endl;
+
+ boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(right_b,out);
+ });
+ std::cout << "right tree from b:\n";
+ std::copy(begin(right_b_reader),
+ end(right_b_reader),
+ std::ostream_iterator<std::string>(std::cout, " "));
+ std::cout << std::endl;
+
+ boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(right_x,out);
+ });
+ std::cout << "right tree from x:\n";
+ std::copy(begin(right_x_reader),
+ end(right_x_reader),
+ std::ostream_iterator<std::string>(std::cout, " "));
+ std::cout << std::endl;
+ }
+ }
+ {
+ node::ptr_t left_d(create_left_tree_from("d"));
+ node::ptr_t right_b(create_right_tree_from("b"));
+ {
+ boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(left_d,out);
+ });
+
+ boost::coroutines2::coroutine<std::string>::pull_type right_b_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(right_b,out);
+ });
+
+ std::cout << "left tree from d == right tree from b? "
+ << std::boolalpha
+ << std::equal(begin(left_d_reader),
+ end(left_d_reader),
+ begin(right_b_reader))
+ << std::endl;
+ }
+ }
+ {
+ node::ptr_t left_d(create_left_tree_from("d"));
+ node::ptr_t right_x(create_right_tree_from("x"));
+ {
+ boost::coroutines2::coroutine<std::string>::pull_type left_d_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(left_d,out);
+ });
+
+ boost::coroutines2::coroutine<std::string>::pull_type right_x_reader(
+ [&]( boost::coroutines2::coroutine<std::string>::push_type & out) {
+ traverse(right_x,out);
+ });
+
+ std::cout << "left tree from d == right tree from x? "
+ << std::boolalpha
+ << std::equal(begin(left_d_reader),
+ end(left_d_reader),
+ begin(right_x_reader))
+ << std::endl;
+ }
+ }
+ std::cout << "Done" << std::endl;
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine2/example/segmented.cpp b/src/boost/libs/coroutine2/example/segmented.cpp
new file mode 100644
index 000000000..07280551b
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/segmented.cpp
@@ -0,0 +1,48 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <cstdlib>
+#include <iostream>
+#include <memory>
+
+#include <boost/coroutine2/all.hpp>
+
+#ifdef BOOST_MSVC //MS VisualStudio
+__declspec(noinline) void access( char *buf);
+#else // GCC
+void access( char *buf) __attribute__ ((noinline));
+#endif
+void access( char *buf) {
+ buf[0] = '\0';
+}
+
+void bar( int i) {
+ char buf[4 * 1024];
+ if ( i > 0) {
+ access( buf);
+ std::cout << i << ". iteration" << std::endl;
+ bar( i - 1);
+ }
+}
+
+int main() {
+ int count = 384;
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ std::cout << "using segmented_stack stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
+ std::cout << "initial stack size = " << boost::context::segmented_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
+ std::cout << "application should not fail" << std::endl;
+#else
+ std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
+ std::cout << "initial stack size = " << boost::context::fixedsize_stack::traits_type::default_size() / 1024 << "kB" << std::endl;
+ std::cout << "application might fail" << std::endl;
+#endif
+ boost::coroutines2::coroutine< void >::pull_type coro{
+ [count](boost::coroutines2::coroutine< void >::push_type & coro){
+ bar( count);
+ }};
+ std::cout << "main: done" << std::endl;
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine2/example/tree.h b/src/boost/libs/coroutine2/example/tree.h
new file mode 100644
index 000000000..28df52730
--- /dev/null
+++ b/src/boost/libs/coroutine2/example/tree.h
@@ -0,0 +1,97 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 TREE_H
+#define TREE_H
+
+#include <cstddef>
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable:4355)
+#endif
+
+struct branch;
+struct leaf;
+
+struct visitor
+{
+ virtual ~visitor() {};
+
+ virtual void visit( branch & b) = 0;
+ virtual void visit( leaf & l) = 0;
+};
+
+struct node
+{
+ typedef boost::intrusive_ptr< node > ptr_t;
+
+ std::size_t use_count;
+
+ node() :
+ use_count( 0)
+ {}
+
+ virtual ~node() {}
+
+ virtual void accept( visitor & v) = 0;
+
+ friend inline void intrusive_ptr_add_ref( node * p)
+ { ++p->use_count; }
+
+ friend inline void intrusive_ptr_release( node * p)
+ { if ( 0 == --p->use_count) delete p; }
+};
+
+struct branch : public node
+{
+ node::ptr_t left;
+ node::ptr_t right;
+
+ static ptr_t create( node::ptr_t left_, node::ptr_t right_)
+ { return ptr_t( new branch( left_, right_) ); }
+
+ branch( node::ptr_t left_, node::ptr_t right_) :
+ left( left_), right( right_)
+ {}
+
+ void accept( visitor & v)
+ { v.visit( * this); }
+};
+
+struct leaf : public node
+{
+ std::string value;
+
+ static ptr_t create( std::string const& value_)
+ { return ptr_t( new leaf( value_) ); }
+
+ leaf( std::string const& value_) :
+ value( value_)
+ {}
+
+ void accept( visitor & v)
+ { v.visit( * this); }
+};
+
+inline
+bool operator==( leaf const& l, leaf const& r)
+{ return l.value == r.value; }
+
+inline
+bool operator!=( leaf const& l, leaf const& r)
+{ return l.value != r.value; }
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+#endif // TREE_H
diff --git a/src/boost/libs/coroutine2/index.html b/src/boost/libs/coroutine2/index.html
new file mode 100644
index 000000000..0ade6cbd2
--- /dev/null
+++ b/src/boost/libs/coroutine2/index.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
+</head>
+<body>
+Automatic redirection failed, please go to
+<a href="doc/html/index.html">doc/html/index.html</a>
+<hr>
+<p>&copy; Copyright Beman Dawes, 2001</p>
+<p> Distributed under the Boost Software
+License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
+www.boost.org/LICENSE_1_0.txt</a>)</p>
+</body>
+</html>
diff --git a/src/boost/libs/coroutine2/meta/libraries.json b/src/boost/libs/coroutine2/meta/libraries.json
new file mode 100644
index 000000000..37c84aef9
--- /dev/null
+++ b/src/boost/libs/coroutine2/meta/libraries.json
@@ -0,0 +1,14 @@
+{
+ "key": "coroutine2",
+ "name": "Coroutine2",
+ "authors": [
+ "Oliver Kowalke"
+ ],
+ "description": "(C++11) Coroutine library.",
+ "category": [
+ "Concurrent"
+ ],
+ "maintainers": [
+ "Oliver Kowalke <oliver.kowalke -at- gmail.com>"
+ ]
+}
diff --git a/src/boost/libs/coroutine2/performance/Jamfile.v2 b/src/boost/libs/coroutine2/performance/Jamfile.v2
new file mode 100644
index 000000000..b0860905d
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/Jamfile.v2
@@ -0,0 +1,67 @@
+
+# Copyright Oliver Kowalke 2014.
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine2/performance
+ : requirements
+ <library>/boost/chrono//boost_chrono
+ <library>/boost/context//boost_context
+ <library>/boost/program_options//boost_program_options
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <cxxflags>-DBOOST_DISABLE_ASSERTS
+ <optimization>speed
+ <variant>release
+ ;
+
+alias sources
+ : bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance
+ : sources
+ performance.cpp
+ ;
diff --git a/src/boost/libs/coroutine2/performance/bind_processor.hpp b/src/boost/libs/coroutine2/performance/bind_processor.hpp
new file mode 100644
index 000000000..bdde48a21
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor.hpp
@@ -0,0 +1,12 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 BIND_TO_PROCESSOR_H
+#define BIND_TO_PROCESSOR_H
+
+void bind_to_processor( unsigned int n);
+
+#endif // BIND_TO_PROCESSOR_H
diff --git a/src/boost/libs/coroutine2/performance/bind_processor_aix.cpp b/src/boost/libs/coroutine2/performance/bind_processor_aix.cpp
new file mode 100644
index 000000000..423fad7c7
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor_aix.cpp
@@ -0,0 +1,25 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/processor.h>
+#include <sys/thread.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::bindprocessor( BINDTHREAD, ::thread_yield(), static_cast< cpu_t >( n) ) == -1)
+ throw std::runtime_error("::bindprocessor() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine2/performance/bind_processor_freebsd.cpp b/src/boost/libs/coroutine2/performance/bind_processor_freebsd.cpp
new file mode 100644
index 000000000..3fe8f66ef
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor_freebsd.cpp
@@ -0,0 +1,29 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/param.h>
+#include <sys/cpuset.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ cpuset_t cpuset;
+ CPU_ZERO( & cpuset);
+ CPU_SET( n, & cpuset);
+
+ if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1)
+ throw std::runtime_error("::cpuset_setaffinity() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine2/performance/bind_processor_hpux.cpp b/src/boost/libs/coroutine2/performance/bind_processor_hpux.cpp
new file mode 100644
index 000000000..fe9d05257
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor_hpux.cpp
@@ -0,0 +1,31 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/pthread.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ ::pthread_spu_t spu;
+ int errno_(
+ ::pthread_processor_bind_np(
+ PTHREAD_BIND_FORCED_NP,
+ & spu,
+ static_cast< pthread_spu_t >( n),
+ PTHREAD_SELFTID_NP) );
+ if ( errno_ != 0)
+ throw std::runtime_error("::pthread_processor_bind_np() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine2/performance/bind_processor_linux.cpp b/src/boost/libs/coroutine2/performance/bind_processor_linux.cpp
new file mode 100644
index 000000000..a68ca6854
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor_linux.cpp
@@ -0,0 +1,30 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 "bind_processor.hpp"
+
+extern "C"
+{
+#include <pthread.h>
+#include <sched.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ cpu_set_t cpuset;
+ CPU_ZERO( & cpuset);
+ CPU_SET( n, & cpuset);
+
+ int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) );
+ if ( errno_ != 0)
+ throw std::runtime_error("::pthread_setaffinity_np() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine2/performance/bind_processor_solaris.cpp b/src/boost/libs/coroutine2/performance/bind_processor_solaris.cpp
new file mode 100644
index 000000000..3724a3cd5
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor_solaris.cpp
@@ -0,0 +1,26 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/types.h>
+#include <sys/processor.h>
+#include <sys/procset.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( n), 0) == -1)
+ throw std::runtime_error("::processor_bind() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine2/performance/bind_processor_windows.cpp b/src/boost/libs/coroutine2/performance/bind_processor_windows.cpp
new file mode 100644
index 000000000..7e5b930e4
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/bind_processor_windows.cpp
@@ -0,0 +1,24 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 "bind_processor.hpp"
+
+extern "C"
+{
+#include <windows.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ( DWORD_PTR)1 << n) == 0)
+ throw std::runtime_error("::SetThreadAffinityMask() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine2/performance/clock.hpp b/src/boost/libs/coroutine2/performance/clock.hpp
new file mode 100644
index 000000000..b897bb53b
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/clock.hpp
@@ -0,0 +1,45 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 CLOCK_H
+#define CLOCK_H
+
+#include <algorithm>
+#include <cstddef>
+#include <numeric>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/chrono.hpp>
+#include <boost/cstdint.hpp>
+
+typedef boost::chrono::high_resolution_clock clock_type;
+typedef clock_type::duration duration_type;
+typedef clock_type::time_point time_point_type;
+
+struct clock_overhead
+{
+ boost::uint64_t operator()()
+ {
+ time_point_type start( clock_type::now() );
+ return ( clock_type::now() - start).count();
+ }
+};
+
+inline
+duration_type overhead_clock()
+{
+ std::size_t iterations( 10);
+ std::vector< boost::uint64_t > overhead( iterations, 0);
+ for ( std::size_t i = 0; i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ clock_overhead() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations);
+}
+
+#endif // CLOCK_H
diff --git a/src/boost/libs/coroutine2/performance/cycle.hpp b/src/boost/libs/coroutine2/performance/cycle.hpp
new file mode 100644
index 000000000..74d59dd3c
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/cycle.hpp
@@ -0,0 +1,26 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 CYCLE_H
+#define CYCLE_H
+
+// x86_64
+// test x86_64 before i386 because icc might
+// define __i686__ for x86_64 too
+#if defined(__x86_64__) || defined(__x86_64) \
+ || defined(__amd64__) || defined(__amd64) \
+ || defined(_M_X64) || defined(_M_AMD64)
+# include "cycle_x86-64.hpp"
+// i386
+#elif defined(i386) || defined(__i386__) || defined(__i386) \
+ || defined(__i486__) || defined(__i586__) || defined(__i686__) \
+ || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \
+ || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \
+ || defined(_M_IX86) || defined(_I86_)
+# include "cycle_i386.hpp"
+#endif
+
+#endif // CYCLE_H
diff --git a/src/boost/libs/coroutine2/performance/cycle_i386.hpp b/src/boost/libs/coroutine2/performance/cycle_i386.hpp
new file mode 100644
index 000000000..0ea2ccefb
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/cycle_i386.hpp
@@ -0,0 +1,83 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 CYCLE_I386_H
+#define CYCLE_I386_H
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+#define BOOST_CONTEXT_CYCLE
+
+typedef boost::uint64_t cycle_type;
+
+#if _MSC_VER
+inline
+cycle_type cycles()
+{
+ cycle_type c;
+ __asm {
+ cpuid
+ rdtsc
+ mov dword ptr [c + 0], eax
+ mov dword ptr [c + 4], edx
+ }
+ return c;
+}
+#elif defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
+inline
+cycle_type cycles()
+{
+ boost::uint32_t lo, hi;
+
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%eax", "%ebx", "%ecx", "%edx"
+ );
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%eax", "%ebx", "%ecx", "%edx"
+ );
+
+ return ( cycle_type)hi << 32 | lo;
+}
+#else
+# error "this compiler is not supported"
+#endif
+
+struct cycle_overhead
+{
+ cycle_type operator()()
+ {
+ cycle_type start( cycles() );
+ return cycles() - start;
+ }
+};
+
+inline
+cycle_type overhead_cycle()
+{
+ std::size_t iterations( 10);
+ std::vector< cycle_type > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ cycle_overhead() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // CYCLE_I386_H
diff --git a/src/boost/libs/coroutine2/performance/cycle_x86-64.hpp b/src/boost/libs/coroutine2/performance/cycle_x86-64.hpp
new file mode 100644
index 000000000..625028579
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/cycle_x86-64.hpp
@@ -0,0 +1,79 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 CYCLE_X86_64_H
+#define CYCLE_X86_64_H
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+#define BOOST_CONTEXT_CYCLE
+
+typedef boost::uint64_t cycle_type;
+
+#if _MSC_VER >= 1400
+# include <intrin.h>
+# pragma intrinsic(__rdtsc)
+inline
+cycle_type cycles()
+{ return __rdtsc(); }
+#elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
+inline
+cycle_type cycles()
+{ return __rdtsc(); }
+#elif defined(__GNUC__) || defined(__SUNPRO_C)
+inline
+cycle_type cycles()
+{
+ boost::uint32_t lo, hi;
+
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%rax", "%rbx", "%rcx", "%rdx"
+ );
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%rax", "%rbx", "%rcx", "%rdx"
+ );
+
+ return ( cycle_type)hi << 32 | lo;
+}
+#else
+# error "this compiler is not supported"
+#endif
+
+struct cycle_overhead
+{
+ cycle_type operator()()
+ {
+ cycle_type start( cycles() );
+ return cycles() - start;
+ }
+};
+
+inline
+cycle_type overhead_cycle()
+{
+ std::size_t iterations( 10);
+ std::vector< cycle_type > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ cycle_overhead() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // CYCLE_X86_64_H
diff --git a/src/boost/libs/coroutine2/performance/performance.cpp b/src/boost/libs/coroutine2/performance/performance.cpp
new file mode 100644
index 000000000..dcc916d44
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/performance.cpp
@@ -0,0 +1,98 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine2/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "bind_processor.hpp"
+#include "clock.hpp"
+#include "cycle.hpp"
+
+boost::uint64_t jobs = 1000;
+
+void fn( boost::coroutines2::coroutine< void >::push_type & c) {
+ while ( true) {
+ c();
+ }
+}
+
+duration_type measure_time_void( duration_type overhead) {
+ boost::coroutines2::coroutine< void >::pull_type c{ fn };
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles_void( cycle_type overhead) {
+ boost::coroutines2::coroutine< void >::pull_type c{ fn };
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[]) {
+ try {
+ bool bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+ if ( bind) {
+ bind_to_processor( 0);
+ }
+ duration_type overhead_c = overhead_clock();
+ boost::uint64_t res = measure_time_void( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ res = measure_cycles_void( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e) {
+ std::cerr << "exception: " << e.what() << std::endl;
+ } catch (...) {
+ std::cerr << "unhandled exception" << std::endl;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine2/performance/segmented/Jamfile.v2 b/src/boost/libs/coroutine2/performance/segmented/Jamfile.v2
new file mode 100644
index 000000000..d459354d2
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/segmented/Jamfile.v2
@@ -0,0 +1,73 @@
+
+# Copyright Oliver Kowalke 2014.
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine2/performance/segmented_stack
+ : requirements
+ <library>/boost/chrono//boost_chrono
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <segmented-stacks>on
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <cxxflags>-DBOOST_DISABLE_ASSERTS
+ <optimization>speed
+ <variant>release
+ ;
+
+alias sources
+ : ../bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : ../bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : ../bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : ../bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : ../bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : ../bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance_create_segmented
+ : sources
+ performance_create_segmented.cpp
+ ;
+
+exe performance_switch
+ : sources
+ performance_switch.cpp
+ ;
diff --git a/src/boost/libs/coroutine2/performance/segmented/performance_create_segmented.cpp b/src/boost/libs/coroutine2/performance/segmented/performance_create_segmented.cpp
new file mode 100644
index 000000000..d2313bfdf
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/segmented/performance_create_segmented.cpp
@@ -0,0 +1,105 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine2/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+typedef boost::coroutines2::segmented_stack stack_allocator;
+typedef boost::coroutines2::coroutine< void > coro_type;
+
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::push_type & c)
+{ while ( true) c(); }
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( stack_alloc, fn);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( stack_alloc, fn);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine2/performance/segmented/performance_switch.cpp b/src/boost/libs/coroutine2/performance/segmented/performance_switch.cpp
new file mode 100644
index 000000000..b23c1e2f8
--- /dev/null
+++ b/src/boost/libs/coroutine2/performance/segmented/performance_switch.cpp
@@ -0,0 +1,202 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine2/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+boost::uint64_t jobs = 1000;
+
+struct X
+{
+ std::string str;
+
+ X( std::string const& str_) :
+ str( str_)
+ {}
+};
+
+const X x("abc");
+
+void fn_void( boost::coroutines2::coroutine< void >::push_type & c)
+{ while ( true) c(); }
+
+void fn_int( boost::coroutines2::coroutine< int >::push_type & c)
+{ while ( true) c( 7); }
+
+void fn_x( boost::coroutines2::coroutine< X >::push_type & c)
+{
+ while ( true) c( x);
+}
+
+duration_type measure_time_void( duration_type overhead)
+{
+ boost::coroutines2::segmented_stack stack_alloc;
+ boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void);
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+duration_type measure_time_int( duration_type overhead)
+{
+ boost::coroutines2::segmented_stack stack_alloc;
+ boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int);
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+duration_type measure_time_x( duration_type overhead)
+{
+ boost::coroutines2::segmented_stack stack_alloc;
+ boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x);
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles_void( cycle_type overhead)
+{
+ boost::coroutines2::segmented_stack stack_alloc;
+ boost::coroutines2::coroutine< void >::pull_type c( stack_alloc, fn_void);
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+cycle_type measure_cycles_int( cycle_type overhead)
+{
+ boost::coroutines2::segmented_stack stack_alloc;
+ boost::coroutines2::coroutine< int >::pull_type c( stack_alloc, fn_int);
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+cycle_type measure_cycles_x( cycle_type overhead)
+{
+ boost::coroutines2::segmented_stack stack_alloc;
+ boost::coroutines2::coroutine< X >::pull_type c( stack_alloc, fn_x);
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time_void( overhead_c).count();
+ std::cout << "void: average of " << res << " nano seconds" << std::endl;
+ res = measure_time_int( overhead_c).count();
+ std::cout << "int: average of " << res << " nano seconds" << std::endl;
+ res = measure_time_x( overhead_c).count();
+ std::cout << "X: average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles_void( overhead_y);
+ std::cout << "void: average of " << res << " cpu cycles" << std::endl;
+ res = measure_cycles_int( overhead_y);
+ std::cout << "int: average of " << res << " cpu cycles" << std::endl;
+ res = measure_cycles_x( overhead_y);
+ std::cout << "X: average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine2/test/Jamfile.v2 b/src/boost/libs/coroutine2/test/Jamfile.v2
new file mode 100644
index 000000000..498a763d4
--- /dev/null
+++ b/src/boost/libs/coroutine2/test/Jamfile.v2
@@ -0,0 +1,88 @@
+
+# Copyright Oliver Kowalke 2014.
+# 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)
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import path ;
+import testing ;
+import toolset ;
+import ../../config/checks/config : requires ;
+
+project boost/coroutine2/test
+ : requirements
+ <library>../../test/build//boost_unit_test_framework
+ <library>/boost/context//boost_context
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <optimization>speed
+ <variant>release
+ ;
+
+rule native-impl ( properties * )
+{
+ local result ;
+ if ( <target-os>darwin in $(properties) || <target-os>android in $(properties) )
+ {
+ result = <build>no ;
+ }
+ else if ( ! ( <target-os>windows in $(properties) ) )
+ {
+ result = <context-impl>ucontext ;
+ }
+ else
+ {
+ result = <context-impl>winfib ;
+ }
+ return $(result) ;
+}
+
+test-suite minimal :
+[ run test_coroutine.cpp :
+ : :
+ <context-impl>fcontext
+ [ requires cxx11_auto_declarations
+ cxx11_constexpr
+ cxx11_defaulted_functions
+ cxx11_final
+ cxx11_hdr_tuple
+ cxx11_lambdas
+ cxx11_noexcept
+ cxx11_nullptr
+ cxx11_rvalue_references
+ cxx11_template_aliases
+ cxx11_variadic_templates ]
+ : test_coroutine_asm ]
+
+[ run test_coroutine.cpp :
+ : :
+ <conditional>@native-impl
+ [ requires cxx11_auto_declarations
+ cxx11_constexpr
+ cxx11_defaulted_functions
+ cxx11_final
+ cxx11_hdr_tuple
+ cxx11_lambdas
+ cxx11_noexcept
+ cxx11_nullptr
+ cxx11_rvalue_references
+ cxx11_template_aliases
+ cxx11_variadic_templates ]
+ : test_coroutine_native ] ;
+
+test-suite full :
+ minimal ;
+
+test-suite extra ;
+
+explicit minimal ;
+explicit extra ;
diff --git a/src/boost/libs/coroutine2/test/test_coroutine.cpp b/src/boost/libs/coroutine2/test/test_coroutine.cpp
new file mode 100644
index 000000000..0a9da6ac0
--- /dev/null
+++ b/src/boost/libs/coroutine2/test/test_coroutine.cpp
@@ -0,0 +1,679 @@
+
+// Copyright Oliver Kowalke 2014.
+// 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 <algorithm>
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include <boost/coroutine2/coroutine.hpp>
+
+namespace coro = boost::coroutines2;
+
+int value1 = 0;
+std::string value2 = "";
+bool value3 = false;
+double value4 = .0;
+int * value5 = nullptr;
+int& value6 = value1;
+int& value7 = value1;
+int value8 = 0;
+int value9 = 0;
+
+struct X
+{
+ X() { value1 = 7; }
+ ~X() { value1 = 0; }
+
+ X( X const&) = delete;
+ X & operator=( X const&) = delete;
+};
+
+class copyable
+{
+public:
+ bool state;
+
+ copyable() :
+ state( false)
+ {}
+
+ copyable( int) :
+ state( true)
+ {}
+
+ void operator()( coro::coroutine< int >::push_type &)
+ { value3 = state; }
+};
+
+class moveable
+{
+public:
+ bool state;
+
+ moveable() :
+ state( false)
+ {}
+
+ moveable( int) :
+ state( true)
+ {}
+
+ moveable( moveable const&) = delete;
+ moveable & operator=( moveable const&) = delete;
+
+ moveable( moveable && other) :
+ state( false)
+ { std::swap( state, other.state); }
+
+ moveable & operator=( moveable && other)
+ {
+ if ( this != & other) {
+ state = other.state;
+ other.state = false;
+ }
+ return * this;
+ }
+
+ void operator()( coro::coroutine< int >::push_type &)
+ { value3 = state; }
+};
+
+class movedata
+{
+public:
+ int i;
+
+ movedata( int i_) :
+ i( i_)
+ {}
+
+ movedata( movedata const&) = delete;
+ movedata & operator=( movedata const&) = delete;
+
+ movedata( movedata && other) :
+ i( 0)
+ { std::swap( i, other.i); }
+
+ movedata & operator=( movedata && other)
+ {
+ if ( this != & other) {
+ i = other.i;
+ other.i = 0;
+ }
+ return * this;
+ }
+};
+
+struct my_exception {};
+
+void f1( coro::coroutine< void >::push_type & c)
+{
+ while ( c)
+ c();
+}
+
+void f2( coro::coroutine< void >::push_type &)
+{ ++value1; }
+
+void f3( coro::coroutine< void >::push_type & c)
+{
+ ++value1;
+ c();
+ ++value1;
+}
+
+void f4( coro::coroutine< int >::push_type & c)
+{
+ c( 3);
+ c( 7);
+}
+
+void f5( coro::coroutine< std::string >::push_type & c)
+{
+ std::string res("abc");
+ c( res);
+ res = "xyz";
+ c( res);
+}
+
+void f6( coro::coroutine< int >::pull_type & c)
+{ value1 = c.get(); }
+
+void f7( coro::coroutine< std::string >::pull_type & c)
+{ value2 = c.get(); }
+
+void f8( coro::coroutine< std::tuple< double, double > >::pull_type & c)
+{
+ double x = 0, y = 0;
+ std::tie( x, y) = c.get();
+ value4 = x + y;
+ c();
+ std::tie( x, y) = c.get();
+ value4 = x + y;
+}
+
+void f9( coro::coroutine< int * >::pull_type & c)
+{ value5 = c.get(); }
+
+void f91( coro::coroutine< int const* >::pull_type & c)
+{ value5 = const_cast< int * >( c.get() ); }
+
+void f10( coro::coroutine< int & >::pull_type & c)
+{
+ int & i = c.get();
+ value5 = const_cast< int * >( & i);
+}
+
+void f101( coro::coroutine< int const& >::pull_type & c)
+{
+ int const& i = c.get();
+ value5 = const_cast< int * >( & i);
+}
+
+void f11( coro::coroutine< std::tuple< int, int > >::pull_type & c)
+{
+ std::tie( value8, value9) = c.get();
+}
+
+void f12( coro::coroutine< void >::pull_type & c)
+{
+ value1 = 7;
+ X x_;
+ c();
+ c();
+}
+
+void f16( coro::coroutine< int >::push_type & c)
+{
+ c( 1);
+ c( 2);
+ c( 3);
+ c( 4);
+ c( 5);
+}
+
+void f17( coro::coroutine< int >::pull_type & c, std::vector< int > & vec)
+{
+ int x = c.get();
+ while ( 5 > x)
+ {
+ vec.push_back( x);
+ x = c().get();
+ }
+}
+
+void f20( coro::coroutine< int >::push_type &)
+{}
+
+void f21( coro::coroutine< int >::pull_type & c)
+{
+ while ( c)
+ {
+ value1 = c.get();
+ c();
+ }
+}
+
+void f22( coro::coroutine< movedata >::pull_type & c)
+{
+ movedata mv( c.get() );
+ value1 = mv.i;
+}
+
+void test_move()
+{
+ {
+ coro::coroutine< int >::pull_type coro1( f20);
+ coro::coroutine< int >::pull_type coro2( f16);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+ BOOST_CHECK_EQUAL( 1, coro2.get() );
+ coro2();
+ BOOST_CHECK_EQUAL( 2, coro2.get() );
+ coro1 = std::move( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro2);
+ coro1();
+ BOOST_CHECK_EQUAL( 3, coro1.get() );
+ BOOST_CHECK( ! coro2);
+ }
+
+ {
+ value3 = false;
+ copyable cp( 3);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( ! value3);
+ coro::coroutine< int >::pull_type coro( cp);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( value3);
+ }
+
+ {
+ value3 = false;
+ moveable mv( 7);
+ BOOST_CHECK( mv.state);
+ BOOST_CHECK( ! value3);
+ coro::coroutine< int >::pull_type coro( std::move( mv) );
+ BOOST_CHECK( ! mv.state);
+ BOOST_CHECK( value3);
+ }
+
+ {
+ value1 = 0;
+ movedata mv( 7);
+ BOOST_CHECK_EQUAL( 0, value1);
+ BOOST_CHECK_EQUAL( 7, mv.i);
+ coro::coroutine< movedata >::push_type coro( f22);
+ coro( std::move( mv) );
+ BOOST_CHECK_EQUAL( 7, value1);
+ BOOST_CHECK_EQUAL( 0, mv.i);
+ }
+}
+
+void test_complete()
+{
+ value1 = 0;
+
+ coro::coroutine< void >::pull_type coro( f2);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+}
+
+void test_bind()
+{
+ value1 = 0;
+
+ coro::coroutine< void >::pull_type coro( std::bind( f2, std::placeholders::_1) );
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+}
+
+void test_jump()
+{
+ value1 = 0;
+
+ coro::coroutine< void >::pull_type coro( f3);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+ coro();
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)2, value1);
+}
+
+void test_result_int()
+{
+ coro::coroutine< int >::pull_type coro( f4);
+ BOOST_CHECK( coro);
+ int result = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( 3, result);
+ result = coro().get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( 7, result);
+ coro();
+ BOOST_CHECK( ! coro);
+}
+
+void test_result_string()
+{
+ coro::coroutine< std::string >::pull_type coro( f5);
+ BOOST_CHECK( coro);
+ std::string result = coro.get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( std::string("abc"), result);
+ result = coro().get();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( std::string("xyz"), result);
+ coro();
+ BOOST_CHECK( ! coro);
+}
+
+void test_arg_int()
+{
+ value1 = 0;
+
+ coro::coroutine< int >::push_type coro( f6);
+ BOOST_CHECK( coro);
+ coro( 3);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( 3, value1);
+}
+
+void test_arg_string()
+{
+ value2 = "";
+
+ coro::coroutine< std::string >::push_type coro( f7);
+ BOOST_CHECK( coro);
+ coro( std::string("abc") );
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( std::string("abc"), value2);
+}
+
+void test_fp()
+{
+ value4 = 0;
+
+ coro::coroutine< std::tuple< double, double > >::push_type coro( f8);
+ BOOST_CHECK( coro);
+ coro( std::make_tuple( 7.35, 3.14) );
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( double) 10.49, value4);
+
+ value4 = 0;
+ coro( std::make_tuple( 1.15, 3.14) );
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( double) 4.29, value4);
+}
+
+void test_ptr()
+{
+ value5 = nullptr;
+
+ int a = 3;
+ coro::coroutine< int * >::push_type coro( f9);
+ BOOST_CHECK( coro);
+ coro( & a);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_const_ptr()
+{
+ value5 = nullptr;
+
+ int a = 3;
+ coro::coroutine< int const* >::push_type coro( f91);
+ BOOST_CHECK( coro);
+ coro( & a);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_ref()
+{
+ value5 = nullptr;
+
+ int a_ = 3;
+ int & a = a_;
+ coro::coroutine< int & >::push_type coro( f10);
+ BOOST_CHECK( coro);
+ coro( std::ref( a) );
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_const_ref()
+{
+ value5 = nullptr;
+
+ int a = 3;
+ coro::coroutine< int const& >::push_type coro( f101);
+ BOOST_CHECK( coro);
+ coro( a);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_no_result()
+{
+ coro::coroutine< int >::pull_type coro( f20);
+ BOOST_CHECK( ! coro);
+}
+
+void test_tuple()
+{
+ value8 = 0;
+ value9 = 0;
+
+ int a = 3, b = 7;
+ std::tuple< int, int > tpl( a, b);
+ BOOST_CHECK_EQUAL( a, std::get< 0 >( tpl) );
+ BOOST_CHECK_EQUAL( b, std::get< 1 >( tpl) );
+ coro::coroutine< std::tuple< int, int > >::push_type coro( f11);
+ BOOST_CHECK( coro);
+ coro( tpl);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( a, value8);
+ BOOST_CHECK_EQUAL( b, value9);
+}
+
+void test_unwind()
+{
+ value1 = 0;
+ {
+ coro::coroutine< void >::push_type coro( f12);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ coro();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value1);
+ coro();
+ BOOST_CHECK_EQUAL( ( int) 7, value1);
+ }
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ int i = 0;
+ {
+ coro::coroutine< void >::push_type coro(
+ [&i](coro::coroutine< void >::pull_type &) mutable {
+ i = 7;
+ });
+ }
+ {
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ auto * coro = new coro::coroutine< void >::pull_type(
+ [](coro::coroutine< void >::push_type & coro) mutable {
+ X x;
+ coro();
+ });
+ BOOST_CHECK_EQUAL( ( int) 7, value1);
+ delete coro;
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ }
+ {
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ auto * coro = new coro::coroutine< void >::push_type(
+ [](coro::coroutine< void >::pull_type & coro) mutable {
+ X x;
+ coro();
+ });
+ ( * coro)();
+ BOOST_CHECK_EQUAL( ( int) 7, value1);
+ delete coro;
+ BOOST_CHECK_EQUAL( ( int) 0, value1);
+ }
+}
+
+void test_exceptions()
+{
+ std::string msg("abc"), value;
+ std::runtime_error ex( msg);
+ try
+ {
+ coro::coroutine< void >::push_type coro(
+ [&msg]( coro::coroutine< void >::pull_type &) {
+ throw std::runtime_error( msg);
+ });
+ BOOST_CHECK( coro);
+ coro();
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK( false);
+ }
+ catch ( std::runtime_error const& ex)
+ { value = ex.what(); }
+ BOOST_CHECK_EQUAL( value, msg);
+}
+
+void test_input_iterator()
+{
+ {
+ using std::begin;
+ using std::end;
+
+ std::vector< int > vec;
+ coro::coroutine< int >::pull_type coro( f16);
+ coro::coroutine< int >::pull_type::iterator e = end( coro);
+ for (
+ coro::coroutine< int >::pull_type::iterator i = begin( coro);
+ i != e; ++i)
+ { vec.push_back( * i); }
+ BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
+ BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+ BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+ BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+ BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+ BOOST_CHECK_EQUAL( ( int)5, vec[4] );
+ }
+ {
+ std::vector< int > vec;
+ coro::coroutine< int >::pull_type coro( f16);
+ for ( auto i : coro)
+ { vec.push_back( i); }
+ BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
+ BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+ BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+ BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+ BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+ BOOST_CHECK_EQUAL( ( int)5, vec[4] );
+ }
+ {
+ int i1 = 1, i2 = 2, i3 = 3;
+ coro::coroutine< int& >::pull_type coro(
+ [&i1,&i2,&i3](coro::coroutine< int& >::push_type & c){
+ c( i1);
+ c( i2);
+ c( i3);
+ });
+
+ int counter = 1;
+ for ( int & i : coro) {
+ switch ( counter) {
+ case 1:
+ BOOST_CHECK_EQUAL( & i1, & i);
+ break;
+ case 2:
+ BOOST_CHECK_EQUAL( & i2, & i);
+ break;
+ case 3:
+ BOOST_CHECK_EQUAL( & i3, & i);
+ break;
+ default:
+ BOOST_ASSERT( false);
+ }
+ ++counter;
+ }
+ }
+}
+
+void test_output_iterator()
+{
+ using std::begin;
+ using std::end;
+
+ int counter = 0;
+ std::vector< int > vec;
+ coro::coroutine< int >::push_type coro(
+ [&vec]( coro::coroutine< int >::pull_type & c) {
+ int x = c.get();
+ while ( 5 > x)
+ {
+ vec.push_back( x);
+ x = c().get();
+ }
+ });
+ coro::coroutine< int >::push_type::iterator e( end( coro) );
+ for ( coro::coroutine< int >::push_type::iterator i( begin( coro) );
+ i != e; ++i)
+ {
+ i = ++counter;
+ }
+ BOOST_CHECK_EQUAL( ( std::size_t)4, vec.size() );
+ BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+ BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+ BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+ BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+}
+
+std::vector< int > vec;
+coro::coroutine< void >::pull_type * child = nullptr;
+
+void start_child_coroutine() {
+ child = new coro::coroutine< void >::pull_type([](coro::coroutine< void >::push_type & yield) {
+ vec.push_back( 2);
+ yield();
+ vec.push_back( 2);
+ yield();
+ vec.push_back( 2);
+ yield();
+ vec.push_back( 2);
+ yield();
+ vec.push_back( 2);
+ yield();
+ vec.push_back( 2);
+ });
+}
+
+coro::coroutine< void >::pull_type start_parent_coroutine() {
+ return coro::coroutine< void >::pull_type([=](coro::coroutine< void >::push_type & yield) {
+ vec.push_back( 1);
+ start_child_coroutine();
+ yield();
+ vec.push_back( 1);
+ });
+}
+
+void test_chaining()
+{
+ auto parent = start_parent_coroutine();
+ while ( * child) {
+ ( * child)();
+ }
+ BOOST_CHECK_EQUAL( 7, vec.size() );
+ BOOST_CHECK_EQUAL( 1, vec[0]);
+ BOOST_CHECK_EQUAL( 2, vec[1]);
+ BOOST_CHECK_EQUAL( 2, vec[2]);
+ BOOST_CHECK_EQUAL( 2, vec[3]);
+ BOOST_CHECK_EQUAL( 2, vec[4]);
+ BOOST_CHECK_EQUAL( 2, vec[5]);
+ BOOST_CHECK_EQUAL( 2, vec[6]);
+}
+
+boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
+{
+ boost::unit_test::test_suite * test =
+ BOOST_TEST_SUITE("Boost.Coroutine2: coroutine test suite");
+
+ test->add( BOOST_TEST_CASE( & test_move) );
+ test->add( BOOST_TEST_CASE( & test_complete) );
+ test->add( BOOST_TEST_CASE( & test_bind) );
+ test->add( BOOST_TEST_CASE( & test_jump) );
+ test->add( BOOST_TEST_CASE( & test_result_int) );
+ test->add( BOOST_TEST_CASE( & test_result_string) );
+ test->add( BOOST_TEST_CASE( & test_arg_int) );
+ test->add( BOOST_TEST_CASE( & test_arg_string) );
+ test->add( BOOST_TEST_CASE( & test_fp) );
+ test->add( BOOST_TEST_CASE( & test_ptr) );
+ test->add( BOOST_TEST_CASE( & test_const_ptr) );
+ test->add( BOOST_TEST_CASE( & test_no_result) );
+ test->add( BOOST_TEST_CASE( & test_ref) );
+ test->add( BOOST_TEST_CASE( & test_const_ref) );
+ test->add( BOOST_TEST_CASE( & test_tuple) );
+ test->add( BOOST_TEST_CASE( & test_unwind) );
+ test->add( BOOST_TEST_CASE( & test_exceptions) );
+ test->add( BOOST_TEST_CASE( & test_input_iterator) );
+ test->add( BOOST_TEST_CASE( & test_output_iterator) );
+ test->add( BOOST_TEST_CASE( & test_chaining) );
+
+ return test;
+}