├── .gitignore ├── LICENSE_1_0.txt ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── include ├── Makefile.am └── experimental │ ├── await │ ├── bits │ ├── associated_allocator.h │ ├── associated_executor.h │ ├── await_context.h │ ├── call_stack.h │ ├── chain.h │ ├── channel.h │ ├── channel_base.h │ ├── channel_void.h │ ├── codefer.h │ ├── codispatch.h │ ├── coinvoker.h │ ├── continuation.h │ ├── copost.h │ ├── defer.h │ ├── defer_after.h │ ├── defer_at.h │ ├── dispatch.h │ ├── dispatch_after.h │ ├── dispatch_at.h │ ├── exception_ptr_executor.h │ ├── execution_context.h │ ├── executor.h │ ├── executor_traits.h │ ├── executor_work.h │ ├── executor_wrapper.h │ ├── executor_wrapper_base.h │ ├── function_traits.h │ ├── get_associated_allocator.h │ ├── get_associated_executor.h │ ├── invoker.h │ ├── loop_scheduler.h │ ├── make_work.h │ ├── operation.h │ ├── packaged_task.h │ ├── post.h │ ├── post_after.h │ ├── post_at.h │ ├── promise_handler.h │ ├── reactor.h │ ├── scheduler.h │ ├── small_block_recycler.h │ ├── strand.h │ ├── system_executor.h │ ├── thread_pool.h │ ├── timed_invoker.h │ ├── timer.h │ ├── timer_queue.h │ ├── tuple_utils.h │ ├── wait_op.h │ ├── wrap.h │ └── yield_context.h │ ├── channel │ ├── continuation │ ├── executor │ ├── future │ ├── loop_scheduler │ ├── memory │ ├── strand │ ├── thread_pool │ ├── timer │ ├── type_traits │ └── yield └── src ├── Makefile.am ├── examples ├── Makefile.am ├── channel │ ├── .gitignore │ ├── Makefile.am │ ├── ping.cpp │ ├── pingpong.cpp │ └── pingvoid.cpp ├── executor │ ├── .gitignore │ ├── Makefile.am │ ├── actor.cpp │ ├── async_1.cpp │ ├── async_op_1.cpp │ ├── async_op_2.cpp │ ├── bank_account_1.cpp │ ├── bank_account_10.cpp │ ├── bank_account_2.cpp │ ├── bank_account_3.cpp │ ├── bank_account_4.cpp │ ├── bank_account_5.cpp │ ├── bank_account_6.cpp │ ├── bank_account_7.cpp │ ├── bank_account_8.cpp │ ├── bank_account_9.cpp │ ├── fork_join.cpp │ ├── pipeline.cpp │ ├── post_1.cpp │ ├── post_2.cpp │ ├── post_3.cpp │ ├── post_4.cpp │ ├── post_5.cpp │ ├── priority_scheduler.cpp │ ├── sort_1.cpp │ ├── sort_2.cpp │ ├── sort_3.cpp │ ├── sort_4.cpp │ ├── sort_5.cpp │ ├── sort_6.cpp │ └── sort_7.cpp ├── timer │ ├── .gitignore │ ├── Makefile.am │ ├── dispatch_after_1.cpp │ ├── dispatch_after_2.cpp │ ├── dispatch_at_1.cpp │ └── dispatch_at_2.cpp └── trading │ ├── .gitignore │ ├── Makefile.am │ ├── client │ ├── enter_one_order.cpp │ └── market_data_dump.cpp │ ├── common │ ├── market_data.cpp │ ├── market_data.hpp │ ├── order_management.cpp │ ├── order_management.hpp │ ├── order_side.cpp │ ├── order_side.hpp │ ├── udp_socket.cpp │ └── udp_socket.hpp │ ├── ports.txt │ ├── server │ ├── .dirstamp │ ├── connection_handler.cpp │ ├── connection_handler.hpp │ ├── market_by_order.cpp │ ├── market_by_order.hpp │ ├── market_data_bus.cpp │ ├── market_data_bus.hpp │ ├── market_data_feed.hpp │ ├── order_book.cpp │ ├── order_book.hpp │ ├── order_management_bus.cpp │ ├── order_management_bus.hpp │ ├── price_time_order_book.cpp │ ├── price_time_order_book.hpp │ └── server.cpp │ └── symbols.txt └── tests ├── .gitignore ├── Makefile.am ├── execution_context ├── .gitignore ├── Makefile.am ├── service_construction.cpp ├── service_inheritance.cpp └── service_ordering.cpp ├── executor ├── .gitignore ├── Makefile.am ├── chain_int.cpp ├── chain_int_int.cpp ├── chain_int_void.cpp ├── chain_void.cpp ├── comparisons.cpp ├── dispatch_after_int.cpp ├── dispatch_after_void.cpp ├── dispatch_at_int.cpp ├── dispatch_at_void.cpp ├── dispatch_int.cpp ├── dispatch_void.cpp ├── post_int.cpp ├── post_void.cpp ├── wrap_dispatch_after_int.cpp ├── wrap_dispatch_after_void.cpp ├── wrap_dispatch_at_int.cpp ├── wrap_dispatch_at_void.cpp ├── wrap_dispatch_int.cpp ├── wrap_dispatch_void.cpp ├── wrap_post_int.cpp └── wrap_post_void.cpp ├── loop_scheduler ├── .gitignore ├── Makefile.am ├── dispatch_int.cpp ├── dispatch_void.cpp ├── nested_dispatch.cpp ├── post_int.cpp ├── post_void.cpp ├── wrap_dispatch_int.cpp ├── wrap_dispatch_void.cpp ├── wrap_post_int.cpp └── wrap_post_void.cpp ├── memory ├── .gitignore ├── Makefile.am └── get_associated_allocator.cpp ├── no_executor ├── .gitignore ├── Makefile.am ├── chain_int.cpp ├── chain_int_int.cpp ├── chain_int_void.cpp ├── chain_void.cpp ├── dispatch_after_int.cpp ├── dispatch_after_void.cpp ├── dispatch_at_int.cpp ├── dispatch_at_void.cpp ├── dispatch_int.cpp ├── dispatch_void.cpp ├── post_int.cpp └── post_void.cpp ├── performance ├── .gitignore ├── Makefile.am ├── function_context_switch.cpp ├── yield_channel.cpp └── yield_context_switch.cpp ├── strand ├── .gitignore ├── Makefile.am ├── dispatch_int.cpp ├── dispatch_void.cpp ├── nested_dispatch.cpp ├── post_int.cpp ├── post_void.cpp ├── sequential.cpp ├── wrap_dispatch_int.cpp ├── wrap_dispatch_void.cpp ├── wrap_post_int.cpp └── wrap_post_void.cpp ├── system_executor ├── .gitignore ├── Makefile.am ├── dispatch_int.cpp ├── dispatch_void.cpp ├── post_int.cpp ├── post_void.cpp ├── wrap_dispatch_int.cpp ├── wrap_dispatch_void.cpp ├── wrap_post_int.cpp └── wrap_post_void.cpp ├── thread_pool ├── .gitignore ├── Makefile.am ├── dispatch_after_int.cpp ├── dispatch_after_void.cpp ├── dispatch_at_int.cpp ├── dispatch_at_void.cpp ├── dispatch_int.cpp ├── dispatch_void.cpp ├── get_associated_executor.cpp ├── make_work.cpp ├── nested_dispatch.cpp ├── post_int.cpp ├── post_void.cpp ├── wrap_dispatch_int.cpp ├── wrap_dispatch_void.cpp ├── wrap_post_int.cpp └── wrap_post_void.cpp ├── timer ├── .gitignore ├── Makefile.am ├── async_wait.cpp ├── cancel.cpp └── wait.cpp └── traits ├── Makefile.am ├── ec.cpp ├── ec_int.cpp ├── ec_int_int.cpp ├── ep.cpp ├── ep_int.cpp ├── ep_int_int.cpp ├── int.cpp ├── int_int.cpp └── void.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | # Autoconf / Automake collateral 16 | Makefile 17 | Makefile.in 18 | aclocal.m4 19 | autom4te.cache 20 | compile 21 | config.guess 22 | config.log 23 | config.status 24 | config.sub 25 | configure 26 | depcomp 27 | install-sh 28 | missing 29 | test-driver 30 | *.gz 31 | *.bz2 32 | *.zip 33 | .deps 34 | 35 | # Debugging files 36 | *.dSYM 37 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign dist-bzip2 dist-zip 2 | 3 | SUBDIRS = include src 4 | 5 | MAINTAINERCLEANFILES = \ 6 | $(srcdir)/aclocal.m4 \ 7 | $(srcdir)/compile \ 8 | $(srcdir)/configure \ 9 | $(srcdir)/config.guess \ 10 | $(srcdir)/config.sub \ 11 | $(srcdir)/depcomp \ 12 | $(srcdir)/install-sh \ 13 | $(srcdir)/missing \ 14 | $(srcdir)/mkinstalldirs \ 15 | $(srcdir)/Makefile.in \ 16 | $(srcdir)/test-driver \ 17 | experimental-*.tar.gz \ 18 | experimental-*.tar.bz2 \ 19 | experimental-*.zip 20 | 21 | EXTRA_DIST = \ 22 | LICENSE_1_0.txt 23 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Helps bootstrapping the application when checked out from CVS. 4 | # Requires GNU autoconf, GNU automake and GNU which. 5 | # 6 | # Copyright (C) 2004, by 7 | # 8 | # Carlo Wood, Run on IRC 9 | # RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt 10 | # Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61 11 | # 12 | 13 | # Do sanity checks. 14 | # Directory check. 15 | if [ ! -f autogen.sh ]; then 16 | echo "Run ./autogen.sh from the directory it exists in." 17 | exit 1 18 | fi 19 | 20 | AUTOMAKE=${AUTOMAKE:-automake} 21 | ACLOCAL=${ACLOCAL:-aclocal} 22 | AUTOCONF=${AUTOCONF:-autoconf} 23 | 24 | ($AUTOCONF --version) >/dev/null 2>/dev/null || (echo "You need GNU autoconf to install from CVS (ftp://ftp.gnu.org/gnu/autoconf/)"; exit 1) || exit 1 25 | ($AUTOMAKE --version) >/dev/null 2>/dev/null || (echo "You need GNU automake 1.7 or higher to install from CVS (ftp://ftp.gnu.org/gnu/automake/)"; exit 1) || exit 1 26 | 27 | # Determine the version of automake. 28 | automake_version=`$AUTOMAKE --version | head -n 1 | sed -e 's/[^12]*\([12]\.[0-9][^ ]*\).*/\1/'` 29 | automake_major=`echo $automake_version | cut -f1 -d.` 30 | automake_minor=`echo $automake_version | cut -f2 -d.` 31 | automake_version_number=`expr "$automake_major" \* 1000 \+ "$automake_minor"` 32 | 33 | # Require automake 1.7. 34 | if expr "1007" \> "$automake_version_number" >/dev/null; then 35 | $AUTOMAKE --version | head -n 1 36 | echo "" 37 | echo "Fatal error: automake 1.7 or higher is required. Please set \$AUTOMAKE" 38 | echo "to point to a newer automake, or upgrade." 39 | echo "" 40 | exit 1 41 | fi 42 | 43 | run() 44 | { 45 | echo "Running $1 ..." 46 | $1 47 | } 48 | 49 | # This is needed when someone just upgraded automake and this cache is still generated by an old version. 50 | rm -rf autom4te.cache config.cache 51 | 52 | run "$ACLOCAL" 53 | run "$AUTOCONF" 54 | run "$AUTOMAKE --add-missing --foreign" 55 | 56 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(executors, [0.1.0]) 2 | AC_CONFIG_SRCDIR(include/experimental/type_traits) 3 | AM_MAINTAINER_MODE 4 | AM_INIT_AUTOMAKE([tar-ustar]) 5 | 6 | AC_CANONICAL_HOST 7 | AM_PROG_CC_C_O 8 | AC_PROG_CXX 9 | AC_LANG(C++) 10 | AC_PROG_RANLIB 11 | 12 | AC_ARG_WITH(boost, 13 | AC_HELP_STRING([--with-boost=DIR],[location of boost distribution]), 14 | [ 15 | if test "${withval}" = no; then 16 | CPPFLAGS="$CPPFLAGS -DEXECUTORS_NO_BOOST=1" 17 | else 18 | CPPFLAGS="$CPPFLAGS -I${withval}" 19 | LIBS="$LIBS -L${withval}/stage/lib -lboost_coroutine -lboost_context -lboost_thread -lboost_system" 20 | fi 21 | ], 22 | [ 23 | CPPFLAGS="$CPPFLAGS -DEXECUTORS_NO_BOOST=1" 24 | ]) 25 | 26 | WINDOWS=no 27 | case $host in 28 | *-*-linux*) 29 | CXXFLAGS="$CXXFLAGS -pthread" 30 | LDFLAGS="$LDFLAGS -pthread" 31 | ;; 32 | *-*-solaris*) 33 | if test "$GXX" = yes; then 34 | CXXFLAGS="$CXXFLAGS -D_PTHREADS" 35 | else 36 | # We'll assume Sun's CC. 37 | CXXFLAGS="$CXXFLAGS -mt" 38 | fi 39 | LIBS="$LIBS -lpthread" 40 | ;; 41 | *-*-mingw32*) 42 | CXXFLAGS="$CXXFLAGS -mthreads" 43 | LDFLAGS="$LDFLAGS -mthreads" 44 | ;; 45 | *-pc-cygwin*) 46 | ;; 47 | *-apple-darwin*) 48 | ;; 49 | *-*-freebsd*) 50 | CXXFLAGS="$CXXFLAGS -pthread" 51 | LDFLAGS="$LDFLAGS -pthread" 52 | ;; 53 | *-*-netbsd*) 54 | CXXFLAGS="$CXXFLAGS -pthread" 55 | LDFLAGS="$LDFLAGS -pthread" 56 | ;; 57 | esac 58 | 59 | if test "$GXX" = yes; then 60 | CPPFLAGS="-std=c++1y -Wno-unused-local-typedefs $CPPFLAGS" 61 | fi 62 | 63 | AC_OUTPUT([ 64 | Makefile 65 | include/Makefile 66 | src/Makefile 67 | src/examples/Makefile 68 | src/examples/channel/Makefile 69 | src/examples/executor/Makefile 70 | src/examples/timer/Makefile 71 | src/examples/trading/Makefile 72 | src/tests/Makefile 73 | src/tests/execution_context/Makefile 74 | src/tests/executor/Makefile 75 | src/tests/loop_scheduler/Makefile 76 | src/tests/memory/Makefile 77 | src/tests/no_executor/Makefile 78 | src/tests/performance/Makefile 79 | src/tests/strand/Makefile 80 | src/tests/system_executor/Makefile 81 | src/tests/thread_pool/Makefile 82 | src/tests/timer/Makefile 83 | src/tests/traits/Makefile]) 84 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | nobase_include_HEADERS = \ 2 | experimental/await \ 3 | experimental/channel \ 4 | experimental/continuation \ 5 | experimental/executor \ 6 | experimental/future \ 7 | experimental/loop_scheduler \ 8 | experimental/memory \ 9 | experimental/strand \ 10 | experimental/timer \ 11 | experimental/type_traits \ 12 | experimental/thread_pool \ 13 | experimental/yield \ 14 | experimental/bits/associated_allocator.h \ 15 | experimental/bits/associated_executor.h \ 16 | experimental/bits/await_context.h \ 17 | experimental/bits/call_stack.h \ 18 | experimental/bits/chain.h \ 19 | experimental/bits/channel.h \ 20 | experimental/bits/channel_base.h \ 21 | experimental/bits/channel_void.h \ 22 | experimental/bits/codefer.h \ 23 | experimental/bits/codispatch.h \ 24 | experimental/bits/coinvoker.h \ 25 | experimental/bits/continuation.h \ 26 | experimental/bits/copost.h \ 27 | experimental/bits/defer.h \ 28 | experimental/bits/defer_at.h \ 29 | experimental/bits/defer_after.h \ 30 | experimental/bits/dispatch.h \ 31 | experimental/bits/dispatch_at.h \ 32 | experimental/bits/dispatch_after.h \ 33 | experimental/bits/exception_ptr_executor.h \ 34 | experimental/bits/execution_context.h \ 35 | experimental/bits/executor.h \ 36 | experimental/bits/executor_traits.h \ 37 | experimental/bits/executor_work.h \ 38 | experimental/bits/executor_wrapper.h \ 39 | experimental/bits/executor_wrapper_base.h \ 40 | experimental/bits/function_traits.h \ 41 | experimental/bits/get_associated_allocator.h \ 42 | experimental/bits/get_associated_executor.h \ 43 | experimental/bits/invoker.h \ 44 | experimental/bits/loop_scheduler.h \ 45 | experimental/bits/make_work.h \ 46 | experimental/bits/operation.h \ 47 | experimental/bits/packaged_task.h \ 48 | experimental/bits/post.h \ 49 | experimental/bits/post_at.h \ 50 | experimental/bits/post_after.h \ 51 | experimental/bits/promise_handler.h \ 52 | experimental/bits/reactor.h \ 53 | experimental/bits/scheduler.h \ 54 | experimental/bits/small_block_recycler.h \ 55 | experimental/bits/strand.h \ 56 | experimental/bits/system_executor.h \ 57 | experimental/bits/thread_pool.h \ 58 | experimental/bits/timed_invoker.h \ 59 | experimental/bits/timer.h \ 60 | experimental/bits/timer_queue.h \ 61 | experimental/bits/tuple_utils.h \ 62 | experimental/bits/wait_op.h \ 63 | experimental/bits/wrap.h \ 64 | experimental/bits/yield_context.h 65 | 66 | MAINTAINERCLEANFILES = \ 67 | $(srcdir)/Makefile.in 68 | -------------------------------------------------------------------------------- /include/experimental/await: -------------------------------------------------------------------------------- 1 | // 2 | // await 3 | // ~~~~~ 4 | // Stackless coroutines / resumable functions. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_AWAIT_HEADER 13 | #define EXECUTORS_EXPERIMENTAL_AWAIT_HEADER 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace std { 21 | namespace experimental { 22 | inline namespace concurrency_v1 { 23 | 24 | class __await_context_impl_base; 25 | class __coroutine; 26 | 27 | // Context object used to represent the currently executing coroutine. 28 | 29 | template 30 | class basic_await_context 31 | { 32 | public: 33 | typedef _Executor executor_type; 34 | 35 | // construct / copy / destroy: 36 | 37 | template 38 | basic_await_context(const basic_await_context<_OtherExecutor>&); 39 | 40 | // basic_await_context operations: 41 | 42 | executor_type get_executor() const noexcept; 43 | basic_await_context operator[](error_code& __ec) const; 44 | 45 | private: 46 | template friend class basic_await_context; 47 | template friend class __await_context_impl; 48 | template friend struct __await_context_handler; 49 | 50 | basic_await_context(const executor_work<_Executor>& __w, 51 | shared_ptr<__await_context_impl_base> __i) 52 | : _M_executor(__w.get_executor()), _M_impl(std::move(__i)) {} 53 | 54 | friend __coroutine& _Get_coroutine(const basic_await_context& __c) 55 | { return _Get_coroutine(*__c._M_impl); } 56 | friend __coroutine& _Get_coroutine(const basic_await_context* __c) 57 | { return _Get_coroutine(*__c->_M_impl); } 58 | friend exception_ptr* _Get_coroutine_exception(const basic_await_context& __c) 59 | { return _Get_coroutine_exception(*__c._M_impl); } 60 | friend exception_ptr* _Get_coroutine_exception(const basic_await_context* __c) 61 | { return _Get_coroutine_exception(*__c->_M_impl); } 62 | friend void** _Get_coroutine_async_result(const basic_await_context& __c) 63 | { return _Get_coroutine_async_result(*__c._M_impl); } 64 | friend void** _Get_coroutine_async_result(const basic_await_context* __c) 65 | { return _Get_coroutine_async_result(*__c->_M_impl); } 66 | 67 | _Executor _M_executor; 68 | shared_ptr<__await_context_impl_base> _M_impl; 69 | error_code* _M_error_code = nullptr; 70 | }; 71 | 72 | template 73 | struct handler_type, _R(_Args...)>; 74 | 75 | typedef basic_await_context await_context; 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #include 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /include/experimental/bits/associated_allocator.h: -------------------------------------------------------------------------------- 1 | // 2 | // associated_allocator.h 3 | // ~~~~~~~~~~~~~~~~~~~~~~ 4 | // Obtain an object's associated allocator. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_ASSOCIATED_ALLOCATOR_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_ASSOCIATED_ALLOCATOR_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | struct __associated_allocator_check 23 | { 24 | typedef void _Type; 25 | }; 26 | 27 | template 28 | struct __associated_allocator 29 | { 30 | typedef _A _Type; 31 | 32 | static _Type _Get(const _T&, const _A& __a) noexcept 33 | { 34 | return __a; 35 | } 36 | }; 37 | 38 | template 39 | struct __associated_allocator<_T, _A, 40 | typename __associated_allocator_check::_Type> 41 | { 42 | typedef typename _T::allocator_type _Type; 43 | 44 | static _Type _Get(const _T& __t, const _A&) noexcept 45 | { 46 | return __t.get_allocator(); 47 | } 48 | }; 49 | 50 | } // inline namespace concurrency_v1 51 | } // namespace experimental 52 | } // namespace std 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/experimental/bits/associated_executor.h: -------------------------------------------------------------------------------- 1 | // 2 | // associated_executor.h 3 | // ~~~~~~~~~~~~~~ 4 | // Obtain an object's associated executor. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_ASSOCIATED_EXECUTOR_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_ASSOCIATED_EXECUTOR_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | struct __associated_executor_check 23 | { 24 | typedef void _Type; 25 | }; 26 | 27 | template 28 | struct __associated_executor 29 | { 30 | typedef _E _Type; 31 | 32 | static _Type _Get(const _T&, const _E& __e) noexcept 33 | { 34 | return __e; 35 | } 36 | }; 37 | 38 | template 39 | struct __associated_executor<_T, _E, 40 | typename __associated_executor_check::_Type> 41 | { 42 | typedef typename _T::executor_type _Type; 43 | 44 | static _Type _Get(const _T& __t, const _E&) noexcept 45 | { 46 | return __t.get_executor(); 47 | } 48 | }; 49 | 50 | } // inline namespace concurrency_v1 51 | } // namespace experimental 52 | } // namespace std 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/experimental/bits/call_stack.h: -------------------------------------------------------------------------------- 1 | // 2 | // call_stack.h 3 | // ~~~~~~~~~~~~ 4 | // Helper to determine whether the caller is inside a given execution context. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_CALL_STACK_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_CALL_STACK_H 14 | 15 | namespace std { 16 | namespace experimental { 17 | inline namespace concurrency_v1 { 18 | 19 | template 20 | class __call_stack 21 | { 22 | public: 23 | class __context 24 | { 25 | public: 26 | __context(const __context&) = delete; 27 | __context& operator=(const __context&) = delete; 28 | 29 | explicit __context(_Key* __k) 30 | : _M_key(__k), _M_next(__call_stack<_Key, _Value>::_S_top) 31 | { 32 | _M_value = reinterpret_cast(this); 33 | __call_stack<_Key, _Value>::_S_top = this; 34 | } 35 | 36 | __context(_Key* k, _Value& v) 37 | : _M_key(k), _M_value(&v), _M_next(__call_stack<_Key, _Value>::_S_top) 38 | { 39 | __call_stack<_Key, _Value>::_S_top = this; 40 | } 41 | 42 | ~__context() 43 | { 44 | __call_stack<_Key, _Value>::_S_top = _M_next; 45 | } 46 | 47 | private: 48 | friend class __call_stack<_Key, _Value>; 49 | _Key* _M_key; 50 | _Value* _M_value; 51 | __context* _M_next; 52 | }; 53 | 54 | static _Value* _Contains(_Key* __k) 55 | { 56 | __context* __elem = _S_top; 57 | while (__elem) 58 | { 59 | if (__elem->_M_key == __k) 60 | return __elem->_M_value; 61 | __elem = __elem->_M_next; 62 | } 63 | return 0; 64 | } 65 | 66 | static _Value* _Top() 67 | { 68 | __context* __elem = _S_top; 69 | return __elem ? __elem->_M_value : 0; 70 | } 71 | 72 | private: 73 | friend class __context; 74 | #if defined(__APPLE__) && defined(__clang__) 75 | static __thread __context* _S_top; 76 | #elif defined(_MSC_VER) 77 | static __declspec(thread) __context* _S_top; 78 | #else 79 | static thread_local __context* _S_top; 80 | #endif 81 | }; 82 | 83 | #if defined(__APPLE__) && defined(__clang__) 84 | template 85 | __thread typename __call_stack<_Key, _Value>::__context* 86 | __call_stack<_Key, _Value>::_S_top; 87 | #elif defined(_MSC_VER) 88 | template 89 | __declspec(thread) typename __call_stack<_Key, _Value>::__context* 90 | __call_stack<_Key, _Value>::_S_top; 91 | #else 92 | template 93 | thread_local typename __call_stack<_Key, _Value>::__context* 94 | __call_stack<_Key, _Value>::_S_top; 95 | #endif 96 | 97 | } // inline namespace concurrency_v1 98 | } // namespace experimental 99 | } // namespace std 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /include/experimental/bits/chain.h: -------------------------------------------------------------------------------- 1 | // 2 | // chain.h 3 | // ~~~~~~~ 4 | // Create a function object from a list of tokens. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_CHAIN_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_CHAIN_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | auto chain(_CompletionTokens&&... __tokens) 23 | { 24 | static_assert(sizeof...(_CompletionTokens) > 0, 25 | "chain() must be called with one or more completion tokens"); 26 | 27 | return __active_invoker(__tokens...); 28 | } 29 | 30 | template 31 | auto chain(_CompletionTokens&&... __tokens) 32 | { 33 | static_assert(sizeof...(_CompletionTokens) > 0, 34 | "chain() must be called with one or more completion tokens"); 35 | 36 | return __active_invoker<_Signature, _CompletionTokens...>(__tokens...); 37 | } 38 | 39 | } // inline namespace concurrency_v1 40 | } // namespace experimental 41 | } // namespace std 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/experimental/bits/codefer.h: -------------------------------------------------------------------------------- 1 | // 2 | // codefer.h 3 | // ~~~~~~~~~~ 4 | // Schedule functions to run concurrently later. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_CODEFER_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_CODEFER_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | struct __coinvoke_defer 22 | { 23 | template 24 | void operator()(_E& __e, _F&& __f, const _A& __a) 25 | { 26 | __e.defer(forward<_F>(__f), __a); 27 | } 28 | }; 29 | 30 | template 31 | inline typename __coinvoke_without_executor<_CompletionTokens...>::_Result 32 | codefer(_CompletionTokens&&... __tokens) 33 | { 34 | constexpr size_t _N = sizeof...(_CompletionTokens) - 1; 35 | typedef __tuple_split_first, _N> _Head; 36 | typedef __tuple_split_second, _N> _Tail; 37 | return __coinvoker_launcher<_Head, _Tail>(__tokens...)._Go(__coinvoke_defer(), __tokens...); 38 | } 39 | 40 | template 41 | struct __coinvoke_defer_ex 42 | { 43 | typename decay<_Executor>::type __e; 44 | 45 | template 46 | void operator()(_E&, _F&& __f, const _A& __a) 47 | { 48 | __e.defer(forward<_F>(__f), __a); 49 | } 50 | }; 51 | 52 | template 53 | inline typename __coinvoke_with_executor<_Executor, _CompletionTokens...>::_Result 54 | codefer(const _Executor& __e, _CompletionTokens&&... __tokens) 55 | { 56 | constexpr size_t _N = sizeof...(_CompletionTokens) - 1; 57 | typedef __tuple_split_first, _N> _Head; 58 | typedef __tuple_split_second, _N> _Tail; 59 | return __coinvoker_launcher<_Head, _Tail>(__tokens...)._Go(__coinvoke_defer_ex<_Executor>{__e}, __tokens...); 60 | } 61 | 62 | } // inline namespace concurrency_v1 63 | } // namespace experimental 64 | } // namespace std 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /include/experimental/bits/codispatch.h: -------------------------------------------------------------------------------- 1 | // 2 | // codispatch.h 3 | // ~~~~~~~~~~~~ 4 | // Schedule functions to run now if possible, otherwise run concurrently later. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_CODISPATCH_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_CODISPATCH_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | struct __coinvoke_dispatch 22 | { 23 | template 24 | void operator()(_E& __e, _F&& __f, const _A& __a) 25 | { 26 | __e.dispatch(forward<_F>(__f), __a); 27 | } 28 | }; 29 | 30 | template 31 | inline typename __coinvoke_without_executor<_CompletionTokens...>::_Result 32 | codispatch(_CompletionTokens&&... __tokens) 33 | { 34 | constexpr size_t _N = sizeof...(_CompletionTokens) - 1; 35 | typedef __tuple_split_first, _N> _Head; 36 | typedef __tuple_split_second, _N> _Tail; 37 | return __coinvoker_launcher<_Head, _Tail>(__tokens...)._Go(__coinvoke_dispatch(), __tokens...); 38 | } 39 | 40 | template 41 | struct __coinvoke_dispatch_ex 42 | { 43 | typename decay<_Executor>::type __e; 44 | 45 | template 46 | void operator()(_E&, _F&& __f, const _A& __a) 47 | { 48 | __e.dispatch(forward<_F>(__f), __a); 49 | } 50 | }; 51 | 52 | template 53 | inline typename __coinvoke_with_executor<_Executor, _CompletionTokens...>::_Result 54 | codispatch(const _Executor& __e, _CompletionTokens&&... __tokens) 55 | { 56 | constexpr size_t _N = sizeof...(_CompletionTokens) - 1; 57 | typedef __tuple_split_first, _N> _Head; 58 | typedef __tuple_split_second, _N> _Tail; 59 | return __coinvoker_launcher<_Head, _Tail>(__tokens...)._Go(__coinvoke_dispatch_ex<_Executor>{__e}, __tokens...); 60 | } 61 | 62 | } // inline namespace concurrency_v1 63 | } // namespace experimental 64 | } // namespace std 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /include/experimental/bits/copost.h: -------------------------------------------------------------------------------- 1 | // 2 | // copost.h 3 | // ~~~~~~~~ 4 | // Schedule functions to run concurrently later. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_COPOST_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_COPOST_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | struct __coinvoke_post 22 | { 23 | template 24 | void operator()(_E& __e, _F&& __f, const _A& __a) 25 | { 26 | __e.post(forward<_F>(__f), __a); 27 | } 28 | }; 29 | 30 | template 31 | inline typename __coinvoke_without_executor<_CompletionTokens...>::_Result 32 | copost(_CompletionTokens&&... __tokens) 33 | { 34 | constexpr size_t _N = sizeof...(_CompletionTokens) - 1; 35 | typedef __tuple_split_first, _N> _Head; 36 | typedef __tuple_split_second, _N> _Tail; 37 | return __coinvoker_launcher<_Head, _Tail>(__tokens...)._Go(__coinvoke_post(), __tokens...); 38 | } 39 | 40 | template 41 | struct __coinvoke_post_ex 42 | { 43 | typename decay<_Executor>::type __e; 44 | 45 | template 46 | void operator()(_E&, _F&& __f, const _A& __a) 47 | { 48 | __e.post(forward<_F>(__f), __a); 49 | } 50 | }; 51 | 52 | template 53 | inline typename __coinvoke_with_executor<_Executor, _CompletionTokens...>::_Result 54 | copost(const _Executor& __e, _CompletionTokens&&... __tokens) 55 | { 56 | constexpr size_t _N = sizeof...(_CompletionTokens) - 1; 57 | typedef __tuple_split_first, _N> _Head; 58 | typedef __tuple_split_second, _N> _Tail; 59 | return __coinvoker_launcher<_Head, _Tail>(__tokens...)._Go(__coinvoke_post_ex<_Executor>{__e}, __tokens...); 60 | } 61 | 62 | } // inline namespace concurrency_v1 63 | } // namespace experimental 64 | } // namespace std 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /include/experimental/bits/defer.h: -------------------------------------------------------------------------------- 1 | // 2 | // defer.h 3 | // ~~~~~~~ 4 | // Schedule a function to run later, treating it as a continuation of the caller. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_DEFER_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_DEFER_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | typename __invoke_with_token<_CompletionTokens...>::_Result 23 | defer(_CompletionTokens&&... __tokens) 24 | { 25 | static_assert(sizeof...(_CompletionTokens) > 0, 26 | "defer() must be called with one or more completion tokens"); 27 | 28 | typedef __passive_invoker _Invoker; 29 | 30 | _Invoker __head(__tokens...); 31 | async_result<_Invoker> __result(__head); 32 | 33 | auto __completion_executor(get_associated_executor(__head)); 34 | auto __completion_allocator(get_associated_allocator(__head)); 35 | __completion_executor.defer(std::move(__head), __completion_allocator); 36 | 37 | return __result.get(); 38 | } 39 | 40 | template 41 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 42 | defer(const _Executor& __e, _CompletionTokens&&... __tokens) 43 | { 44 | static_assert(sizeof...(_CompletionTokens) > 0, 45 | "defer() must be called with one or more completion tokens"); 46 | 47 | typedef __active_invoker _Invoker; 48 | 49 | _Invoker __head(__tokens...); 50 | async_result<_Invoker> __result(__head); 51 | 52 | auto __completion_executor(__e); 53 | auto __completion_allocator(get_associated_allocator(__head)); 54 | __completion_executor.defer(std::move(__head), __completion_allocator); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | defer(_ExecutionContext& __c, _CompletionTokens&&... __tokens) 62 | { 63 | static_assert(sizeof...(_CompletionTokens) > 0, 64 | "defer() must be called with one or more completion tokens"); 65 | 66 | typedef __active_invoker _Invoker; 67 | 68 | _Invoker __head(__tokens...); 69 | async_result<_Invoker> __result(__head); 70 | 71 | auto __completion_executor(__c.get_executor()); 72 | auto __completion_allocator(get_associated_allocator(__head)); 73 | __completion_executor.defer(std::move(__head), __completion_allocator); 74 | 75 | return __result.get(); 76 | } 77 | 78 | } // inline namespace concurrency_v1 79 | } // namespace experimental 80 | } // namespace std 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/experimental/bits/defer_after.h: -------------------------------------------------------------------------------- 1 | // 2 | // defer_after.h 3 | // ~~~~~~~~~~~~~ 4 | // Schedule a function to run at a relative time. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_DEFER_AFTER_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_DEFER_AFTER_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | typename __invoke_with_token<_CompletionTokens...>::_Result 24 | defer_after(const chrono::duration<_Rep, _Period>& __rel_time, 25 | _CompletionTokens&&... __tokens) 26 | { 27 | static_assert(sizeof...(_CompletionTokens) > 0, 28 | "defer_after() must be called with one or more completion tokens"); 29 | 30 | typedef __timed_invoker _Invoker; 31 | 32 | _Invoker __head(__tokens...); 33 | async_result __result(__head._Get_tail()); 34 | 35 | auto __completion_executor(get_associated_executor(__head._Get_tail())); 36 | __head._Start(__completion_executor, __rel_time); 37 | 38 | return __result.get(); 39 | } 40 | 41 | template 42 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 43 | defer_after(const chrono::duration<_Rep, _Period>& __rel_time, 44 | const _Executor& __e, _CompletionTokens&&... __tokens) 45 | { 46 | static_assert(sizeof...(_CompletionTokens) > 0, 47 | "defer_after() must be called with one or more completion tokens"); 48 | 49 | typedef __timed_invoker _Invoker; 50 | 51 | _Invoker __head(__tokens...); 52 | async_result __result(__head._Get_tail()); 53 | 54 | __head._Start(__e, __rel_time); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | defer_after(const chrono::duration<_Rep, _Period>& __rel_time, 62 | _ExecutionContext& __c, _CompletionTokens&&... __tokens) 63 | { 64 | static_assert(sizeof...(_CompletionTokens) > 0, 65 | "defer_after() must be called with one or more completion tokens"); 66 | 67 | typedef __timed_invoker _Invoker; 68 | 69 | _Invoker __head(__tokens...); 70 | async_result __result(__head._Get_tail()); 71 | 72 | __head._Start(__c.get_executor(), __rel_time); 73 | 74 | return __result.get(); 75 | } 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/experimental/bits/defer_at.h: -------------------------------------------------------------------------------- 1 | // 2 | // defer_at.h 3 | // ~~~~~~~~~~ 4 | // Schedule a function to run at an absolute time. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_DEFER_AT_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_DEFER_AT_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | typename __invoke_with_token<_CompletionTokens...>::_Result 24 | defer_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 25 | _CompletionTokens&&... __tokens) 26 | { 27 | static_assert(sizeof...(_CompletionTokens) > 0, 28 | "defer_at() must be called with one or more completion tokens"); 29 | 30 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 31 | 32 | _Invoker __head(__tokens...); 33 | async_result __result(__head._Get_tail()); 34 | 35 | auto __completion_executor(get_associated_executor(__head._Get_tail())); 36 | __head._Start(__completion_executor, __abs_time); 37 | 38 | return __result.get(); 39 | } 40 | 41 | template 42 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 43 | defer_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 44 | const _Executor& __e, _CompletionTokens&&... __tokens) 45 | { 46 | static_assert(sizeof...(_CompletionTokens) > 0, 47 | "defer_at() must be called with one or more completion tokens"); 48 | 49 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 50 | 51 | _Invoker __head(__tokens...); 52 | async_result __result(__head._Get_tail()); 53 | 54 | __head._Start(__e, __abs_time); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | defer_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 62 | _ExecutionContext& __c, _CompletionTokens&&... __tokens) 63 | { 64 | static_assert(sizeof...(_CompletionTokens) > 0, 65 | "defer_at() must be called with one or more completion tokens"); 66 | 67 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 68 | 69 | _Invoker __head(__tokens...); 70 | async_result __result(__head._Get_tail()); 71 | 72 | __head._Start(__c.get_executor(), __abs_time); 73 | 74 | return __result.get(); 75 | } 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/experimental/bits/dispatch.h: -------------------------------------------------------------------------------- 1 | // 2 | // dispatch.h 3 | // ~~~~~~~~~~ 4 | // Schedule a function to run now if possible, otherwise later. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_DISPATCH_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_DISPATCH_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | typename __invoke_with_token<_CompletionTokens...>::_Result 23 | dispatch(_CompletionTokens&&... __tokens) 24 | { 25 | static_assert(sizeof...(_CompletionTokens) > 0, 26 | "dispatch() must be called with one or more completion tokens"); 27 | 28 | typedef __passive_invoker _Invoker; 29 | 30 | _Invoker __head(__tokens...); 31 | async_result<_Invoker> __result(__head); 32 | 33 | auto __completion_executor(get_associated_executor(__head)); 34 | auto __completion_allocator(get_associated_allocator(__head)); 35 | __completion_executor.dispatch(std::move(__head), __completion_allocator); 36 | 37 | return __result.get(); 38 | } 39 | 40 | template 41 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 42 | dispatch(const _Executor& __e, _CompletionTokens&&... __tokens) 43 | { 44 | static_assert(sizeof...(_CompletionTokens) > 0, 45 | "dispatch() must be called with one or more completion tokens"); 46 | 47 | typedef __active_invoker _Invoker; 48 | 49 | _Invoker __head(__tokens...); 50 | async_result<_Invoker> __result(__head); 51 | 52 | auto __completion_executor(__e); 53 | auto __completion_allocator(get_associated_allocator(__head)); 54 | __completion_executor.dispatch(std::move(__head), __completion_allocator); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | dispatch(_ExecutionContext& __c, _CompletionTokens&&... __tokens) 62 | { 63 | static_assert(sizeof...(_CompletionTokens) > 0, 64 | "dispatch() must be called with one or more completion tokens"); 65 | 66 | typedef __active_invoker _Invoker; 67 | 68 | _Invoker __head(__tokens...); 69 | async_result<_Invoker> __result(__head); 70 | 71 | auto __completion_executor(__c.get_executor()); 72 | auto __completion_allocator(get_associated_allocator(__head)); 73 | __completion_executor.dispatch(std::move(__head), __completion_allocator); 74 | 75 | return __result.get(); 76 | } 77 | 78 | } // inline namespace concurrency_v1 79 | } // namespace experimental 80 | } // namespace std 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/experimental/bits/dispatch_after.h: -------------------------------------------------------------------------------- 1 | // 2 | // dispatch_after.h 3 | // ~~~~~~~~~~~~~~~~ 4 | // Schedule a function to run at a relative time. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_DISPATCH_AFTER_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_DISPATCH_AFTER_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | typename __invoke_with_token<_CompletionTokens...>::_Result 24 | dispatch_after(const chrono::duration<_Rep, _Period>& __rel_time, 25 | _CompletionTokens&&... __tokens) 26 | { 27 | static_assert(sizeof...(_CompletionTokens) > 0, 28 | "dispatch_after() must be called with one or more completion tokens"); 29 | 30 | typedef __timed_invoker _Invoker; 31 | 32 | _Invoker __head(__tokens...); 33 | async_result __result(__head._Get_tail()); 34 | 35 | auto __completion_executor(get_associated_executor(__head._Get_tail())); 36 | __head._Start(__completion_executor, __rel_time); 37 | 38 | return __result.get(); 39 | } 40 | 41 | template 42 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 43 | dispatch_after(const chrono::duration<_Rep, _Period>& __rel_time, 44 | const _Executor& __e, _CompletionTokens&&... __tokens) 45 | { 46 | static_assert(sizeof...(_CompletionTokens) > 0, 47 | "dispatch_after() must be called with one or more completion tokens"); 48 | 49 | typedef __timed_invoker _Invoker; 50 | 51 | _Invoker __head(__tokens...); 52 | async_result __result(__head._Get_tail()); 53 | 54 | __head._Start(__e, __rel_time); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | dispatch_after(const chrono::duration<_Rep, _Period>& __rel_time, 62 | _ExecutionContext& __c, _CompletionTokens&&... __tokens) 63 | { 64 | static_assert(sizeof...(_CompletionTokens) > 0, 65 | "dispatch_after() must be called with one or more completion tokens"); 66 | 67 | typedef __timed_invoker _Invoker; 68 | 69 | _Invoker __head(__tokens...); 70 | async_result __result(__head._Get_tail()); 71 | 72 | __head._Start(__c.get_executor(), __rel_time); 73 | 74 | return __result.get(); 75 | } 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/experimental/bits/dispatch_at.h: -------------------------------------------------------------------------------- 1 | // 2 | // dispatch_at.h 3 | // ~~~~~~~~~~~~~ 4 | // Schedule a function to run at an absolute time. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_DISPATCH_AT_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_DISPATCH_AT_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | typename __invoke_with_token<_CompletionTokens...>::_Result 24 | dispatch_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 25 | _CompletionTokens&&... __tokens) 26 | { 27 | static_assert(sizeof...(_CompletionTokens) > 0, 28 | "dispatch_at() must be called with one or more completion tokens"); 29 | 30 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 31 | 32 | _Invoker __head(__tokens...); 33 | async_result __result(__head._Get_tail()); 34 | 35 | auto __completion_executor(get_associated_executor(__head._Get_tail())); 36 | __head._Start(__completion_executor, __abs_time); 37 | 38 | return __result.get(); 39 | } 40 | 41 | template 42 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 43 | dispatch_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 44 | const _Executor& __e, _CompletionTokens&&... __tokens) 45 | { 46 | static_assert(sizeof...(_CompletionTokens) > 0, 47 | "dispatch_at() must be called with one or more completion tokens"); 48 | 49 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 50 | 51 | _Invoker __head(__tokens...); 52 | async_result __result(__head._Get_tail()); 53 | 54 | __head._Start(__e, __abs_time); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | dispatch_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 62 | _ExecutionContext& __c, _CompletionTokens&&... __tokens) 63 | { 64 | static_assert(sizeof...(_CompletionTokens) > 0, 65 | "dispatch_at() must be called with one or more completion tokens"); 66 | 67 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 68 | 69 | _Invoker __head(__tokens...); 70 | async_result __result(__head._Get_tail()); 71 | 72 | __head._Start(__c.get_executor(), __abs_time); 73 | 74 | return __result.get(); 75 | } 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/experimental/bits/exception_ptr_executor.h: -------------------------------------------------------------------------------- 1 | // 2 | // exception_ptr_executor.h 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // Executor used to capture exceptions into an execption_ptr. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_EXCEPTION_PTR_EXECUTOR_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_EXCEPTION_PTR_EXECUTOR_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | struct __exception_ptr_call_wrapper 23 | { 24 | exception_ptr* _M_exception; 25 | _Func _M_func; 26 | 27 | void operator()() 28 | { 29 | try 30 | { 31 | std::move(_M_func)(); 32 | } 33 | catch (...) 34 | { 35 | *_M_exception = current_exception(); 36 | } 37 | } 38 | }; 39 | 40 | template 41 | struct __exception_ptr_executor 42 | { 43 | exception_ptr* _M_exception; 44 | _Executor _M_executor; 45 | 46 | __exception_ptr_executor(exception_ptr* __ep, const _Executor& __ex) 47 | : _M_exception(__ep), _M_executor(__ex) 48 | { 49 | } 50 | 51 | execution_context& context() noexcept 52 | { 53 | return _M_executor.context(); 54 | } 55 | 56 | void on_work_started() noexcept 57 | { 58 | _M_executor.on_work_started(); 59 | } 60 | 61 | void on_work_finished() noexcept 62 | { 63 | _M_executor.on_work_finished(); 64 | } 65 | 66 | template void dispatch(_F&& __f, const _A& __a) 67 | { 68 | typedef typename decay<_F>::type _Func; 69 | _M_executor.dispatch(__exception_ptr_call_wrapper<_Func>{_M_exception, forward<_F>(__f)}, __a); 70 | } 71 | 72 | template void post(_F&& __f, const _A& __a) 73 | { 74 | typedef typename decay<_F>::type _Func; 75 | _M_executor.post(__exception_ptr_call_wrapper<_Func>{_M_exception, forward<_F>(__f)}, __a); 76 | } 77 | 78 | template void defer(_F&& __f, const _A& __a) 79 | { 80 | typedef typename decay<_F>::type _Func; 81 | _M_executor.defer(__exception_ptr_call_wrapper<_Func>{_M_exception, forward<_F>(__f)}, __a); 82 | } 83 | 84 | friend bool operator==(const __exception_ptr_executor& __a, const __exception_ptr_executor& __b) noexcept 85 | { 86 | return __a._M_exception == __b._M_exception; 87 | } 88 | 89 | friend bool operator!=(const __exception_ptr_executor& __a, const __exception_ptr_executor& __b) noexcept 90 | { 91 | return __a._M_exception != __b._M_exception; 92 | } 93 | }; 94 | 95 | template 96 | struct is_executor<__exception_ptr_executor<_Executor>> : true_type {}; 97 | 98 | } // inline namespace concurrency_v1 99 | } // namespace experimental 100 | } // namespace std 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/experimental/bits/executor_traits.h: -------------------------------------------------------------------------------- 1 | // 2 | // executor_traits.h 3 | // ~~~~~~~~~~~~~~~~~ 4 | // Helper traits to do with executors. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_EXECUTOR_TRAITS_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_EXECUTOR_TRAITS_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template struct __is_executor; 22 | 23 | template struct __is_executor<_T, _U...> 24 | : is_executor::type> {}; 25 | 26 | template struct __is_execution_context; 27 | 28 | template struct __is_execution_context<_T, _U...> 29 | : is_convertible::type&, execution_context&> {}; 30 | 31 | } // inline namespace concurrency_v1 32 | } // namespace experimental 33 | } // namespace std 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/experimental/bits/executor_work.h: -------------------------------------------------------------------------------- 1 | // 2 | // executor_work.h 3 | // ~~~~~~~~~~~~~~~ 4 | // Controls ownership of executor work within a scope. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_EXECUTOR_WORK_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_EXECUTOR_WORK_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | inline executor_work<_Executor>::executor_work(const executor_type& __e) noexcept 24 | : _M_executor(__e), _M_owns(true) 25 | { 26 | _M_executor.on_work_started(); 27 | } 28 | 29 | template 30 | inline executor_work<_Executor>::executor_work(const executor_work& __w) noexcept 31 | : _M_executor(__w._M_executor), _M_owns(__w._M_owns) 32 | { 33 | if (_M_owns) 34 | _M_executor.on_work_started(); 35 | } 36 | 37 | template 38 | inline executor_work<_Executor>::executor_work(executor_work&& __w) noexcept 39 | : _M_executor(std::move(__w._M_executor)), 40 | _M_owns(__w._M_owns) 41 | { 42 | __w._M_owns = false; 43 | } 44 | 45 | template 46 | inline executor_work<_Executor>::~executor_work() 47 | { 48 | if (_M_owns) 49 | _M_executor.on_work_finished(); 50 | } 51 | 52 | template 53 | inline typename executor_work<_Executor>::executor_type 54 | executor_work<_Executor>::get_executor() const noexcept 55 | { 56 | return _M_executor; 57 | } 58 | 59 | template 60 | inline bool executor_work<_Executor>::owns_work() const noexcept 61 | { 62 | return _M_owns; 63 | } 64 | 65 | template 66 | inline void executor_work<_Executor>::reset() noexcept 67 | { 68 | if (_M_owns) 69 | { 70 | _M_executor.on_work_finished(); 71 | _M_owns = false; 72 | } 73 | } 74 | 75 | } // inline namespace concurrency_v1 76 | } // namespace experimental 77 | } // namespace std 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /include/experimental/bits/get_associated_allocator.h: -------------------------------------------------------------------------------- 1 | // 2 | // get_associated_allocator.h 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // Helper function to obtain an associated allocator. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef ALLOCATORS_EXPERIMENTAL_BITS_GET_ASSOCIATED_ALLOCATOR_H 13 | #define ALLOCATORS_EXPERIMENTAL_BITS_GET_ASSOCIATED_ALLOCATOR_H 14 | 15 | namespace std { 16 | namespace experimental { 17 | inline namespace concurrency_v1 { 18 | 19 | template 20 | inline associated_allocator_t<_T> get_associated_allocator(const _T& __t) 21 | { 22 | return associated_allocator<_T>::get(__t); 23 | } 24 | 25 | template 26 | inline associated_allocator_t<_T, _Alloc> 27 | get_associated_allocator(const _T& __t, const _Alloc& __a) 28 | { 29 | return associated_allocator<_T, _Alloc>::get(__t, __a); 30 | } 31 | 32 | } // inline namespace concurrency_v1 33 | } // namespace experimental 34 | } // namespace std 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/experimental/bits/get_associated_executor.h: -------------------------------------------------------------------------------- 1 | // 2 | // get_associated_executor.h 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // Helper function to obtain an associated executor. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_GET_ASSOCIATED_EXECUTOR_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_GET_ASSOCIATED_EXECUTOR_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | struct __get_associated_executor_with_executor_result 23 | { 24 | typedef associated_executor_t<_T, _Executor> _Result; 25 | }; 26 | 27 | template 28 | struct __get_associated_executor_with_execution_context_result 29 | { 30 | typedef associated_executor_t<_T, typename _ExecutionContext::executor_type> _Result; 31 | }; 32 | 33 | struct __get_associated_executor_no_result {}; 34 | 35 | template 36 | struct __get_associated_executor_with_executor 37 | : conditional<__is_executor<_Executor>::value, 38 | __get_associated_executor_with_executor_result<_T, _Executor>, __get_associated_executor_no_result>::type 39 | { 40 | }; 41 | 42 | template 43 | struct __get_associated_executor_with_execution_context 44 | : conditional<__is_execution_context<_ExecutionContext>::value, 45 | __get_associated_executor_with_execution_context_result<_T, _ExecutionContext>, __get_associated_executor_no_result>::type 46 | { 47 | }; 48 | 49 | template 50 | inline associated_executor_t<_T> get_associated_executor(const _T& __t) 51 | { 52 | return associated_executor<_T>::get(__t); 53 | } 54 | 55 | template 56 | inline typename __get_associated_executor_with_executor<_T, _Executor>::_Result 57 | get_associated_executor(const _T& __t, const _Executor& __e) 58 | { 59 | return associated_executor<_T, _Executor>::get(__t, __e); 60 | } 61 | 62 | template 63 | inline typename __get_associated_executor_with_execution_context<_T, _ExecutionContext>::_Result 64 | get_associated_executor(const _T& __t, _ExecutionContext& __c) 65 | { 66 | return associated_executor<_T, typename _ExecutionContext::executor_type>::get(__t, __c.get_executor()); 67 | } 68 | 69 | } // inline namespace concurrency_v1 70 | } // namespace experimental 71 | } // namespace std 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /include/experimental/bits/operation.h: -------------------------------------------------------------------------------- 1 | // 2 | // operation.h 3 | // ~~~~~~~~~~~ 4 | // Base class and queue for all pending operations. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_OPERATION_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_OPERATION_H 14 | 15 | namespace std { 16 | namespace experimental { 17 | inline namespace concurrency_v1 { 18 | 19 | template class __op_queue; 20 | 21 | class __operation 22 | { 23 | public: 24 | virtual void _Destroy() = 0; 25 | virtual void _Complete() = 0; 26 | 27 | protected: 28 | __operation() : _M_next(0) {} 29 | virtual ~__operation() {} 30 | 31 | private: 32 | __operation* _M_next; 33 | template friend class __op_queue; 34 | }; 35 | 36 | template 37 | class __op_queue 38 | { 39 | public: 40 | __op_queue() : _M_front(0), _M_back(0) {} 41 | __op_queue(const __op_queue&) = delete; 42 | __op_queue& operator=(const __op_queue&) = delete; 43 | 44 | ~__op_queue() 45 | { 46 | while (_Operation* __op = _M_front) 47 | { 48 | _Pop(); 49 | __op->_Destroy(); 50 | } 51 | } 52 | 53 | _Operation* _Front() { return _M_front; } 54 | bool _Empty() const { return _M_front == 0; } 55 | 56 | void _Pop() 57 | { 58 | if (_Operation* __tmp = _M_front) 59 | { 60 | _M_front = static_cast<_Operation*>(__tmp->_M_next); 61 | if (_M_front == 0) 62 | _M_back = 0; 63 | __tmp->_M_next = 0; 64 | } 65 | } 66 | 67 | void _Push(_Operation* __op) 68 | { 69 | __op->_M_next = 0; 70 | if (_M_back) 71 | { 72 | _M_back->_M_next = __op; 73 | _M_back = __op; 74 | } 75 | else 76 | { 77 | _M_front = _M_back = __op; 78 | } 79 | } 80 | 81 | template 82 | void _Push(__op_queue<_OtherOperation>& __q) 83 | { 84 | if (_Operation* __other_front = __q._M_front) 85 | { 86 | if (_M_back) 87 | _M_back->_M_next = __other_front; 88 | else 89 | _M_front = __other_front; 90 | _M_back = __q._M_back; 91 | __q._M_front = __q._M_back = 0; 92 | } 93 | } 94 | 95 | private: 96 | _Operation* _M_front; 97 | _Operation* _M_back; 98 | template friend class __op_queue; 99 | }; 100 | 101 | } // inline namespace concurrency_v1 102 | } // namespace experimental 103 | } // namespace std 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /include/experimental/bits/packaged_task.h: -------------------------------------------------------------------------------- 1 | // 2 | // packaged_task.h 3 | // ~~~~~~~~~~~~~~~ 4 | // Support for packaged_task. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_PACKAGED_TASK_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_PACKAGED_TASK_H 14 | 15 | namespace std { 16 | namespace experimental { 17 | inline namespace concurrency_v1 { 18 | 19 | template 20 | struct handler_type, _R(_Args...)> 21 | { 22 | typedef packaged_handler::type(_Args...), _Alloc> type; 23 | }; 24 | 25 | template 26 | class async_result> 27 | : public async_result> 28 | { 29 | public: 30 | explicit async_result(packaged_handler<_Signature, _Alloc>& __h) 31 | : async_result>(__h) {} 32 | }; 33 | 34 | template 35 | inline packaged_token::type, _Alloc> package(_F&& __f, const _Alloc& __a) 36 | { 37 | return packaged_token::type, _Alloc>(forward<_F>(__f), __a); 38 | } 39 | 40 | template 41 | class async_result> 42 | { 43 | public: 44 | typedef future<_R> type; 45 | 46 | async_result(packaged_task<_R(_Args...)>& __h) 47 | : _M_future(__h.get_future()) {} 48 | async_result(const async_result&) = delete; 49 | async_result& operator=(const async_result&) = delete; 50 | 51 | type get() { return std::move(_M_future); } 52 | 53 | private: 54 | type _M_future; 55 | }; 56 | 57 | } // inline namespace concurrency_v1 58 | } // namespace experimental 59 | } // namespace std 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/experimental/bits/post.h: -------------------------------------------------------------------------------- 1 | // 2 | // post.h 3 | // ~~~~~~ 4 | // Schedule a function to run later. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_POST_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_POST_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | typename __invoke_with_token<_CompletionTokens...>::_Result 23 | post(_CompletionTokens&&... __tokens) 24 | { 25 | static_assert(sizeof...(_CompletionTokens) > 0, 26 | "post() must be called with one or more completion tokens"); 27 | 28 | typedef __passive_invoker _Invoker; 29 | 30 | _Invoker __head(__tokens...); 31 | async_result<_Invoker> __result(__head); 32 | 33 | auto __completion_executor(get_associated_executor(__head)); 34 | auto __completion_allocator(get_associated_allocator(__head)); 35 | __completion_executor.post(std::move(__head), __completion_allocator); 36 | 37 | return __result.get(); 38 | } 39 | 40 | template 41 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 42 | post(const _Executor& __e, _CompletionTokens&&... __tokens) 43 | { 44 | static_assert(sizeof...(_CompletionTokens) > 0, 45 | "post() must be called with one or more completion tokens"); 46 | 47 | typedef __active_invoker _Invoker; 48 | 49 | _Invoker __head(__tokens...); 50 | async_result<_Invoker> __result(__head); 51 | 52 | auto __completion_executor(__e); 53 | auto __completion_allocator(get_associated_allocator(__head)); 54 | __completion_executor.post(std::move(__head), __completion_allocator); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | post(_ExecutionContext& __c, _CompletionTokens&&... __tokens) 62 | { 63 | static_assert(sizeof...(_CompletionTokens) > 0, 64 | "post() must be called with one or more completion tokens"); 65 | 66 | typedef __active_invoker _Invoker; 67 | 68 | _Invoker __head(__tokens...); 69 | async_result<_Invoker> __result(__head); 70 | 71 | auto __completion_executor(__c.get_executor()); 72 | auto __completion_allocator(get_associated_allocator(__head)); 73 | __completion_executor.post(std::move(__head), __completion_allocator); 74 | 75 | return __result.get(); 76 | } 77 | 78 | } // inline namespace concurrency_v1 79 | } // namespace experimental 80 | } // namespace std 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/experimental/bits/post_after.h: -------------------------------------------------------------------------------- 1 | // 2 | // post_after.h 3 | // ~~~~~~~~~~~~ 4 | // Schedule a function to run at a relative time. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_POST_AFTER_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_POST_AFTER_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | typename __invoke_with_token<_CompletionTokens...>::_Result 24 | post_after(const chrono::duration<_Rep, _Period>& __rel_time, 25 | _CompletionTokens&&... __tokens) 26 | { 27 | static_assert(sizeof...(_CompletionTokens) > 0, 28 | "post_after() must be called with one or more completion tokens"); 29 | 30 | typedef __timed_invoker _Invoker; 31 | 32 | _Invoker __head(__tokens...); 33 | async_result __result(__head._Get_tail()); 34 | 35 | auto __completion_executor(get_associated_executor(__head._Get_tail())); 36 | __head._Start(__completion_executor, __rel_time); 37 | 38 | return __result.get(); 39 | } 40 | 41 | template 42 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 43 | post_after(const chrono::duration<_Rep, _Period>& __rel_time, 44 | const _Executor& __e, _CompletionTokens&&... __tokens) 45 | { 46 | static_assert(sizeof...(_CompletionTokens) > 0, 47 | "post_after() must be called with one or more completion tokens"); 48 | 49 | typedef __timed_invoker _Invoker; 50 | 51 | _Invoker __head(__tokens...); 52 | async_result __result(__head._Get_tail()); 53 | 54 | __head._Start(__e, __rel_time); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | post_after(const chrono::duration<_Rep, _Period>& __rel_time, 62 | _ExecutionContext& __c, _CompletionTokens&&... __tokens) 63 | { 64 | static_assert(sizeof...(_CompletionTokens) > 0, 65 | "post_after() must be called with one or more completion tokens"); 66 | 67 | typedef __timed_invoker _Invoker; 68 | 69 | _Invoker __head(__tokens...); 70 | async_result __result(__head._Get_tail()); 71 | 72 | __head._Start(__c.get_executor(), __rel_time); 73 | 74 | return __result.get(); 75 | } 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/experimental/bits/post_at.h: -------------------------------------------------------------------------------- 1 | // 2 | // post_at.h 3 | // ~~~~~~~~~ 4 | // Schedule a function to run at an absolute time. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_POST_AT_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_POST_AT_H 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | template 23 | typename __invoke_with_token<_CompletionTokens...>::_Result 24 | post_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 25 | _CompletionTokens&&... __tokens) 26 | { 27 | static_assert(sizeof...(_CompletionTokens) > 0, 28 | "post_at() must be called with one or more completion tokens"); 29 | 30 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 31 | 32 | _Invoker __head(__tokens...); 33 | async_result __result(__head._Get_tail()); 34 | 35 | auto __completion_executor(get_associated_executor(__head._Get_tail())); 36 | __head._Start(__completion_executor, __abs_time); 37 | 38 | return __result.get(); 39 | } 40 | 41 | template 42 | typename __invoke_with_executor<_Executor, _CompletionTokens...>::_Result 43 | post_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 44 | const _Executor& __e, _CompletionTokens&&... __tokens) 45 | { 46 | static_assert(sizeof...(_CompletionTokens) > 0, 47 | "post_at() must be called with one or more completion tokens"); 48 | 49 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 50 | 51 | _Invoker __head(__tokens...); 52 | async_result __result(__head._Get_tail()); 53 | 54 | __head._Start(__e, __abs_time); 55 | 56 | return __result.get(); 57 | } 58 | 59 | template 60 | typename __invoke_with_execution_context<_ExecutionContext, _CompletionTokens...>::_Result 61 | post_at(const chrono::time_point<_Clock, _Duration>& __abs_time, 62 | _ExecutionContext& __c, _CompletionTokens&&... __tokens) 63 | { 64 | static_assert(sizeof...(_CompletionTokens) > 0, 65 | "post_at() must be called with one or more completion tokens"); 66 | 67 | typedef __timed_invoker<_Clock, _CompletionTokens...> _Invoker; 68 | 69 | _Invoker __head(__tokens...); 70 | async_result __result(__head._Get_tail()); 71 | 72 | __head._Start(__c.get_executor(), __abs_time); 73 | 74 | return __result.get(); 75 | } 76 | 77 | } // inline namespace concurrency_v1 78 | } // namespace experimental 79 | } // namespace std 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/experimental/bits/timed_invoker.h: -------------------------------------------------------------------------------- 1 | // 2 | // timed_invoker.h 3 | // ~~~~~~~~~~~~~~~ 4 | // Function object to invoke another function object after a delay. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_TIMED_INVOKER_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_TIMED_INVOKER_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | class __timed_invoker 23 | { 24 | public: 25 | typedef __active_invoker _Tail; 26 | 27 | __timed_invoker(typename remove_reference<_CompletionTokens>::type&... __tokens) 28 | : _M_tail(__tokens...) 29 | { 30 | } 31 | 32 | template 33 | void _Start(const _Executor& __e, const _Time& __t) 34 | { 35 | _M_timer.reset(new basic_timer<_Clock>(_Executor(__e).context(), __t)); 36 | basic_timer<_Clock>* __timer = _M_timer.get(); 37 | __timer->wait((wrap)(__e, std::move(*this))); 38 | } 39 | 40 | void operator()(const error_code&) 41 | { 42 | std::move(_M_tail)(); 43 | } 44 | 45 | _Tail& _Get_tail() noexcept 46 | { 47 | return _M_tail; 48 | } 49 | 50 | private: 51 | unique_ptr> _M_timer; 52 | _Tail _M_tail; 53 | }; 54 | 55 | } // inline namespace concurrency_v1 56 | } // namespace experimental 57 | } // namespace std 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/experimental/bits/wait_op.h: -------------------------------------------------------------------------------- 1 | // 2 | // wait_op.h 3 | // ~~~~~~~~~ 4 | // Timer wait operation. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_WAIT_OP_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_WAIT_OP_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace std { 22 | namespace experimental { 23 | inline namespace concurrency_v1 { 24 | 25 | class __wait_op_base 26 | : public __operation 27 | { 28 | protected: 29 | template friend class __timer_queue; 30 | error_code _M_ec; 31 | }; 32 | 33 | template 34 | class __wait_op 35 | : public __wait_op_base 36 | { 37 | public: 38 | template explicit __wait_op(_F&& __f) 39 | : _M_func(forward<_F>(__f)), _M_work(get_associated_executor(_M_func)) 40 | { 41 | } 42 | 43 | virtual void _Complete() 44 | { 45 | auto __allocator(get_associated_allocator(_M_func)); 46 | auto __op(_Adopt_small_block(__allocator, this)); 47 | executor_work<_Executor> __work(std::move(_M_work)); 48 | _Executor __executor(__work.get_executor()); 49 | auto __i(_Make_tuple_invoker(std::move(_M_func), _M_ec)); 50 | __op.reset(); 51 | __executor.post(std::move(__i), __allocator); 52 | } 53 | 54 | virtual void _Destroy() 55 | { 56 | auto __allocator(get_associated_allocator(_M_func)); 57 | _Adopt_small_block(__allocator, this); 58 | } 59 | 60 | private: 61 | _Func _M_func; 62 | typedef associated_executor_t<_Func> _Executor; 63 | executor_work<_Executor> _M_work; 64 | }; 65 | 66 | } // inline namespace concurrency_v1 67 | } // namespace experimental 68 | } // namespace std 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /include/experimental/bits/wrap.h: -------------------------------------------------------------------------------- 1 | // 2 | // wrap.h 3 | // ~~~~~~ 4 | // Associate an executor with an object. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_BITS_WRAP_H 13 | #define EXECUTORS_EXPERIMENTAL_BITS_WRAP_H 14 | 15 | #include 16 | 17 | namespace std { 18 | namespace experimental { 19 | inline namespace concurrency_v1 { 20 | 21 | template 22 | struct __wrap_with_executor_result 23 | { 24 | typedef executor_wrapper::type, _Executor> _Result; 25 | }; 26 | 27 | template 28 | struct __wrap_with_execution_context_result 29 | { 30 | typedef executor_wrapper::type, 31 | typename _ExecutionContext::executor_type> _Result; 32 | }; 33 | 34 | struct __wrap_no_result {}; 35 | 36 | template 37 | struct __wrap_with_executor 38 | : conditional<__is_executor<_Executor>::value, 39 | __wrap_with_executor_result<_Executor, _T>, __wrap_no_result>::type 40 | { 41 | }; 42 | 43 | template 44 | struct __wrap_with_execution_context 45 | : conditional<__is_execution_context<_ExecutionContext>::value, 46 | __wrap_with_execution_context_result<_ExecutionContext, _T>, __wrap_no_result>::type 47 | { 48 | }; 49 | 50 | template 51 | inline typename __wrap_with_executor<_Executor, _T>::_Result 52 | wrap(const _Executor& __e, _T&& __t) 53 | { 54 | return executor_wrapper::type, _Executor>(forward<_T>(__t), __e); 55 | } 56 | 57 | template 58 | inline typename __wrap_with_execution_context<_ExecutionContext, _T>::_Result 59 | wrap(_ExecutionContext& __c, _T&& __t) 60 | { 61 | return executor_wrapper::type, 62 | typename _ExecutionContext::executor_type>(forward<_T>(__t), __c.get_executor()); 63 | } 64 | 65 | } // inline namespace concurrency_v1 66 | } // namespace experimental 67 | } // namespace std 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/experimental/memory: -------------------------------------------------------------------------------- 1 | // 2 | // memory 3 | // ~~~~~~ 4 | // Function to obtain a function objects associated allocator. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_MEMORY_HEADER 13 | #define EXECUTORS_EXPERIMENTAL_MEMORY_HEADER 14 | 15 | #include 16 | #include 17 | 18 | namespace std { 19 | namespace experimental { 20 | inline namespace concurrency_v1 { 21 | 22 | // Trait used to obtain an object's associated allocator. 23 | 24 | template > 25 | struct associated_allocator 26 | { 27 | typedef typename __associated_allocator<_T, _Alloc>::_Type type; 28 | 29 | static type get(const _T& __t, const _Alloc& __a = _Alloc()) noexcept 30 | { 31 | return __associated_allocator<_T, _Alloc>::_Get(__t, __a); 32 | } 33 | }; 34 | 35 | template > 36 | using associated_allocator_t = typename associated_allocator<_T, _Alloc>::type; 37 | 38 | // Helper function to obtain an associated allocator. 39 | 40 | template 41 | associated_allocator_t<_T> get_associated_allocator(const _T& __t); 42 | template 43 | associated_allocator_t<_T, _Alloc> 44 | get_associated_allocator(const _T& __t, const _Alloc& __a); 45 | 46 | } // inline namespace concurrency_v1 47 | } // namespace experimental 48 | } // namespace std 49 | 50 | #include 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/experimental/strand: -------------------------------------------------------------------------------- 1 | // 2 | // strand 3 | // ~~~~~~ 4 | // Strand used for preventing non-concurrent invocation of handlers. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_STRAND_HEADER 13 | #define EXECUTORS_EXPERIMENTAL_STRAND_HEADER 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace std { 20 | namespace experimental { 21 | inline namespace concurrency_v1 { 22 | 23 | struct __strand_impl; 24 | 25 | template 26 | class strand 27 | { 28 | public: 29 | typedef _Executor inner_executor_type; 30 | 31 | // construct / copy / destroy: 32 | 33 | template strand(_Dummy = 0, 34 | typename enable_if::value, _Dummy>::type* = 0); 35 | explicit strand(_Executor __e); 36 | strand(const strand& __s); 37 | strand(strand&& __s); 38 | template strand(const strand<_OtherExecutor>& __s); 39 | template strand(strand<_OtherExecutor>&& __s); 40 | 41 | strand& operator=(const strand& __s); 42 | strand& operator=(strand&& __s); 43 | template strand& operator=(const strand<_OtherExecutor>& __s); 44 | template strand& operator=(strand<_OtherExecutor>&& __s); 45 | 46 | ~strand(); 47 | 48 | // executor operations: 49 | 50 | inner_executor_type get_inner_executor() const noexcept; 51 | 52 | bool running_in_this_thread() const noexcept; 53 | 54 | execution_context& context() noexcept; 55 | 56 | void on_work_started() noexcept; 57 | void on_work_finished() noexcept; 58 | 59 | template 60 | void dispatch(_Func&& __f, const _Alloc& a); 61 | template 62 | void post(_Func&& __f, const _Alloc& a); 63 | template 64 | void defer(_Func&& __f, const _Alloc& a); 65 | 66 | private: 67 | template friend class strand; 68 | template friend bool operator==(const strand<_E>&, const strand<_E>&) noexcept; 69 | friend class work; 70 | strand(const _Executor& __e, const shared_ptr<__strand_impl>& __i); 71 | _Executor _M_executor; 72 | shared_ptr<__strand_impl> _M_impl; 73 | }; 74 | 75 | template 76 | bool operator==(const strand<_Executor>& __a, const strand<_Executor>& __b) noexcept; 77 | template 78 | bool operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b) noexcept; 79 | 80 | template struct is_executor> : true_type {}; 81 | 82 | template auto make_strand(_T&& __t); 83 | 84 | } // inline namespace concurrency_v1 85 | } // namespace experimental 86 | } // namespace std 87 | 88 | #include 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /include/experimental/thread_pool: -------------------------------------------------------------------------------- 1 | // 2 | // thread_pool 3 | // ~~~~~~~~~~~ 4 | // Simple thread pool. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_THREAD_POOL_HEADER 13 | #define EXECUTORS_EXPERIMENTAL_THREAD_POOL_HEADER 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace std { 21 | namespace experimental { 22 | inline namespace concurrency_v1 { 23 | 24 | // Thread pool. 25 | 26 | class thread_pool 27 | : public execution_context, 28 | private __scheduler 29 | { 30 | public: 31 | class executor_type; 32 | 33 | // construct / copy / destroy: 34 | 35 | thread_pool(); 36 | explicit thread_pool(size_t __num_threads); 37 | thread_pool(const thread_pool&) = delete; 38 | thread_pool& operator=(const thread_pool&) = delete; 39 | ~thread_pool(); 40 | 41 | // thread pool operations: 42 | 43 | executor_type get_executor() const noexcept; 44 | 45 | void stop(); 46 | void join(); 47 | 48 | private: 49 | vector _M_threads; 50 | }; 51 | 52 | class thread_pool::executor_type 53 | { 54 | public: 55 | // construct / copy / destroy: 56 | 57 | executor_type(const executor_type& __e) noexcept = default; 58 | executor_type(executor_type&& __e) noexcept = default; 59 | executor_type& operator=(const executor_type& __e) noexcept = default; 60 | executor_type& operator=(executor_type&& __e) noexcept = default; 61 | ~executor_type() = default; 62 | 63 | // executor operations: 64 | 65 | bool running_in_this_thread() const noexcept; 66 | 67 | thread_pool& context() noexcept; 68 | 69 | void on_work_started() noexcept; 70 | void on_work_finished() noexcept; 71 | 72 | template 73 | void dispatch(_Func&& __f, const _Alloc& a); 74 | template 75 | void post(_Func&& __f, const _Alloc& a); 76 | template 77 | void defer(_Func&& __f, const _Alloc& a); 78 | 79 | private: 80 | friend class thread_pool; 81 | friend bool operator==(const executor_type&, const executor_type&) noexcept; 82 | explicit executor_type(thread_pool* __p) : _M_pool(__p) {} 83 | thread_pool* _M_pool; 84 | }; 85 | 86 | bool operator==(const thread_pool::executor_type& __a, 87 | const thread_pool::executor_type& __b) noexcept; 88 | bool operator!=(const thread_pool::executor_type& __a, 89 | const thread_pool::executor_type& __b) noexcept; 90 | 91 | template <> struct is_executor : true_type {}; 92 | 93 | } // inline namespace concurrency_v1 94 | } // namespace experimental 95 | } // namespace std 96 | 97 | #include 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /include/experimental/yield: -------------------------------------------------------------------------------- 1 | // 2 | // yield 3 | // ~~~~~ 4 | // Stackful coroutines / resumable functions. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef EXECUTORS_EXPERIMENTAL_YIELD_HEADER 13 | #define EXECUTORS_EXPERIMENTAL_YIELD_HEADER 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace std { 21 | namespace experimental { 22 | inline namespace concurrency_v1 { 23 | 24 | struct __yield_context_caller; 25 | struct __yield_context_callee; 26 | 27 | // Context object used to represent the currently executing coroutine. 28 | 29 | template 30 | class basic_yield_context 31 | { 32 | public: 33 | typedef _Executor executor_type; 34 | 35 | // construct / copy / destroy: 36 | 37 | template 38 | basic_yield_context(const basic_yield_context<_OtherExecutor>&); 39 | 40 | // basic_yield_context operations: 41 | 42 | executor_type get_executor() const noexcept; 43 | basic_yield_context operator[](error_code& __ec) const; 44 | 45 | private: 46 | template friend class basic_yield_context; 47 | template friend struct __yield_context_handler; 48 | template friend struct __yield_context_entry_point; 49 | 50 | basic_yield_context(const _Executor& __e) : _M_executor(__e), _M_error_code(nullptr) {} 51 | 52 | _Executor _M_executor; 53 | weak_ptr<__yield_context_callee> _M_callee; 54 | __yield_context_caller* _M_caller; 55 | error_code* _M_error_code; 56 | }; 57 | 58 | template 59 | struct handler_type, _R(_Args...)>; 60 | 61 | typedef basic_yield_context yield_context; 62 | 63 | } // inline namespace concurrency_v1 64 | } // namespace experimental 65 | } // namespace std 66 | 67 | #include 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = examples tests 2 | 3 | MAINTAINERCLEANFILES = \ 4 | $(srcdir)/Makefile.in 5 | -------------------------------------------------------------------------------- /src/examples/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = \ 2 | channel \ 3 | executor \ 4 | trading \ 5 | timer 6 | 7 | MAINTAINERCLEANFILES = \ 8 | $(srcdir)/Makefile.in 9 | -------------------------------------------------------------------------------- /src/examples/channel/.gitignore: -------------------------------------------------------------------------------- 1 | ping 2 | pingpong 3 | pingvoid 4 | -------------------------------------------------------------------------------- /src/examples/channel/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | ping \ 3 | pingpong \ 4 | pingvoid 5 | 6 | AM_CXXFLAGS = -I$(srcdir)/../../../include 7 | 8 | ping_SOURCES = ping.cpp 9 | pingpong_SOURCES = pingpong.cpp 10 | pingvoid_SOURCES = pingvoid.cpp 11 | 12 | MAINTAINERCLEANFILES = \ 13 | $(srcdir)/Makefile.in 14 | -------------------------------------------------------------------------------- /src/examples/channel/ping.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::channel; 10 | using std::experimental::dispatch; 11 | using std::experimental::dispatch_after; 12 | using std::experimental::strand; 13 | using std::experimental::system_executor; 14 | using std::experimental::wrap; 15 | using std::experimental::yield_context; 16 | 17 | void pinger(std::shared_ptr> c, yield_context yield) 18 | { 19 | for (;;) 20 | { 21 | c->put("ping", yield); 22 | } 23 | } 24 | 25 | void printer(std::shared_ptr> c, yield_context yield) 26 | { 27 | for (;;) 28 | { 29 | std::string msg = c->get(yield); 30 | std::cout << msg << std::endl; 31 | dispatch_after(std::chrono::seconds(1), yield); 32 | } 33 | } 34 | 35 | int main() 36 | { 37 | auto c = std::make_shared>(); 38 | strand s; 39 | 40 | dispatch(wrap(s, [c](yield_context yield){ pinger(c, yield); })); 41 | dispatch(wrap(s, [c](yield_context yield){ printer(c, yield); })); 42 | 43 | std::string input; 44 | std::getline(std::cin, input); 45 | } 46 | -------------------------------------------------------------------------------- /src/examples/channel/pingpong.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::channel; 10 | using std::experimental::dispatch; 11 | using std::experimental::dispatch_after; 12 | using std::experimental::strand; 13 | using std::experimental::system_executor; 14 | using std::experimental::wrap; 15 | using std::experimental::yield_context; 16 | 17 | void pinger(std::shared_ptr> c, yield_context yield) 18 | { 19 | for (;;) 20 | { 21 | c->put("ping", yield); 22 | } 23 | } 24 | 25 | void ponger(std::shared_ptr> c, yield_context yield) 26 | { 27 | for (;;) 28 | { 29 | c->put("pong", yield); 30 | } 31 | } 32 | 33 | void printer(std::shared_ptr> c, yield_context yield) 34 | { 35 | for (;;) 36 | { 37 | std::string msg = c->get(yield); 38 | std::cout << msg << std::endl; 39 | dispatch_after(std::chrono::seconds(1), yield); 40 | } 41 | } 42 | 43 | int main() 44 | { 45 | auto c = std::make_shared>(); 46 | strand s; 47 | 48 | dispatch(wrap(s, [c](yield_context yield){ pinger(c, yield); })); 49 | dispatch(wrap(s, [c](yield_context yield){ ponger(c, yield); })); 50 | dispatch(wrap(s, [c](yield_context yield){ printer(c, yield); })); 51 | 52 | std::string input; 53 | std::getline(std::cin, input); 54 | } 55 | -------------------------------------------------------------------------------- /src/examples/channel/pingvoid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::channel; 10 | using std::experimental::dispatch; 11 | using std::experimental::dispatch_after; 12 | using std::experimental::strand; 13 | using std::experimental::system_executor; 14 | using std::experimental::wrap; 15 | using std::experimental::yield_context; 16 | 17 | void pinger(std::shared_ptr> c, yield_context yield) 18 | { 19 | for (;;) 20 | { 21 | c->put(yield); 22 | } 23 | } 24 | 25 | void printer(std::shared_ptr> c, yield_context yield) 26 | { 27 | for (;;) 28 | { 29 | c->get(yield); 30 | std::cout << "void" << std::endl; 31 | dispatch_after(std::chrono::seconds(1), yield); 32 | } 33 | } 34 | 35 | int main() 36 | { 37 | auto c = std::make_shared>(); 38 | strand s; 39 | 40 | dispatch(wrap(s, [c](yield_context yield){ pinger(c, yield); })); 41 | dispatch(wrap(s, [c](yield_context yield){ printer(c, yield); })); 42 | 43 | std::string input; 44 | std::getline(std::cin, input); 45 | } 46 | -------------------------------------------------------------------------------- /src/examples/executor/.gitignore: -------------------------------------------------------------------------------- 1 | actor 2 | async_1 3 | async_op_1 4 | async_op_2 5 | bank_account_1 6 | bank_account_2 7 | bank_account_3 8 | bank_account_4 9 | bank_account_5 10 | bank_account_6 11 | bank_account_7 12 | bank_account_8 13 | bank_account_9 14 | bank_account_10 15 | fork_join 16 | pipeline 17 | post_1 18 | post_2 19 | post_3 20 | post_4 21 | post_5 22 | priority_scheduler 23 | sort_1 24 | sort_2 25 | sort_3 26 | sort_4 27 | sort_5 28 | sort_6 29 | sort_7 30 | -------------------------------------------------------------------------------- /src/examples/executor/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | actor \ 3 | async_1 \ 4 | async_op_1 \ 5 | async_op_2 \ 6 | bank_account_1 \ 7 | bank_account_2 \ 8 | bank_account_3 \ 9 | bank_account_4 \ 10 | bank_account_5 \ 11 | bank_account_6 \ 12 | bank_account_7 \ 13 | bank_account_8 \ 14 | bank_account_9 \ 15 | bank_account_10 \ 16 | fork_join \ 17 | pipeline \ 18 | post_1 \ 19 | post_2 \ 20 | post_3 \ 21 | post_4 \ 22 | post_5 \ 23 | priority_scheduler \ 24 | sort_1 \ 25 | sort_2 \ 26 | sort_3 \ 27 | sort_4 \ 28 | sort_5 \ 29 | sort_6 \ 30 | sort_7 31 | 32 | AM_CXXFLAGS = -I$(srcdir)/../../../include 33 | 34 | actor_SOURCES = actor.cpp 35 | async_1_SOURCES = async_1.cpp 36 | async_op_1_SOURCES = async_op_1.cpp 37 | async_op_2_SOURCES = async_op_2.cpp 38 | bank_account_1_SOURCES = bank_account_1.cpp 39 | bank_account_2_SOURCES = bank_account_2.cpp 40 | bank_account_3_SOURCES = bank_account_3.cpp 41 | bank_account_4_SOURCES = bank_account_4.cpp 42 | bank_account_5_SOURCES = bank_account_5.cpp 43 | bank_account_6_SOURCES = bank_account_6.cpp 44 | bank_account_7_SOURCES = bank_account_7.cpp 45 | bank_account_8_SOURCES = bank_account_8.cpp 46 | bank_account_9_SOURCES = bank_account_9.cpp 47 | bank_account_10_SOURCES = bank_account_10.cpp 48 | fork_join_SOURCES = fork_join.cpp 49 | pipeline_SOURCES = pipeline.cpp 50 | post_1_SOURCES = post_1.cpp 51 | post_2_SOURCES = post_2.cpp 52 | post_3_SOURCES = post_3.cpp 53 | post_4_SOURCES = post_4.cpp 54 | post_5_SOURCES = post_5.cpp 55 | priority_scheduler_SOURCES = priority_scheduler.cpp 56 | sort_1_SOURCES = sort_1.cpp 57 | sort_2_SOURCES = sort_2.cpp 58 | sort_3_SOURCES = sort_3.cpp 59 | sort_4_SOURCES = sort_4.cpp 60 | sort_5_SOURCES = sort_5.cpp 61 | sort_6_SOURCES = sort_6.cpp 62 | sort_7_SOURCES = sort_7.cpp 63 | 64 | MAINTAINERCLEANFILES = \ 65 | $(srcdir)/Makefile.in 66 | -------------------------------------------------------------------------------- /src/examples/executor/async_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using std::experimental::post; 8 | using std::experimental::package; 9 | 10 | // Emulate std::async() when used with launch::async. 11 | template 12 | auto async(F&& f, Args&&... args) 13 | { 14 | return post( 15 | package( 16 | std::bind(std::forward(f), 17 | std::forward(args)...))); 18 | } 19 | 20 | int main() 21 | { 22 | std::future fut = async( 23 | []{ 24 | std::cout << "Enter a line: "; 25 | std::string s; 26 | std::getline(std::cin, s); 27 | return s; 28 | }); 29 | 30 | // Do something else here... 31 | 32 | std::cout << fut.get() << std::endl; 33 | } 34 | -------------------------------------------------------------------------------- /src/examples/executor/async_op_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using std::experimental::dispatch; 8 | using std::experimental::loop_scheduler;; 9 | using std::experimental::make_work; 10 | using std::experimental::post; 11 | using std::experimental::thread_pool; 12 | using std::experimental::wrap; 13 | 14 | // A function to asynchronously read a single line from an input stream. 15 | template 16 | void async_getline(std::istream& is, Handler handler) 17 | { 18 | // Create executor_work for the handler's associated executor. 19 | auto work = make_work(handler); 20 | 21 | // Post a function object to do the work asynchronously. 22 | post([&is, work, handler=std::move(handler)]() mutable 23 | { 24 | std::string line; 25 | std::getline(is, line); 26 | 27 | // Pass the result to the handler, via the associated executor. 28 | dispatch(work.get_executor(), 29 | [line=std::move(line), handler=std::move(handler)]() mutable 30 | { 31 | handler(std::move(line)); 32 | }); 33 | }); 34 | } 35 | 36 | class line_printer 37 | { 38 | public: 39 | typedef loop_scheduler::executor_type executor_type; 40 | 41 | explicit line_printer(loop_scheduler& s) 42 | : executor_(s.get_executor()) 43 | { 44 | } 45 | 46 | executor_type get_executor() const noexcept 47 | { 48 | return executor_; 49 | } 50 | 51 | void operator()(std::string line) 52 | { 53 | std::cout << "Line: " << line << "\n"; 54 | } 55 | 56 | private: 57 | loop_scheduler::executor_type executor_; 58 | }; 59 | 60 | int main() 61 | { 62 | thread_pool pool; 63 | 64 | std::cout << "Enter a line: "; 65 | 66 | async_getline(std::cin, 67 | wrap(pool, [](std::string line) 68 | { 69 | std::cout << "Line: " << line << "\n"; 70 | })); 71 | 72 | pool.join(); 73 | 74 | loop_scheduler scheduler; 75 | 76 | std::cout << "Enter another line: "; 77 | 78 | async_getline(std::cin, line_printer(scheduler)); 79 | 80 | scheduler.run(); 81 | } 82 | -------------------------------------------------------------------------------- /src/examples/executor/bank_account_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::experimental::post; 5 | using std::experimental::thread_pool; 6 | 7 | // Traditional active object pattern. 8 | // Member functions do not block. 9 | 10 | class bank_account 11 | { 12 | int balance_ = 0; 13 | mutable thread_pool pool_{1}; 14 | 15 | public: 16 | void deposit(int amount) 17 | { 18 | post(pool_, [=] 19 | { 20 | balance_ += amount; 21 | }); 22 | } 23 | 24 | void withdraw(int amount) 25 | { 26 | post(pool_, [=] 27 | { 28 | if (balance_ >= amount) 29 | balance_ -= amount; 30 | }); 31 | } 32 | 33 | void print_balance() const 34 | { 35 | post(pool_, [=] 36 | { 37 | std::cout << "balance = " << balance_ << "\n"; 38 | }); 39 | } 40 | 41 | ~bank_account() 42 | { 43 | pool_.join(); 44 | } 45 | }; 46 | 47 | int main() 48 | { 49 | bank_account acct; 50 | acct.deposit(20); 51 | acct.withdraw(10); 52 | acct.print_balance(); 53 | } 54 | -------------------------------------------------------------------------------- /src/examples/executor/bank_account_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::package; 7 | using std::experimental::post; 8 | using std::experimental::thread_pool; 9 | 10 | // Traditional active object pattern. 11 | // Member functions block until operation is finished. 12 | 13 | class bank_account 14 | { 15 | int balance_ = 0; 16 | mutable thread_pool pool_{1}; 17 | 18 | public: 19 | void deposit(int amount) 20 | { 21 | post(pool_, 22 | package([=] 23 | { 24 | balance_ += amount; 25 | })).get(); 26 | } 27 | 28 | void withdraw(int amount) 29 | { 30 | post(pool_, 31 | package([=] 32 | { 33 | if (balance_ >= amount) 34 | balance_ -= amount; 35 | })).get(); 36 | } 37 | 38 | int balance() const 39 | { 40 | return post(pool_, 41 | package([=] 42 | { 43 | return balance_; 44 | })).get(); 45 | } 46 | }; 47 | 48 | int main() 49 | { 50 | bank_account acct; 51 | acct.deposit(20); 52 | acct.withdraw(10); 53 | std::cout << "balance = " << acct.balance() << "\n"; 54 | } 55 | -------------------------------------------------------------------------------- /src/examples/executor/bank_account_3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::dispatch; 7 | using std::experimental::package; 8 | using std::experimental::strand; 9 | using std::experimental::system_executor; 10 | 11 | // Active object sharing a system-wide pool of threads. 12 | // Member functions block until operation is finished. 13 | 14 | class bank_account 15 | { 16 | int balance_ = 0; 17 | mutable strand strand_; 18 | 19 | public: 20 | void deposit(int amount) 21 | { 22 | dispatch(strand_, 23 | package([=] 24 | { 25 | balance_ += amount; 26 | })).get(); 27 | } 28 | 29 | void withdraw(int amount) 30 | { 31 | dispatch(strand_, 32 | package([=] 33 | { 34 | if (balance_ >= amount) 35 | balance_ -= amount; 36 | })).get(); 37 | } 38 | 39 | int balance() const 40 | { 41 | return dispatch(strand_, 42 | package([=] 43 | { 44 | return balance_; 45 | })).get(); 46 | } 47 | }; 48 | 49 | int main() 50 | { 51 | bank_account acct; 52 | acct.deposit(20); 53 | acct.withdraw(10); 54 | std::cout << "balance = " << acct.balance() << "\n"; 55 | } 56 | -------------------------------------------------------------------------------- /src/examples/executor/bank_account_4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::post; 7 | using std::experimental::thread_pool; 8 | using std::experimental::use_future; 9 | 10 | // Traditional active object pattern. 11 | // The caller chooses how to wait for the operation to finish. 12 | 13 | class bank_account 14 | { 15 | int balance_ = 0; 16 | mutable thread_pool pool_{1}; 17 | 18 | public: 19 | template 20 | auto deposit(int amount, CompletionToken&& token) 21 | { 22 | return post(pool_, [=] 23 | { 24 | balance_ += amount; 25 | }, 26 | std::forward(token)); 27 | } 28 | 29 | template 30 | auto withdraw(int amount, CompletionToken&& token) 31 | { 32 | return post(pool_, [=] 33 | { 34 | if (balance_ >= amount) 35 | balance_ -= amount; 36 | }, 37 | std::forward(token)); 38 | } 39 | 40 | template 41 | auto balance(CompletionToken&& token) const 42 | { 43 | return post(pool_, [=] 44 | { 45 | return balance_; 46 | }, 47 | std::forward(token)); 48 | } 49 | }; 50 | 51 | int main() 52 | { 53 | bank_account acct1; 54 | acct1.deposit(20, []{ std::cout << "deposit complete\n"; }); 55 | acct1.withdraw(10, []{ std::cout << "withdraw complete\n"; }); 56 | acct1.balance([](int b){ std::cout << "balance = " << b << "\n"; }); 57 | 58 | bank_account acct2; 59 | acct2.deposit(40, use_future).get(); 60 | acct2.withdraw(15, use_future).get(); 61 | std::cout << "balance = " << acct2.balance(use_future).get() << "\n"; 62 | } 63 | -------------------------------------------------------------------------------- /src/examples/executor/bank_account_5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::dispatch; 7 | using std::experimental::strand; 8 | using std::experimental::system_executor; 9 | using std::experimental::use_future; 10 | 11 | // Active object sharing a system-wide pool of threads. 12 | // The caller chooses how to wait for the operation to finish. 13 | // Lightweight, immediate execution using dispatch. 14 | 15 | class bank_account 16 | { 17 | int balance_ = 0; 18 | mutable strand strand_; 19 | 20 | public: 21 | template 22 | auto deposit(int amount, CompletionToken&& token) 23 | { 24 | return dispatch(strand_, [=] 25 | { 26 | balance_ += amount; 27 | }, 28 | std::forward(token)); 29 | } 30 | 31 | template 32 | auto withdraw(int amount, CompletionToken&& token) 33 | { 34 | return dispatch(strand_, [=] 35 | { 36 | if (balance_ >= amount) 37 | balance_ -= amount; 38 | }, 39 | std::forward(token)); 40 | } 41 | 42 | template 43 | auto balance(CompletionToken&& token) const 44 | { 45 | return dispatch(strand_, [=] 46 | { 47 | return balance_; 48 | }, 49 | std::forward(token)); 50 | } 51 | }; 52 | 53 | int main() 54 | { 55 | bank_account acct1; 56 | acct1.deposit(20, []{ std::cout << "deposit complete\n"; }); 57 | acct1.withdraw(10, []{ std::cout << "withdraw complete\n"; }); 58 | acct1.balance([](int b){ std::cout << "balance = " << b << "\n"; }); 59 | 60 | bank_account acct2; 61 | acct2.deposit(40, use_future).get(); 62 | acct2.withdraw(15, use_future).get(); 63 | std::cout << "balance = " << acct2.balance(use_future).get() << "\n"; 64 | } 65 | -------------------------------------------------------------------------------- /src/examples/executor/bank_account_6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using std::experimental::dispatch; 6 | using std::experimental::strand; 7 | using std::experimental::system_executor; 8 | using std::experimental::use_future; 9 | using std::experimental::wrap; 10 | 11 | // Active object sharing a system-wide pool of threads. 12 | // The caller chooses how to wait for the operation to finish. 13 | // Lightweight, immediate execution using dispatch. 14 | // Composition using variadic dispatch. 15 | 16 | class bank_account 17 | { 18 | int balance_ = 0; 19 | mutable strand ex_; 20 | 21 | public: 22 | template 23 | auto deposit(int amount, CompletionToken&& token) 24 | { 25 | return dispatch(ex_, [=] 26 | { 27 | balance_ += amount; 28 | }, 29 | std::forward(token)); 30 | } 31 | 32 | template 33 | auto withdraw(int amount, CompletionToken&& token) 34 | { 35 | return dispatch(ex_, [=] 36 | { 37 | if (balance_ >= amount) 38 | balance_ -= amount; 39 | }, 40 | std::forward(token)); 41 | } 42 | 43 | template 44 | auto balance(CompletionToken&& token) const 45 | { 46 | return dispatch(ex_, [=] 47 | { 48 | return balance_; 49 | }, 50 | std::forward(token)); 51 | } 52 | 53 | template 54 | auto transfer(int amount, bank_account& to_acct, CompletionToken&& token) 55 | { 56 | return dispatch( 57 | wrap(ex_, [=] 58 | { 59 | if (balance_ >= amount) 60 | { 61 | balance_ -= amount; 62 | return amount; 63 | } 64 | 65 | return 0; 66 | }), 67 | wrap(to_acct.ex_, 68 | [&to_acct](int deducted) 69 | { 70 | to_acct.balance_ += deducted; 71 | }), 72 | std::forward(token)); 73 | } 74 | }; 75 | 76 | int main() 77 | { 78 | bank_account acct1, acct2; 79 | acct1.deposit(20, use_future).get(); 80 | acct2.deposit(30, use_future).get(); 81 | acct1.withdraw(10, use_future).get(); 82 | acct2.transfer(5, acct1, use_future).get(); 83 | std::cout << "Account 1 balance = " << acct1.balance(use_future).get() << "\n"; 84 | std::cout << "Account 2 balance = " << acct2.balance(use_future).get() << "\n"; 85 | } 86 | -------------------------------------------------------------------------------- /src/examples/executor/post_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::post; 10 | 11 | class latch 12 | { 13 | public: 14 | explicit latch(std::size_t initial_count) 15 | : count_(initial_count) 16 | { 17 | } 18 | 19 | void arrive() 20 | { 21 | std::unique_lock lock(mutex_); 22 | assert(count_ > 0); 23 | if (--count_ == 0) 24 | condition_.notify_all(); 25 | } 26 | 27 | void wait() 28 | { 29 | std::unique_lock lock(mutex_); 30 | condition_.wait(lock, [this]{ return count_ == 0; }); 31 | } 32 | 33 | private: 34 | std::mutex mutex_; 35 | std::condition_variable condition_; 36 | std::size_t count_; 37 | }; 38 | 39 | struct work 40 | { 41 | }; 42 | 43 | void do_something(const work&) 44 | { 45 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 46 | } 47 | 48 | int main(int argc, char* argv[]) 49 | { 50 | if (argc != 2) 51 | { 52 | std::cerr << "Usage: post_1 \n"; 53 | return 1; 54 | } 55 | 56 | std::vector work_list(std::atoi(argv[1])); 57 | 58 | // Start a bunch of asynchronous tasks and wait for them to complete. 59 | latch l(work_list.size()); 60 | for (auto work: work_list) 61 | { 62 | post( 63 | [work, &l] 64 | { 65 | do_something(work); 66 | l.arrive(); 67 | }); 68 | } 69 | l.wait(); 70 | } 71 | -------------------------------------------------------------------------------- /src/examples/executor/post_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using std::experimental::post; 8 | using std::experimental::thread_pool; 9 | 10 | struct work 11 | { 12 | }; 13 | 14 | void do_something(const work&) 15 | { 16 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 17 | } 18 | 19 | int main(int argc, char* argv[]) 20 | { 21 | if (argc != 2) 22 | { 23 | std::cerr << "Usage: post_2 \n"; 24 | return 1; 25 | } 26 | 27 | std::vector work_list(std::atoi(argv[1])); 28 | 29 | // Start a large amount of work and join on the pool to complete. 30 | thread_pool tp(16); 31 | for (auto work: work_list) 32 | { 33 | post(tp, 34 | [work] 35 | { 36 | do_something(work); 37 | }); 38 | } 39 | tp.join(); 40 | } 41 | -------------------------------------------------------------------------------- /src/examples/executor/post_4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using std::experimental::make_work; 16 | using std::experimental::post; 17 | using std::experimental::strand; 18 | using std::experimental::system_executor; 19 | using std::experimental::thread_pool; 20 | 21 | std::vector read_file(const std::string& filename) 22 | { 23 | std::ifstream file(filename.c_str()); 24 | std::istreambuf_iterator iter(file.rdbuf()), end; 25 | return std::vector(iter, end); 26 | } 27 | 28 | std::vector process_content(std::vector content) 29 | { 30 | for (char& c: content) 31 | c = std::toupper(c); 32 | return std::move(content); 33 | } 34 | 35 | void append_content(std::vector& dest, std::vector source) 36 | { 37 | dest.insert(dest.end(), source.begin(), source.end()); 38 | } 39 | 40 | void render_content(const std::vector& content) 41 | { 42 | std::ostreambuf_iterator iter(std::cout.rdbuf()); 43 | std::copy(content.begin(), content.end(), iter); 44 | } 45 | 46 | int main(int argc, char* argv[]) 47 | { 48 | if (argc < 2) 49 | { 50 | std::cerr << "Usage: post_4 \n"; 51 | return 1; 52 | } 53 | 54 | std::vector src_files; 55 | for (int i = 1; i < argc; ++i) 56 | src_files.push_back(argv[i]); 57 | 58 | thread_pool file_pool(8); 59 | strand merge_executor; 60 | std::vector out; 61 | std::size_t pending_results = src_files.size(); 62 | thread_pool ui_executor(1); 63 | 64 | for (auto src: src_files) 65 | { 66 | // Post file read on file_pool and content processing on system_executor. 67 | post(file_pool, 68 | [&, work=make_work(ui_executor), src] 69 | { 70 | post( 71 | [&, work, content=read_file(src)]() mutable 72 | { 73 | post(merge_executor, 74 | [&, work, result=process_content(std::move(content))] 75 | { 76 | append_content(out, result); 77 | if (--pending_results == 0) 78 | { 79 | post(ui_executor, 80 | [&] 81 | { 82 | render_content(out); 83 | }); 84 | } 85 | }); 86 | }); 87 | }); 88 | } 89 | 90 | ui_executor.join(); 91 | } 92 | -------------------------------------------------------------------------------- /src/examples/executor/post_5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using std::experimental::loop_scheduler; 17 | using std::experimental::make_work; 18 | using std::experimental::post; 19 | using std::experimental::strand; 20 | using std::experimental::system_executor; 21 | using std::experimental::thread_pool; 22 | 23 | class content_pipeline 24 | { 25 | public: 26 | void run(const std::vector& src_files) 27 | { 28 | // Reset internal state. 29 | out_.clear(); 30 | pending_results_ = src_files.size(); 31 | ui_executor_.restart(); 32 | 33 | // Kick of the first stage of the pipeline. 34 | for (auto src: src_files) 35 | read_file(src); 36 | 37 | // Run the ui executor until the pipeline is complete. 38 | ui_executor_.run(); 39 | } 40 | 41 | private: 42 | void read_file(const std::string& filename) 43 | { 44 | post(file_pool_, 45 | [this, work=make_work(ui_executor_), filename] 46 | { 47 | std::ifstream file(filename.c_str()); 48 | std::istreambuf_iterator iter(file.rdbuf()), end; 49 | process_content(std::vector(iter, end)); 50 | }); 51 | } 52 | 53 | void process_content(std::vector content) 54 | { 55 | post( 56 | [this, work=make_work(ui_executor_), content=std::move(content)]() mutable 57 | { 58 | for (char& c: content) 59 | c = std::toupper(c); 60 | merge_content(std::move(content)); 61 | }); 62 | } 63 | 64 | void merge_content(std::vector result) 65 | { 66 | post(merge_executor_, 67 | [this, work=make_work(ui_executor_), result=std::move(result)] 68 | { 69 | out_.insert(out_.end(), result.begin(), result.end()); 70 | if (--pending_results_ == 0) 71 | render_content(); 72 | }); 73 | } 74 | 75 | void render_content() 76 | { 77 | post(ui_executor_, 78 | [this] 79 | { 80 | std::ostreambuf_iterator iter(std::cout.rdbuf()); 81 | std::copy(out_.begin(), out_.end(), iter); 82 | }); 83 | } 84 | 85 | thread_pool file_pool_{8}; 86 | strand merge_executor_; 87 | std::vector out_; 88 | std::size_t pending_results_; 89 | loop_scheduler ui_executor_{1}; 90 | }; 91 | 92 | int main(int argc, char* argv[]) 93 | { 94 | if (argc < 2) 95 | { 96 | std::cerr << "Usage: post_5 \n"; 97 | return 1; 98 | } 99 | 100 | std::vector src_files; 101 | for (int i = 1; i < argc; ++i) 102 | src_files.push_back(argv[i]); 103 | 104 | content_pipeline pipeline; 105 | pipeline.run(src_files); 106 | } 107 | -------------------------------------------------------------------------------- /src/examples/executor/sort_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::copost; 10 | using std::experimental::use_future; 11 | 12 | int main(int argc, char* argv[]) 13 | { 14 | const std::string parallel("parallel"); 15 | const std::string serial("serial"); 16 | 17 | if (!(argc == 3 && (argv[1] != parallel || argv[1] != serial))) 18 | { 19 | std::cerr << "Usage: `sort parallel ' or `sort serial '" << std::endl; 20 | return 1; 21 | } 22 | 23 | std::vector vec(std::atoll(argv[2])); 24 | std::iota(vec.begin(), vec.end(), 0); 25 | 26 | std::random_device rd; 27 | std::mt19937 g(rd()); 28 | std::shuffle(vec.begin(), vec.end(), g); 29 | 30 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 31 | 32 | if (argv[1] == parallel) 33 | { 34 | copost( 35 | [&]{ std::sort(vec.begin(), vec.begin() + (vec.size() / 2)); }, 36 | [&]{ std::sort(vec.begin() + (vec.size() / 2), vec.end()); }, 37 | use_future).get(); 38 | 39 | std::inplace_merge(vec.begin(), vec.begin() + (vec.size() / 2), vec.end()); 40 | } 41 | else 42 | { 43 | std::sort(vec.begin(), vec.end()); 44 | } 45 | 46 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 47 | 48 | std::cout << "sort took "; 49 | std::cout << std::chrono::duration_cast(elapsed).count(); 50 | std::cout << " microseconds" << std::endl; 51 | } 52 | -------------------------------------------------------------------------------- /src/examples/executor/sort_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::copost; 10 | using std::experimental::chain; 11 | using std::experimental::use_future; 12 | 13 | template 14 | auto parallel_sort(Iterator begin, Iterator end, CompletionToken&& token) 15 | { 16 | const std::size_t n = end - begin; 17 | return copost( 18 | [=]{ std::sort(begin, begin + (n / 2)); }, 19 | [=]{ std::sort(begin + (n / 2), end); }, 20 | chain( 21 | [=]{ std::inplace_merge(begin, begin + (n / 2), end); }, 22 | std::forward(token))); 23 | } 24 | 25 | int main(int argc, char* argv[]) 26 | { 27 | const std::string parallel("parallel"); 28 | const std::string serial("serial"); 29 | 30 | if (!(argc == 3 && (argv[1] != parallel || argv[1] != serial))) 31 | { 32 | std::cerr << "Usage: `sort parallel ' or `sort serial '" << std::endl; 33 | return 1; 34 | } 35 | 36 | std::vector vec(std::atoll(argv[2])); 37 | for (std::size_t i = 0; i < vec.size(); ++i) 38 | vec[i] = i; 39 | 40 | std::random_device rd; 41 | std::mt19937 g(rd()); 42 | std::shuffle(vec.begin(), vec.end(), g); 43 | 44 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 45 | 46 | if (argv[1] == parallel) 47 | { 48 | parallel_sort(vec.begin(), vec.end(), use_future).get(); 49 | } 50 | else 51 | { 52 | std::sort(vec.begin(), vec.end()); 53 | } 54 | 55 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 56 | 57 | std::cout << "sort took "; 58 | std::cout << std::chrono::duration_cast(elapsed).count(); 59 | std::cout << " microseconds" << std::endl; 60 | } 61 | -------------------------------------------------------------------------------- /src/examples/executor/sort_3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::experimental::copost; 10 | using std::experimental::chain; 11 | using std::experimental::use_future; 12 | 13 | template 14 | auto parallel_sort(Iterator begin, Iterator end, CompletionToken&& token) 15 | { 16 | const std::size_t n = end - begin; 17 | if (n <= 32768) 18 | { 19 | return dispatch( 20 | [=]{ std::sort(begin, end); }, 21 | std::forward(token)); 22 | } 23 | else 24 | { 25 | return copost( 26 | [=]{ std::sort(begin, begin + (n / 2)); }, 27 | [=]{ std::sort(begin + (n / 2), end); }, 28 | chain( 29 | [=]{ std::inplace_merge(begin, begin + (n / 2), end); }, 30 | std::forward(token))); 31 | } 32 | } 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | const std::string parallel("parallel"); 37 | const std::string serial("serial"); 38 | 39 | if (!(argc == 3 && (argv[1] != parallel || argv[1] != serial))) 40 | { 41 | std::cerr << "Usage: `sort parallel ' or `sort serial '" << std::endl; 42 | return 1; 43 | } 44 | 45 | std::vector vec(std::atoll(argv[2])); 46 | for (std::size_t i = 0; i < vec.size(); ++i) 47 | vec[i] = i; 48 | 49 | std::random_device rd; 50 | std::mt19937 g(rd()); 51 | std::shuffle(vec.begin(), vec.end(), g); 52 | 53 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 54 | 55 | if (argv[1] == parallel) 56 | { 57 | parallel_sort(vec.begin(), vec.end(), use_future).get(); 58 | } 59 | else 60 | { 61 | std::sort(vec.begin(), vec.end()); 62 | } 63 | 64 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 65 | 66 | std::cout << "sort took "; 67 | std::cout << std::chrono::duration_cast(elapsed).count(); 68 | std::cout << " microseconds" << std::endl; 69 | } 70 | -------------------------------------------------------------------------------- /src/examples/executor/sort_4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using std::experimental::continuation; 11 | using std::experimental::copost; 12 | using std::experimental::chain; 13 | using std::experimental::use_future; 14 | 15 | template 16 | auto parallel_sort(Iterator begin, Iterator end, CompletionToken&& token) 17 | { 18 | const std::size_t n = end - begin; 19 | if (n <= 32768) 20 | { 21 | return dispatch( 22 | [=]{ std::sort(begin, end); }, 23 | std::forward(token)); 24 | } 25 | else 26 | { 27 | return copost( 28 | [=](continuation<> c) 29 | { 30 | return parallel_sort(begin, begin + (n / 2), std::move(c)); 31 | }, 32 | [=](continuation<> c) 33 | { 34 | return parallel_sort(begin + (n / 2), end, std::move(c)); 35 | }, 36 | chain( 37 | [=]{ std::inplace_merge(begin, begin + (n / 2), end); }, 38 | std::forward(token))); 39 | } 40 | } 41 | 42 | int main(int argc, char* argv[]) 43 | { 44 | const std::string parallel("parallel"); 45 | const std::string serial("serial"); 46 | 47 | if (!(argc == 3 && (argv[1] != parallel || argv[1] != serial))) 48 | { 49 | std::cerr << "Usage: `sort parallel ' or `sort serial '" << std::endl; 50 | return 1; 51 | } 52 | 53 | std::vector vec(std::atoll(argv[2])); 54 | for (std::size_t i = 0; i < vec.size(); ++i) 55 | vec[i] = i; 56 | 57 | std::random_device rd; 58 | std::mt19937 g(rd()); 59 | std::shuffle(vec.begin(), vec.end(), g); 60 | 61 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 62 | 63 | if (argv[1] == parallel) 64 | { 65 | parallel_sort(vec.begin(), vec.end(), use_future).get(); 66 | } 67 | else 68 | { 69 | std::sort(vec.begin(), vec.end()); 70 | } 71 | 72 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 73 | 74 | std::cout << "sort took "; 75 | std::cout << std::chrono::duration_cast(elapsed).count(); 76 | std::cout << " microseconds" << std::endl; 77 | } 78 | -------------------------------------------------------------------------------- /src/examples/executor/sort_5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using std::experimental::await_context; 11 | using std::experimental::codispatch; 12 | using std::experimental::use_future; 13 | 14 | template 15 | void sort_coroutine(Iterator begin, Iterator end, await_context ctx) 16 | { 17 | std::size_t n = end - begin; 18 | reenter (ctx) 19 | { 20 | if (n <= 32768) 21 | { 22 | std::sort(begin, end); 23 | } 24 | else 25 | { 26 | await copost( 27 | [=](await_context ctx) { sort_coroutine(begin, begin + n / 2, ctx); }, 28 | [=](await_context ctx) { sort_coroutine(begin + n / 2, end, ctx); }, 29 | ctx); 30 | std::inplace_merge(begin, begin + n / 2, end); 31 | } 32 | } 33 | } 34 | 35 | template 36 | auto parallel_sort(Iterator begin, Iterator end, CompletionToken&& token) 37 | { 38 | return dispatch( 39 | [=](await_context ctx){ sort_coroutine(begin, end, ctx); }, 40 | std::forward(token)); 41 | } 42 | 43 | int main(int argc, char* argv[]) 44 | { 45 | const std::string parallel("parallel"); 46 | const std::string serial("serial"); 47 | 48 | if (!(argc == 3 && (argv[1] != parallel || argv[1] != serial))) 49 | { 50 | std::cerr << "Usage: `sort parallel ' or `sort serial '" << std::endl; 51 | return 1; 52 | } 53 | 54 | std::vector vec(std::atoll(argv[2])); 55 | for (std::size_t i = 0; i < vec.size(); ++i) 56 | vec[i] = i; 57 | 58 | std::random_device rd; 59 | std::mt19937 g(rd()); 60 | std::shuffle(vec.begin(), vec.end(), g); 61 | 62 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 63 | 64 | if (argv[1] == parallel) 65 | { 66 | parallel_sort(vec.begin(), vec.end(), use_future).get(); 67 | } 68 | else 69 | { 70 | std::sort(vec.begin(), vec.end()); 71 | } 72 | 73 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 74 | 75 | std::cout << "sort took "; 76 | std::cout << std::chrono::duration_cast(elapsed).count(); 77 | std::cout << " microseconds" << std::endl; 78 | } 79 | -------------------------------------------------------------------------------- /src/examples/executor/sort_6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using std::experimental::codispatch; 11 | using std::experimental::use_future; 12 | using std::experimental::yield_context; 13 | 14 | template 15 | void sort_coroutine(Iterator begin, Iterator end, yield_context yield) 16 | { 17 | std::size_t n = end - begin; 18 | if (n <= 32768) 19 | { 20 | std::sort(begin, end); 21 | } 22 | else 23 | { 24 | copost( 25 | [=](yield_context yield) { sort_coroutine(begin, begin + n / 2, yield); }, 26 | [=](yield_context yield) { sort_coroutine(begin + n / 2, end, yield); }, 27 | yield); 28 | std::inplace_merge(begin, begin + n / 2, end); 29 | } 30 | } 31 | 32 | template 33 | auto parallel_sort(Iterator begin, Iterator end, CompletionToken&& token) 34 | { 35 | return dispatch( 36 | [=](yield_context ctx){ sort_coroutine(begin, end, ctx); }, 37 | std::forward(token)); 38 | } 39 | 40 | int main(int argc, char* argv[]) 41 | { 42 | const std::string parallel("parallel"); 43 | const std::string serial("serial"); 44 | 45 | if (!(argc == 3 && (argv[1] != parallel || argv[1] != serial))) 46 | { 47 | std::cerr << "Usage: `sort parallel ' or `sort serial '" << std::endl; 48 | return 1; 49 | } 50 | 51 | std::vector vec(std::atoll(argv[2])); 52 | for (std::size_t i = 0; i < vec.size(); ++i) 53 | vec[i] = i; 54 | 55 | std::random_device rd; 56 | std::mt19937 g(rd()); 57 | std::shuffle(vec.begin(), vec.end(), g); 58 | 59 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 60 | 61 | if (argv[1] == parallel) 62 | { 63 | parallel_sort(vec.begin(), vec.end(), use_future).get(); 64 | } 65 | else 66 | { 67 | std::sort(vec.begin(), vec.end()); 68 | } 69 | 70 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 71 | 72 | std::cout << "sort took "; 73 | std::cout << std::chrono::duration_cast(elapsed).count(); 74 | std::cout << " microseconds" << std::endl; 75 | } 76 | -------------------------------------------------------------------------------- /src/examples/timer/.gitignore: -------------------------------------------------------------------------------- 1 | dispatch_at_1 2 | dispatch_at_2 3 | dispatch_after_1 4 | dispatch_after_2 5 | -------------------------------------------------------------------------------- /src/examples/timer/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | dispatch_at_1 \ 3 | dispatch_at_2 \ 4 | dispatch_after_1 \ 5 | dispatch_after_2 6 | 7 | AM_CXXFLAGS = -I$(srcdir)/../../../include 8 | 9 | dispatch_at_1_SOURCES = dispatch_at_1.cpp 10 | dispatch_at_2_SOURCES = dispatch_at_2.cpp 11 | dispatch_after_1_SOURCES = dispatch_after_1.cpp 12 | dispatch_after_2_SOURCES = dispatch_after_2.cpp 13 | 14 | MAINTAINERCLEANFILES = \ 15 | $(srcdir)/Makefile.in 16 | -------------------------------------------------------------------------------- /src/examples/timer/dispatch_after_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::dispatch; 7 | using std::experimental::dispatch_after; 8 | using std::experimental::use_future; 9 | using std::experimental::yield_context; 10 | 11 | int main() 12 | { 13 | dispatch( 14 | [](yield_context yield) 15 | { 16 | for (int i = 0; i < 10; ++i) 17 | { 18 | dispatch_after(std::chrono::seconds(1), yield); 19 | std::cout << i << std::endl; 20 | } 21 | }, use_future).get(); 22 | } 23 | -------------------------------------------------------------------------------- /src/examples/timer/dispatch_after_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::dispatch; 7 | using std::experimental::dispatch_after; 8 | using std::experimental::loop_scheduler; 9 | using std::experimental::yield_context; 10 | 11 | int main() 12 | { 13 | loop_scheduler scheduler; 14 | auto executor = scheduler.get_executor(); 15 | 16 | dispatch( 17 | wrap(executor, 18 | [](yield_context yield) 19 | { 20 | for (int i = 0; i < 10; ++i) 21 | { 22 | dispatch_after(std::chrono::seconds(1), yield); 23 | std::cout << i << std::endl; 24 | } 25 | } 26 | )); 27 | 28 | scheduler.run(); 29 | } 30 | -------------------------------------------------------------------------------- /src/examples/timer/dispatch_at_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::dispatch; 7 | using std::experimental::dispatch_at; 8 | using std::experimental::use_future; 9 | using std::experimental::yield_context; 10 | 11 | int main() 12 | { 13 | dispatch( 14 | [](yield_context yield) 15 | { 16 | auto start_time = std::chrono::steady_clock::now(); 17 | for (int i = 0; i < 10; ++i) 18 | { 19 | dispatch_at(start_time + std::chrono::seconds(i + 1), yield); 20 | std::cout << i << std::endl; 21 | } 22 | }, use_future).get(); 23 | } 24 | -------------------------------------------------------------------------------- /src/examples/timer/dispatch_at_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::experimental::dispatch; 7 | using std::experimental::dispatch_at; 8 | using std::experimental::loop_scheduler; 9 | using std::experimental::yield_context; 10 | 11 | int main() 12 | { 13 | loop_scheduler scheduler; 14 | auto executor = scheduler.get_executor(); 15 | 16 | dispatch( 17 | wrap(executor, 18 | [](yield_context yield) 19 | { 20 | auto start_time = std::chrono::steady_clock::now(); 21 | for (int i = 0; i < 10; ++i) 22 | { 23 | dispatch_at(start_time + std::chrono::seconds(i + 1), yield); 24 | std::cout << i << std::endl; 25 | } 26 | } 27 | )); 28 | 29 | scheduler.run(); 30 | } 31 | -------------------------------------------------------------------------------- /src/examples/trading/.gitignore: -------------------------------------------------------------------------------- 1 | enter_one_order 2 | market_data_dump 3 | trading_server 4 | Makefile.in 5 | Makefile 6 | .dirstamp 7 | -------------------------------------------------------------------------------- /src/examples/trading/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = subdir-objects 2 | 3 | noinst_PROGRAMS = \ 4 | trading_server \ 5 | enter_one_order \ 6 | market_data_dump 7 | 8 | AM_CXXFLAGS = -I$(srcdir)/../../../include 9 | 10 | trading_server_SOURCES = \ 11 | common/order_management.cpp \ 12 | common/order_side.cpp \ 13 | common/market_data.cpp \ 14 | common/udp_socket.cpp \ 15 | server/connection_handler.cpp \ 16 | server/market_by_order.cpp \ 17 | server/market_data_bus.cpp \ 18 | server/order_book.cpp \ 19 | server/order_management_bus.cpp \ 20 | server/price_time_order_book.cpp \ 21 | server/server.cpp 22 | 23 | enter_one_order_SOURCES = \ 24 | common/order_management.cpp \ 25 | common/order_side.cpp \ 26 | common/udp_socket.cpp \ 27 | client/enter_one_order.cpp 28 | 29 | market_data_dump_SOURCES = \ 30 | common/market_data.cpp \ 31 | common/order_side.cpp \ 32 | common/udp_socket.cpp \ 33 | client/market_data_dump.cpp 34 | 35 | EXTRA_DIST = \ 36 | common/order_side.hpp \ 37 | common/market_data.hpp \ 38 | common/udp_socket.hpp \ 39 | common/order_management.hpp \ 40 | server/order_management_bus.hpp \ 41 | server/price_time_order_book.hpp \ 42 | server/connection_handler.hpp \ 43 | server/order_book.hpp \ 44 | server/market_data_bus.hpp \ 45 | server/market_by_order.hpp \ 46 | server/market_data_feed.hpp 47 | 48 | MAINTAINERCLEANFILES = \ 49 | $(srcdir)/Makefile.in 50 | -------------------------------------------------------------------------------- /src/examples/trading/client/enter_one_order.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // enter_one_order.cpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Program to enter a single order. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | #include "common/order_management.hpp" 16 | #include "common/udp_socket.hpp" 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | if (argc != 8) 21 | { 22 | std::cerr << "Usage: enter_one_order \n"; 23 | return 1; 24 | } 25 | 26 | udp_socket sock(0); 27 | sock.connect(argv[1], std::atoi(argv[2])); 28 | 29 | // Create the message. 30 | order_management::new_order new_order; 31 | new_order.symbol = argv[3]; 32 | new_order.side = (argv[4][0] == 'B') ? order_side::buy : order_side::sell; 33 | new_order.price = std::atoi(argv[5]); 34 | new_order.quantity = std::atoi(argv[6]); 35 | new_order.immediate_or_cancel = (std::atoi(argv[7]) != 0); 36 | 37 | // Encode and send the message. 38 | std::ostringstream os; 39 | os << new_order; 40 | std::string msg = os.str(); 41 | sock.send(msg.data(), msg.length()); 42 | } 43 | -------------------------------------------------------------------------------- /src/examples/trading/client/market_data_dump.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_data_dump.cpp 3 | // ~~~~~~~~~~~~~~~~~~~~ 4 | // Client program to dump market data messages. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | #include "common/market_data.hpp" 16 | #include "common/udp_socket.hpp" 17 | 18 | void handle_heartbeat(std::istream& is) 19 | { 20 | market_data::heartbeat heartbeat; 21 | if (is >> heartbeat) 22 | { 23 | std::cout << "." << std::flush; 24 | } 25 | else 26 | { 27 | std::cout << "Invalid heartbeat message\n"; 28 | } 29 | } 30 | 31 | void handle_new_order(std::istream& is) 32 | { 33 | market_data::new_order new_order; 34 | if (is >> new_order) 35 | { 36 | std::cout << "\nNew order: "; 37 | std::cout << (new_order.side == order_side::buy ? "Buy " : "Sell "); 38 | std::cout << new_order.symbol << " "; 39 | std::cout << new_order.quantity << "@"; 40 | std::cout << new_order.price << "\n"; 41 | } 42 | else 43 | { 44 | std::cout << "Invalid new_order message\n"; 45 | } 46 | } 47 | 48 | void handle_trade(std::istream& is) 49 | { 50 | market_data::trade trade; 51 | if (is >> trade) 52 | { 53 | std::cout << "\nTrade: "; 54 | std::cout << trade.symbol << " "; 55 | std::cout << trade.quantity << "@"; 56 | std::cout << trade.price << "\n"; 57 | } 58 | else 59 | { 60 | std::cout << "Invalid new_order message\n"; 61 | } 62 | } 63 | 64 | int main(int argc, char* argv[]) 65 | { 66 | if (argc != 2) 67 | { 68 | std::cerr << "Usage: market_data_dump \n"; 69 | return 1; 70 | } 71 | 72 | udp_socket sock(std::atoi(argv[1])); 73 | 74 | for (;;) 75 | { 76 | char buffer[1024]; 77 | if (std::size_t length = sock.receive(buffer, sizeof(buffer))) 78 | { 79 | std::istringstream is(std::string(buffer, length)); 80 | if (buffer[0] == 'H') 81 | handle_heartbeat(is); 82 | else if (buffer[0] == 'O') 83 | handle_new_order(is); 84 | else if (buffer[0] == 'T') 85 | handle_trade(is); 86 | else 87 | std::cout << "Unrecognised message type\n"; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/examples/trading/common/market_data.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_data.cpp 3 | // ~~~~~~~~~~~~~~~ 4 | // Market data events. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "market_data.hpp" 13 | #include 14 | #include 15 | 16 | namespace market_data { 17 | 18 | std::istream& operator>>(std::istream& is, heartbeat& h) 19 | { 20 | if (is.get() == 'H') 21 | is >> h.sequence_number >> h.time; 22 | else 23 | is.setstate(std::ios::badbit); 24 | return is; 25 | } 26 | 27 | std::ostream& operator<<(std::ostream& os, const heartbeat& h) 28 | { 29 | os << 'H' << ' ' << h.sequence_number << ' ' << h.time; 30 | return os; 31 | } 32 | 33 | std::istream& operator>>(std::istream& is, new_order& o) 34 | { 35 | if (is.get() == 'O') 36 | is >> o.sequence_number >> o.symbol >> o.side >> o.price >> o.quantity; 37 | else 38 | is.setstate(std::ios::badbit); 39 | return is; 40 | } 41 | 42 | std::ostream& operator<<(std::ostream& os, const new_order& o) 43 | { 44 | os << 'O' << ' ' << o.sequence_number << ' ' << o.symbol << ' ' << o.side << ' ' << o.price << ' ' << o.quantity; 45 | return os; 46 | } 47 | 48 | std::istream& operator>>(std::istream& is, trade& t) 49 | { 50 | if (is.get() == 'T') 51 | is >> t.sequence_number >> t.symbol >> t.aggressor_side >> t.price >> t.quantity; 52 | else 53 | is.setstate(std::ios::badbit); 54 | return is; 55 | } 56 | 57 | std::ostream& operator<<(std::ostream& os, const trade& t) 58 | { 59 | os << 'T' << ' ' << t.sequence_number << ' ' << t.symbol << ' ' << t.aggressor_side << ' ' << t.price << ' ' << t.quantity; 60 | return os; 61 | } 62 | 63 | } // namespace market_data 64 | -------------------------------------------------------------------------------- /src/examples/trading/common/market_data.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_data.hpp 3 | // ~~~~~~~~~~~~~~~ 4 | // Market data events. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef MARKET_DATA_HPP 13 | #define MARKET_DATA_HPP 14 | 15 | #include 16 | #include 17 | #include 18 | #include "order_side.hpp" 19 | 20 | namespace market_data { 21 | 22 | struct heartbeat 23 | { 24 | std::uint64_t sequence_number; 25 | std::uint64_t time; 26 | }; 27 | 28 | std::istream& operator>>(std::istream& is, heartbeat& h); 29 | std::ostream& operator<<(std::ostream& os, const heartbeat& h); 30 | 31 | struct new_order 32 | { 33 | std::uint64_t sequence_number; 34 | std::string symbol; 35 | order_side side; 36 | int price; 37 | unsigned int quantity; 38 | }; 39 | 40 | std::istream& operator>>(std::istream& is, new_order& o); 41 | std::ostream& operator<<(std::ostream& os, const new_order& o); 42 | 43 | struct trade 44 | { 45 | std::uint64_t sequence_number; 46 | std::string symbol; 47 | order_side aggressor_side; 48 | int price; 49 | unsigned int quantity; 50 | }; 51 | 52 | std::istream& operator>>(std::istream& is, trade& t); 53 | std::ostream& operator<<(std::ostream& os, const trade& t); 54 | 55 | } // namespace market_data 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/examples/trading/common/order_management.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_management.cpp 3 | // ~~~~~~~~~~~~~~~~~~~~ 4 | // Order mangement events. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "order_management.hpp" 13 | #include 14 | #include 15 | 16 | namespace order_management { 17 | 18 | std::istream& operator>>(std::istream& is, new_order& o) 19 | { 20 | if (is.get() == 'S') 21 | is >> o.symbol >> o.side >> o.price >> o.quantity >> o.immediate_or_cancel; 22 | else 23 | is.setstate(std::ios::badbit); 24 | return is; 25 | } 26 | 27 | std::ostream& operator<<(std::ostream& os, const new_order& o) 28 | { 29 | os << 'S' << ' ' << o.symbol << ' ' << o.side << ' ' << o.price << ' ' << o.quantity << ' ' << o.immediate_or_cancel; 30 | return os; 31 | } 32 | 33 | } // namespace order_management 34 | -------------------------------------------------------------------------------- /src/examples/trading/common/order_management.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_management.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~ 4 | // Order mangement events. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef ORDER_MANAGEMENT_HPP 13 | #define ORDER_MANAGEMENT_HPP 14 | 15 | #include 16 | #include 17 | #include "order_side.hpp" 18 | 19 | namespace order_management { 20 | 21 | struct new_order 22 | { 23 | std::string symbol; 24 | order_side side; 25 | int price; 26 | unsigned int quantity; 27 | bool immediate_or_cancel; 28 | }; 29 | 30 | std::istream& operator>>(std::istream& is, new_order& s); 31 | std::ostream& operator<<(std::ostream& os, const new_order& s); 32 | 33 | } // namespace order_management 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/examples/trading/common/order_side.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_side.cpp 3 | // ~~~~~~~~~~~~~~ 4 | // Enumeration used to indicate whether an order is a buy or a sell. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "order_side.hpp" 13 | #include 14 | #include 15 | 16 | std::istream& operator>>(std::istream& is, order_side& s) 17 | { 18 | char side = 0; 19 | is >> side; 20 | switch (side) 21 | { 22 | case 'B': 23 | s = order_side::buy; 24 | break; 25 | case 'S': 26 | s = order_side::sell; 27 | break; 28 | default: 29 | is.setstate(std::ios::badbit); 30 | break; 31 | } 32 | return is; 33 | } 34 | 35 | std::ostream& operator<<(std::ostream& os, const order_side& s) 36 | { 37 | os << static_cast(s); 38 | return os; 39 | } 40 | -------------------------------------------------------------------------------- /src/examples/trading/common/order_side.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_side.hpp 3 | // ~~~~~~~~~~~~~~ 4 | // Enumeration used to indicate whether an order is a buy or a sell. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef ORDER_SIDE_HPP 13 | #define ORDER_SIDE_HPP 14 | 15 | #include 16 | 17 | enum class order_side 18 | { 19 | buy = 'B', 20 | sell = 'S' 21 | }; 22 | 23 | std::istream& operator>>(std::istream& is, order_side& s); 24 | std::ostream& operator<<(std::ostream& os, const order_side& s); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/examples/trading/common/udp_socket.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // udp_socket.cpp 3 | // ~~~~~~~~~~~~~~ 4 | // Simple UDP socket wrapper. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "udp_socket.hpp" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | udp_socket::udp_socket(unsigned short port) 22 | : socket_(::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) 23 | { 24 | if (socket_ == -1) 25 | { 26 | std::error_code ec(errno, std::generic_category()); 27 | throw std::system_error(ec, "udp_socket creation"); 28 | } 29 | 30 | union 31 | { 32 | sockaddr base; 33 | sockaddr_in v4; 34 | } addr; 35 | 36 | addr.v4.sin_family = AF_INET; 37 | addr.v4.sin_addr.s_addr = 0; 38 | addr.v4.sin_port = htons(port); 39 | 40 | if (::bind(socket_, &addr.base, sizeof(addr.v4)) == -1) 41 | { 42 | std::error_code ec(errno, std::generic_category()); 43 | ::close(socket_); 44 | throw std::system_error(ec, "udp_socket bind"); 45 | } 46 | 47 | int opt = 1; 48 | if (::setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) 49 | { 50 | std::error_code ec(errno, std::generic_category()); 51 | ::close(socket_); 52 | throw std::system_error(ec, "udp_socket setsockopt"); 53 | } 54 | } 55 | 56 | udp_socket::~udp_socket() 57 | { 58 | ::close(socket_); 59 | } 60 | 61 | void udp_socket::connect(const std::string& ip, unsigned short port) 62 | { 63 | union 64 | { 65 | sockaddr base; 66 | sockaddr_in v4; 67 | } addr; 68 | 69 | addr.v4.sin_family = AF_INET; 70 | addr.v4.sin_port = htons(port); 71 | 72 | switch (::inet_pton(AF_INET, ip.c_str(), &addr.v4.sin_addr)) 73 | { 74 | default: 75 | assert(0); 76 | break; 77 | case 1: 78 | break; 79 | case 0: 80 | throw std::system_error(make_error_code(std::errc::invalid_argument), "udp_socket connect"); 81 | case -1: 82 | std::error_code ec(errno, std::generic_category()); 83 | throw std::system_error(ec, "udp_socket connect"); 84 | } 85 | 86 | if (::connect(socket_, &addr.base, sizeof(addr.v4)) == -1) 87 | { 88 | std::error_code ec(errno, std::generic_category()); 89 | throw std::system_error(ec, "udp_socket connect"); 90 | } 91 | } 92 | 93 | void udp_socket::send(const void* data, std::size_t length) 94 | { 95 | for (;;) 96 | { 97 | ssize_t n = ::send(socket_, data, length, 0); 98 | if (n >= 0 || (n == -1 && errno != EINTR)) 99 | break; 100 | } 101 | } 102 | 103 | std::size_t udp_socket::receive(void* data, std::size_t length) 104 | { 105 | for (;;) 106 | { 107 | ssize_t n = ::recv(socket_, data, length, 0); 108 | if (n > 0) 109 | return n; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/examples/trading/common/udp_socket.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // udp_socket.hpp 3 | // ~~~~~~~~~~~~~~ 4 | // Simple UDP socket wrapper. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef UDP_SOCKET_HPP 13 | #define UDP_SOCKET_HPP 14 | 15 | #include 16 | #include 17 | 18 | // A very simple wrapper for UDP sockets. 19 | class udp_socket 20 | { 21 | public: 22 | udp_socket(const udp_socket&) = delete; 23 | udp_socket& operator=(const udp_socket&) = delete; 24 | 25 | // Open and bind the socket. 26 | explicit udp_socket(unsigned short port); 27 | 28 | // Closes the socket. 29 | ~udp_socket(); 30 | 31 | // Connect the socket to the specified remote IP address and port. 32 | void connect(const std::string& ip, unsigned short port); 33 | 34 | // Send a datagram on the socket. 35 | void send(const void* data, std::size_t length); 36 | 37 | // Synchronously receive a datagram on the socket. 38 | std::size_t receive(void* data, std::size_t length); 39 | 40 | private: 41 | // The UDP socket's file descriptor. 42 | int socket_; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/examples/trading/ports.txt: -------------------------------------------------------------------------------- 1 | 40001 2 | 40002 3 | 40003 4 | 40004 5 | 40005 6 | -------------------------------------------------------------------------------- /src/examples/trading/server/.dirstamp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chriskohlhoff/executors/9b42e193b27cc5c3308dd3bc4e52712c2e442c4b/src/examples/trading/server/.dirstamp -------------------------------------------------------------------------------- /src/examples/trading/server/connection_handler.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // connect_handler.cpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Handles inbound order management transactions. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "connection_handler.hpp" 13 | #include "common/order_management.hpp" 14 | #include "order_management_bus.hpp" 15 | #include 16 | #include 17 | 18 | const std::size_t thread_pool_size = 2; 19 | 20 | connection_handler::connection_handler(unsigned short port, order_management_bus& bus) 21 | : socket_(port), thread_pool_(thread_pool_size), order_management_bus_(bus) 22 | { 23 | std::cerr << "Listening on port " << port << std::endl; 24 | } 25 | 26 | void connection_handler::start() 27 | { 28 | std::experimental::post(thread_pool_, [this]{ receive_and_dispatch(); }); 29 | } 30 | 31 | void connection_handler::join() 32 | { 33 | thread_pool_.join(); 34 | } 35 | 36 | void connection_handler::receive_and_dispatch() 37 | { 38 | // Wait until a new message is received. 39 | char buffer[1024]; 40 | std::size_t length = socket_.receive(buffer, sizeof(buffer)); 41 | 42 | // Wake another thread to wait for new messages. 43 | std::experimental::post(thread_pool_, [this]{ receive_and_dispatch(); }); 44 | 45 | // Process the new message and pass it to the order management bus. 46 | std::istringstream is(std::string(buffer, length)); 47 | order_management::new_order event; 48 | if (is >> event) 49 | order_management_bus_.dispatch_event(event); 50 | } 51 | -------------------------------------------------------------------------------- /src/examples/trading/server/connection_handler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // connect_handler.hpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Handles inbound order management transactions. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef CONNECTION_HANDLER_HPP 13 | #define CONNECTION_HANDLER_HPP 14 | 15 | #include 16 | #include "common/udp_socket.hpp" 17 | 18 | class order_management_bus; 19 | 20 | class connection_handler 21 | { 22 | public: 23 | // Create a connection handler to listen on the specified port. 24 | connection_handler(unsigned short port, order_management_bus& bus); 25 | 26 | // Run the connection handler to listen for inbound messages. Any valid order 27 | // messages that are received are passed to the order management bus. 28 | void start(); 29 | 30 | // Wait for connection handler to exit. 31 | void join(); 32 | 33 | private: 34 | // Helper function to receive and dispatch a single message. 35 | void receive_and_dispatch(); 36 | 37 | udp_socket socket_; 38 | std::experimental::thread_pool thread_pool_; 39 | order_management_bus& order_management_bus_; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/examples/trading/server/market_by_order.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_by_order.cpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Market data feed that publishes every passive order and trade. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "market_by_order.hpp" 13 | #include 14 | #include 15 | #include 16 | 17 | market_by_order::market_by_order(const std::string& ip, unsigned short port) 18 | : socket_(0), next_sequence_number_(0) 19 | { 20 | socket_.connect(ip, port); 21 | std::experimental::dispatch(strand_, [this]{ send_heartbeat(); }); 22 | } 23 | 24 | void market_by_order::handle_event(market_data::new_order o) 25 | { 26 | std::experimental::dispatch(strand_, 27 | [=]() mutable 28 | { 29 | o.sequence_number = next_sequence_number_++; 30 | 31 | std::ostringstream os; 32 | os << o; 33 | std::string msg = os.str(); 34 | 35 | socket_.send(msg.data(), msg.length()); 36 | }); 37 | } 38 | 39 | void market_by_order::handle_event(market_data::trade t) 40 | { 41 | std::experimental::dispatch(strand_, 42 | [=]() mutable 43 | { 44 | t.sequence_number = next_sequence_number_++; 45 | 46 | std::ostringstream os; 47 | os << t; 48 | std::string msg = os.str(); 49 | 50 | socket_.send(msg.data(), msg.length()); 51 | }); 52 | } 53 | 54 | void market_by_order::send_heartbeat() 55 | { 56 | market_data::heartbeat h; 57 | h.sequence_number = next_sequence_number_; 58 | h.time = std::time(nullptr); 59 | 60 | std::ostringstream os; 61 | os << h; 62 | std::string msg = os.str(); 63 | 64 | socket_.send(msg.data(), msg.length()); 65 | 66 | std::experimental::defer_after(std::chrono::seconds(1), 67 | strand_, [this]{ send_heartbeat(); }); 68 | } 69 | -------------------------------------------------------------------------------- /src/examples/trading/server/market_by_order.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_by_order.hpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Market data feed that publishes every passive order and trade. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef MARKET_BY_ORDER_HPP 13 | #define MARKET_BY_ORDER_HPP 14 | 15 | #include 16 | #include 17 | #include 18 | #include "common/udp_socket.hpp" 19 | #include "market_data_feed.hpp" 20 | 21 | class market_by_order : public market_data_feed 22 | { 23 | public: 24 | // Create a new market-by-order data feed sending to the specified IP address 25 | // and port number. 26 | market_by_order(const std::string& ip, unsigned short port); 27 | 28 | // Dispatch a market data event to the feed. 29 | virtual void handle_event(market_data::new_order o); 30 | virtual void handle_event(market_data::trade t); 31 | 32 | private: 33 | // Send a heartbeat to let market data subscribers know that we're still alive. 34 | void send_heartbeat(); 35 | 36 | std::experimental::strand strand_; 37 | udp_socket socket_; 38 | std::uint64_t next_sequence_number_; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/examples/trading/server/market_data_bus.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_data_bus.cpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Bus used to distribute events to all market data feeds. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "market_data_bus.hpp" 13 | 14 | void market_data_bus::subscribe(market_data_feed& f) 15 | { 16 | feeds_.push_back(&f); 17 | } 18 | 19 | void market_data_bus::dispatch_event(market_data::new_order o) 20 | { 21 | for (auto& f: feeds_) 22 | f->handle_event(o); 23 | } 24 | 25 | void market_data_bus::dispatch_event(market_data::trade t) 26 | { 27 | for (auto& f: feeds_) 28 | f->handle_event(t); 29 | } 30 | -------------------------------------------------------------------------------- /src/examples/trading/server/market_data_bus.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_data_bus.hpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // Bus used to distribute events to all market data feeds. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef MARKET_DATA_BUS_HPP 13 | #define MARKET_DATA_BUS_HPP 14 | 15 | #include 16 | #include "common/market_data.hpp" 17 | #include "market_data_feed.hpp" 18 | 19 | class market_data_bus 20 | { 21 | public: 22 | // Subscribe a market data feed to the bus. 23 | void subscribe(market_data_feed& f); 24 | 25 | // Dispatch a market data event to the bus. 26 | void dispatch_event(market_data::new_order o); 27 | void dispatch_event(market_data::trade t); 28 | 29 | private: 30 | std::vector feeds_; 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/examples/trading/server/market_data_feed.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // market_data_feed.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~ 4 | // Base class for all market data feeds. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef MARKET_DATA_FEED_HPP 13 | #define MARKET_DATA_FEED_HPP 14 | 15 | #include 16 | #include "common/market_data.hpp" 17 | 18 | class market_data_feed 19 | { 20 | public: 21 | // Destroy the market data feed. 22 | virtual ~market_data_feed() {} 23 | 24 | // Dispatch a market data event to the feed. 25 | virtual void handle_event(market_data::new_order o) = 0; 26 | virtual void handle_event(market_data::trade t) = 0; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/examples/trading/server/order_book.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_book.cpp 3 | // ~~~~~~~~~~~~~~ 4 | // Base class for all order books. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "order_book.hpp" 13 | 14 | order_book::order_book(const std::string& s) 15 | : symbol_(s) 16 | { 17 | } 18 | 19 | order_book::~order_book() 20 | { 21 | } 22 | 23 | const std::string order_book::symbol() const 24 | { 25 | return symbol_; 26 | } 27 | -------------------------------------------------------------------------------- /src/examples/trading/server/order_book.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_book.hpp 3 | // ~~~~~~~~~~~~~~ 4 | // Base class for all order books. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef ORDER_BOOK_HPP 13 | #define ORDER_BOOK_HPP 14 | 15 | #include 16 | #include "common/order_management.hpp" 17 | 18 | class order_book 19 | { 20 | public: 21 | // Create the order book with the specified symbol. 22 | order_book(const std::string& s); 23 | 24 | // Destroy the order book. 25 | virtual ~order_book(); 26 | 27 | // Get the order book's symbol. 28 | const std::string symbol() const; 29 | 30 | // Dispatch an order management event to the order book. 31 | virtual void handle_event(order_management::new_order o) = 0; 32 | 33 | private: 34 | const std::string symbol_; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/examples/trading/server/order_management_bus.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_management_bus.cpp 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // Bus used to distribute order management events to all order books. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include "order_management_bus.hpp" 13 | 14 | void order_management_bus::subscribe(order_book& b) 15 | { 16 | books_.insert(std::make_pair(b.symbol(), &b)); 17 | } 18 | 19 | void order_management_bus::dispatch_event(order_management::new_order o) 20 | { 21 | auto iter = books_.find(o.symbol); 22 | if (iter != books_.end()) 23 | iter->second->handle_event(o); 24 | } 25 | -------------------------------------------------------------------------------- /src/examples/trading/server/order_management_bus.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // order_management_bus.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // Bus used to distribute order management events to all order books. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef ORDER_MANAGEMENT_BUS_HPP 13 | #define ORDER_MANAGEMENT_BUS_HPP 14 | 15 | #include 16 | #include 17 | #include "common/order_management.hpp" 18 | #include "order_book.hpp" 19 | 20 | class order_management_bus 21 | { 22 | public: 23 | // Subscribe an order book to the bus. 24 | void subscribe(order_book& b); 25 | 26 | // Dispatch an order management event to the bus. 27 | void dispatch_event(order_management::new_order o); 28 | 29 | private: 30 | std::unordered_map books_; 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/examples/trading/server/price_time_order_book.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // price_time_order_book.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // Order book using price-time priority. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #ifndef PRICE_TIME_ORDER_BOOK_HPP 13 | #define PRICE_TIME_ORDER_BOOK_HPP 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "order_book.hpp" 22 | 23 | class market_data_bus; 24 | 25 | class price_time_order_book : public order_book 26 | { 27 | public: 28 | // Create the order book with the specified symbol. 29 | price_time_order_book(const std::string& s, market_data_bus& bus); 30 | 31 | // Dispatch an order management event to the order book. 32 | virtual void handle_event(order_management::new_order o); 33 | 34 | protected: 35 | // Process a new order and find possible matches. 36 | void process_new_order(order_management::new_order o); 37 | 38 | // Finds at most one match. Returns true if matched, false otherwise. 39 | bool find_match(order_management::new_order& o); 40 | 41 | // Add the order to the book. 42 | void add_order(const order_management::new_order& o); 43 | 44 | struct order 45 | { 46 | int price; 47 | std::uint64_t time; 48 | unsigned int quantity; 49 | bool operator<(const order& other) const; 50 | }; 51 | 52 | std::experimental::strand strand_; 53 | market_data_bus& market_data_bus_; 54 | std::uint64_t next_time_; 55 | std::priority_queue buy_orders_; 56 | std::priority_queue sell_orders_; 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/examples/trading/server/server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // server.cpp 3 | // ~~~~~~~~~~ 4 | // Entry point for the server. 5 | // 6 | // Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com) 7 | // 8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "connection_handler.hpp" 18 | #include "market_data_bus.hpp" 19 | #include "market_by_order.hpp" 20 | #include "order_management_bus.hpp" 21 | #include "price_time_order_book.hpp" 22 | 23 | int main(int argc, char* argv[]) 24 | { 25 | if (argc != 5) 26 | { 27 | std::cerr << "Usage: server \n"; 28 | return 1; 29 | } 30 | 31 | // Create the market-by-order data feed. 32 | market_by_order by_order(argv[1], std::atoi(argv[2])); 33 | 34 | // Create the market data bus and subscribe the data feed to it. 35 | market_data_bus md_bus; 36 | md_bus.subscribe(by_order); 37 | 38 | // Read in list of symbols and create all order books. 39 | std::ifstream symbol_file(argv[3]); 40 | std::istream_iterator symbol_iter(symbol_file), symbol_end; 41 | std::list books; 42 | for (; symbol_iter != symbol_end; ++symbol_iter) 43 | books.emplace_back(*symbol_iter, md_bus); 44 | symbol_file.close(); 45 | 46 | // Create the order management bus and subscribe all books to it. 47 | order_management_bus om_bus; 48 | for (auto& book : books) 49 | om_bus.subscribe(book); 50 | 51 | // Read in the list of ports and create all connection handlers. 52 | std::ifstream ports_file(argv[4]); 53 | std::istream_iterator ports_iter(ports_file), ports_end; 54 | std::list connections; 55 | for (; ports_iter != ports_end; ++ports_iter) 56 | connections.emplace_back(*ports_iter, om_bus); 57 | ports_file.close(); 58 | 59 | // Start all connection handlers. 60 | for (auto& connection : connections) 61 | connection.start(); 62 | 63 | // Wait for all connection handlers to exit, i.e. never. 64 | for (auto& connection : connections) 65 | connection.join(); 66 | } 67 | -------------------------------------------------------------------------------- /src/examples/trading/symbols.txt: -------------------------------------------------------------------------------- 1 | AAPL 2 | ABBV 3 | ABT 4 | ACN 5 | AIG 6 | ALL 7 | AMGN 8 | AMZN 9 | APA 10 | APC 11 | AXP 12 | BA 13 | BAC 14 | BAX 15 | BIIB 16 | BK 17 | BMY 18 | BRK.B 19 | C 20 | CAT 21 | CL 22 | CMCSA 23 | COF 24 | COP 25 | COST 26 | CSCO 27 | CVS 28 | CVX 29 | DD 30 | DIS 31 | DOW 32 | DVN 33 | EBAY 34 | EMC 35 | EMR 36 | EXC 37 | F 38 | FB 39 | FCX 40 | FDX 41 | FOXA 42 | GD 43 | GE 44 | GILD 45 | GM 46 | GOOG 47 | GS 48 | HAL 49 | HD 50 | HON 51 | HPQ 52 | IBM 53 | INTC 54 | JNJ 55 | JPM 56 | KO 57 | LLY 58 | LMT 59 | LOW 60 | MA 61 | MCD 62 | MDLZ 63 | MDT 64 | MET 65 | MMM 66 | MO 67 | MON 68 | MRK 69 | MS 70 | MSFT 71 | NKE 72 | NOV 73 | NSC 74 | ORCL 75 | OXY 76 | PEP 77 | PFE 78 | PG 79 | PM 80 | QCOM 81 | RTN 82 | SBUX 83 | SLB 84 | SO 85 | SPG 86 | T 87 | TGT 88 | TWX 89 | TXN 90 | UNH 91 | UNP 92 | UPS 93 | USB 94 | UTX 95 | V 96 | VZ 97 | WAG 98 | WFC 99 | WMT 100 | XOM 101 | -------------------------------------------------------------------------------- /src/tests/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.log 3 | *.trs 4 | void 5 | ec 6 | ep 7 | int 8 | ec_int 9 | ep_int 10 | int_int 11 | ec_int_int 12 | ep_int_int 13 | -------------------------------------------------------------------------------- /src/tests/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = \ 2 | traits \ 3 | memory \ 4 | no_executor \ 5 | executor \ 6 | system_executor \ 7 | loop_scheduler \ 8 | thread_pool \ 9 | execution_context \ 10 | strand \ 11 | timer \ 12 | performance 13 | 14 | MAINTAINERCLEANFILES = \ 15 | $(srcdir)/Makefile.in 16 | -------------------------------------------------------------------------------- /src/tests/execution_context/.gitignore: -------------------------------------------------------------------------------- 1 | service_construction 2 | service_inheritance 3 | service_ordering 4 | -------------------------------------------------------------------------------- /src/tests/execution_context/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | service_construction \ 3 | service_inheritance \ 4 | service_ordering 5 | 6 | TESTS = \ 7 | service_construction \ 8 | service_inheritance \ 9 | service_ordering 10 | 11 | AM_CXXFLAGS = -I$(srcdir)/../../../include 12 | 13 | service_construction_SOURCES = service_construction.cpp 14 | service_inheritance_SOURCES = service_inheritance.cpp 15 | service_ordering_SOURCES = service_ordering.cpp 16 | 17 | MAINTAINERCLEANFILES = \ 18 | $(srcdir)/Makefile.in 19 | -------------------------------------------------------------------------------- /src/tests/execution_context/service_construction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class service1 6 | : public std::experimental::execution_context::service 7 | { 8 | public: 9 | explicit service1(std::experimental::execution_context& ctx, int = 42) 10 | : std::experimental::execution_context::service(ctx) 11 | { 12 | } 13 | 14 | private: 15 | void shutdown_service() {} 16 | }; 17 | 18 | class service2 19 | : public std::experimental::execution_context::service 20 | { 21 | public: 22 | explicit service2(std::experimental::execution_context& ctx, int) 23 | : std::experimental::execution_context::service(ctx) 24 | { 25 | } 26 | 27 | private: 28 | void shutdown_service() {} 29 | }; 30 | 31 | int main() 32 | { 33 | { 34 | std::experimental::loop_scheduler scheduler; 35 | assert(!std::experimental::has_service(scheduler)); 36 | std::experimental::use_service(scheduler); 37 | assert(std::experimental::has_service(scheduler)); 38 | } 39 | 40 | { 41 | std::experimental::loop_scheduler scheduler; 42 | assert(!std::experimental::has_service(scheduler)); 43 | std::experimental::make_service(scheduler); 44 | assert(std::experimental::has_service(scheduler)); 45 | } 46 | 47 | { 48 | std::experimental::loop_scheduler scheduler; 49 | assert(!std::experimental::has_service(scheduler)); 50 | std::experimental::make_service(scheduler, 123); 51 | assert(std::experimental::has_service(scheduler)); 52 | } 53 | 54 | { 55 | std::experimental::loop_scheduler scheduler; 56 | assert(!std::experimental::has_service(scheduler)); 57 | try 58 | { 59 | std::experimental::use_service(scheduler); 60 | assert(0); 61 | } 62 | catch (std::bad_cast&) 63 | { 64 | } 65 | assert(!std::experimental::has_service(scheduler)); 66 | } 67 | 68 | { 69 | std::experimental::loop_scheduler scheduler; 70 | assert(!std::experimental::has_service(scheduler)); 71 | std::experimental::make_service(scheduler, 123); 72 | assert(std::experimental::has_service(scheduler)); 73 | std::experimental::use_service(scheduler); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/tests/executor/.gitignore: -------------------------------------------------------------------------------- 1 | chain_int 2 | chain_int_int 3 | chain_int_void 4 | chain_void 5 | comparisons 6 | dispatch_int 7 | dispatch_void 8 | dispatch_after_int 9 | dispatch_after_void 10 | dispatch_at_int 11 | dispatch_at_void 12 | post_int 13 | post_void 14 | wrap_dispatch_int 15 | wrap_dispatch_void 16 | wrap_dispatch_after_int 17 | wrap_dispatch_after_void 18 | wrap_dispatch_at_int 19 | wrap_dispatch_at_void 20 | wrap_post_int 21 | wrap_post_void 22 | -------------------------------------------------------------------------------- /src/tests/executor/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | chain_int \ 3 | chain_int_int \ 4 | chain_int_void \ 5 | chain_void \ 6 | comparisons \ 7 | dispatch_int \ 8 | dispatch_void \ 9 | dispatch_after_int \ 10 | dispatch_after_void \ 11 | dispatch_at_int \ 12 | dispatch_at_void \ 13 | post_int \ 14 | post_void \ 15 | wrap_dispatch_int \ 16 | wrap_dispatch_void \ 17 | wrap_dispatch_after_int \ 18 | wrap_dispatch_after_void \ 19 | wrap_dispatch_at_int \ 20 | wrap_dispatch_at_void \ 21 | wrap_post_int \ 22 | wrap_post_void 23 | 24 | TESTS = \ 25 | chain_int \ 26 | chain_int_int \ 27 | chain_int_void \ 28 | chain_void \ 29 | comparisons \ 30 | dispatch_int \ 31 | dispatch_void \ 32 | dispatch_after_int \ 33 | dispatch_after_void \ 34 | dispatch_at_int \ 35 | dispatch_at_void \ 36 | post_int \ 37 | post_void \ 38 | wrap_dispatch_int \ 39 | wrap_dispatch_void \ 40 | wrap_dispatch_after_int \ 41 | wrap_dispatch_after_void \ 42 | wrap_dispatch_at_int \ 43 | wrap_dispatch_at_void \ 44 | wrap_post_int \ 45 | wrap_post_void 46 | 47 | AM_CXXFLAGS = -I$(srcdir)/../../../include 48 | 49 | chain_int_SOURCES = chain_int.cpp 50 | chain_int_int_SOURCES = chain_int_int.cpp 51 | chain_int_void_SOURCES = chain_int_void.cpp 52 | chain_void_SOURCES = chain_void.cpp 53 | comparisons_SOURCES = comparisons.cpp 54 | dispatch_int_SOURCES = dispatch_int.cpp 55 | dispatch_void_SOURCES = dispatch_void.cpp 56 | dispatch_after_int_SOURCES = dispatch_after_int.cpp 57 | dispatch_after_void_SOURCES = dispatch_after_void.cpp 58 | dispatch_at_int_SOURCES = dispatch_at_int.cpp 59 | dispatch_at_void_SOURCES = dispatch_at_void.cpp 60 | post_int_SOURCES = post_int.cpp 61 | post_void_SOURCES = post_void.cpp 62 | wrap_dispatch_int_SOURCES = wrap_dispatch_int.cpp 63 | wrap_dispatch_void_SOURCES = wrap_dispatch_void.cpp 64 | wrap_dispatch_after_int_SOURCES = wrap_dispatch_after_int.cpp 65 | wrap_dispatch_after_void_SOURCES = wrap_dispatch_after_void.cpp 66 | wrap_dispatch_at_int_SOURCES = wrap_dispatch_at_int.cpp 67 | wrap_dispatch_at_void_SOURCES = wrap_dispatch_at_void.cpp 68 | wrap_post_int_SOURCES = wrap_post_int.cpp 69 | wrap_post_void_SOURCES = wrap_post_void.cpp 70 | 71 | MAINTAINERCLEANFILES = \ 72 | $(srcdir)/Makefile.in 73 | -------------------------------------------------------------------------------- /src/tests/executor/comparisons.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() 9 | { 10 | std::experimental::loop_scheduler scheduler; 11 | 12 | std::experimental::executor ex1 = scheduler.get_executor(); 13 | std::experimental::executor ex2 = scheduler.get_executor(); 14 | assert(ex1 == ex2); 15 | 16 | ex2 = ex1; 17 | assert(ex1 == ex2); 18 | 19 | ex1 = std::experimental::system_executor(); 20 | assert(ex1 != ex2); 21 | 22 | ex2 = std::experimental::system_executor(); 23 | assert(ex1 == ex2); 24 | 25 | std::experimental::strand s1; 26 | ex1 = s1; 27 | ex2 = s1; 28 | assert(ex1 == ex2); 29 | 30 | std::experimental::strand s2; 31 | ex1 = s2; 32 | assert(s1 != s2); 33 | assert(ex1 != ex2); 34 | 35 | std::experimental::strand s3(s1); 36 | ex1 = s3; 37 | assert(s1 == s3); 38 | assert(s2 != s3); 39 | assert(ex1 == ex2); 40 | } 41 | -------------------------------------------------------------------------------- /src/tests/loop_scheduler/.gitignore: -------------------------------------------------------------------------------- 1 | dispatch_int 2 | dispatch_void 3 | nested_dispatch 4 | post_int 5 | post_void 6 | wrap_dispatch_int 7 | wrap_dispatch_void 8 | wrap_post_int 9 | wrap_post_void 10 | -------------------------------------------------------------------------------- /src/tests/loop_scheduler/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | dispatch_int \ 3 | dispatch_void \ 4 | nested_dispatch \ 5 | post_int \ 6 | post_void \ 7 | wrap_dispatch_int \ 8 | wrap_dispatch_void \ 9 | wrap_post_int \ 10 | wrap_post_void 11 | 12 | TESTS = \ 13 | dispatch_int \ 14 | dispatch_void \ 15 | nested_dispatch \ 16 | post_int \ 17 | post_void \ 18 | wrap_dispatch_int \ 19 | wrap_dispatch_void \ 20 | wrap_post_int \ 21 | wrap_post_void 22 | 23 | AM_CXXFLAGS = -I$(srcdir)/../../../include 24 | 25 | dispatch_int_SOURCES = dispatch_int.cpp 26 | dispatch_void_SOURCES = dispatch_void.cpp 27 | nested_dispatch_SOURCES = nested_dispatch.cpp 28 | post_int_SOURCES = post_int.cpp 29 | post_void_SOURCES = post_void.cpp 30 | wrap_dispatch_int_SOURCES = wrap_dispatch_int.cpp 31 | wrap_dispatch_void_SOURCES = wrap_dispatch_void.cpp 32 | wrap_post_int_SOURCES = wrap_post_int.cpp 33 | wrap_post_void_SOURCES = wrap_post_void.cpp 34 | 35 | MAINTAINERCLEANFILES = \ 36 | $(srcdir)/Makefile.in 37 | -------------------------------------------------------------------------------- /src/tests/loop_scheduler/nested_dispatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::experimental::loop_scheduler scheduler; 8 | auto ex = scheduler.get_executor(); 9 | 10 | int count = 0; 11 | 12 | std::experimental::post(ex, 13 | [&]() 14 | { 15 | int count_before_dispatch = count; 16 | std::experimental::dispatch(ex, [&](){ ++count; }); 17 | assert(count == count_before_dispatch + 1); 18 | }); 19 | 20 | int count_before_dispatch = count; 21 | std::experimental::dispatch(ex, [&](){ ++count; }); 22 | assert(count == count_before_dispatch); 23 | 24 | scheduler.run(); 25 | assert(count == 2); 26 | } 27 | -------------------------------------------------------------------------------- /src/tests/memory/.gitignore: -------------------------------------------------------------------------------- 1 | get_associated_allocator 2 | -------------------------------------------------------------------------------- /src/tests/memory/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | get_associated_allocator 3 | 4 | TESTS = \ 5 | get_associated_allocator 6 | 7 | AM_CXXFLAGS = -I$(srcdir)/../../../include 8 | 9 | get_associated_allocator_SOURCES = get_associated_allocator.cpp 10 | 11 | MAINTAINERCLEANFILES = \ 12 | $(srcdir)/Makefile.in 13 | -------------------------------------------------------------------------------- /src/tests/memory/get_associated_allocator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct uses_char_allocator 4 | { 5 | typedef std::allocator allocator_type; 6 | 7 | allocator_type get_allocator() const noexcept 8 | { 9 | return allocator_type(); 10 | } 11 | }; 12 | 13 | template 14 | class my_allocator : public std::allocator 15 | { 16 | }; 17 | 18 | int main() 19 | { 20 | std::allocator a1 = std::experimental::get_associated_allocator([]{}); 21 | std::allocator a2 = std::experimental::get_associated_allocator(uses_char_allocator()); 22 | my_allocator a3 = std::experimental::get_associated_allocator([]{}, my_allocator()); 23 | std::allocator a4 = std::experimental::get_associated_allocator(uses_char_allocator(), my_allocator()); 24 | 25 | (void)a1; 26 | (void)a2; 27 | (void)a3; 28 | (void)a4; 29 | } 30 | -------------------------------------------------------------------------------- /src/tests/no_executor/.gitignore: -------------------------------------------------------------------------------- 1 | chain_int 2 | chain_int_int 3 | chain_int_void 4 | chain_void 5 | dispatch_int 6 | dispatch_void 7 | dispatch_after_int 8 | dispatch_after_void 9 | dispatch_at_int 10 | dispatch_at_void 11 | post_int 12 | post_void 13 | -------------------------------------------------------------------------------- /src/tests/no_executor/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | chain_int \ 3 | chain_int_int \ 4 | chain_int_void \ 5 | chain_void \ 6 | dispatch_int \ 7 | dispatch_void \ 8 | dispatch_after_int \ 9 | dispatch_after_void \ 10 | dispatch_at_int \ 11 | dispatch_at_void \ 12 | post_int \ 13 | post_void 14 | 15 | TESTS = \ 16 | chain_int \ 17 | chain_int_int \ 18 | chain_int_void \ 19 | chain_void \ 20 | dispatch_int \ 21 | dispatch_void \ 22 | dispatch_after_int \ 23 | dispatch_after_void \ 24 | dispatch_at_int \ 25 | dispatch_at_void \ 26 | post_int \ 27 | post_void 28 | 29 | AM_CXXFLAGS = -I$(srcdir)/../../../include 30 | 31 | chain_int_SOURCES = chain_int.cpp 32 | chain_int_int_SOURCES = chain_int_int.cpp 33 | chain_int_void_SOURCES = chain_int_void.cpp 34 | chain_void_SOURCES = chain_void.cpp 35 | dispatch_int_SOURCES = dispatch_int.cpp 36 | dispatch_void_SOURCES = dispatch_void.cpp 37 | dispatch_after_int_SOURCES = dispatch_after_int.cpp 38 | dispatch_after_void_SOURCES = dispatch_after_void.cpp 39 | dispatch_at_int_SOURCES = dispatch_at_int.cpp 40 | dispatch_at_void_SOURCES = dispatch_at_void.cpp 41 | post_int_SOURCES = post_int.cpp 42 | post_void_SOURCES = post_void.cpp 43 | 44 | MAINTAINERCLEANFILES = \ 45 | $(srcdir)/Makefile.in 46 | -------------------------------------------------------------------------------- /src/tests/performance/.gitignore: -------------------------------------------------------------------------------- 1 | function_context_switch 2 | yield_channel 3 | yield_context_switch 4 | -------------------------------------------------------------------------------- /src/tests/performance/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | function_context_switch \ 3 | yield_channel \ 4 | yield_context_switch 5 | 6 | AM_CXXFLAGS = -I$(srcdir)/../../../include 7 | 8 | function_context_switch_SOURCES = function_context_switch.cpp 9 | yield_channel_SOURCES = yield_channel.cpp 10 | yield_context_switch_SOURCES = yield_context_switch.cpp 11 | 12 | MAINTAINERCLEANFILES = \ 13 | $(srcdir)/Makefile.in 14 | -------------------------------------------------------------------------------- /src/tests/performance/function_context_switch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::experimental; 6 | 7 | const int chains = 4; 8 | const int iterations = 1000000; 9 | 10 | void chain(loop_scheduler::executor_type ex, int i) 11 | { 12 | if (i < iterations) 13 | post(wrap(ex, [=]{ chain(ex, i + 1); })); 14 | } 15 | 16 | int main() 17 | { 18 | loop_scheduler s(1); 19 | auto ex = s.get_executor(); 20 | 21 | for (int c = 0; c < chains; ++c) 22 | dispatch(wrap(ex, [=]{ chain(ex, 0); })); 23 | 24 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 25 | s.run(); 26 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 27 | 28 | std::cout << "time per switch: "; 29 | std::chrono::steady_clock::duration per_iteration = elapsed / iterations / chains; 30 | std::cout << std::chrono::duration_cast(per_iteration).count(); 31 | std::cout << " nanoseconds\n"; 32 | 33 | std::cout << "switches per second: "; 34 | std::cout << (std::chrono::seconds(1) / per_iteration) << "\n"; 35 | } 36 | -------------------------------------------------------------------------------- /src/tests/performance/yield_channel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std::experimental; 8 | 9 | const int iterations = 100000; 10 | 11 | int main() 12 | { 13 | loop_scheduler s(1); 14 | auto ex = s.get_executor(); 15 | 16 | channel ch1(s); 17 | channel ch2(s); 18 | 19 | dispatch( 20 | wrap(ex, 21 | [&](basic_yield_context yield) 22 | { 23 | for (int i = 0; i < iterations; ++i) 24 | { 25 | ch1.put(i, yield); 26 | ch2.get(yield); 27 | } 28 | })); 29 | 30 | dispatch( 31 | wrap(ex, 32 | [&](basic_yield_context yield) 33 | { 34 | for (int i = 0; i < iterations; ++i) 35 | { 36 | ch1.get(yield); 37 | ch2.put(i, yield); 38 | } 39 | })); 40 | 41 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 42 | s.run(); 43 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 44 | 45 | std::cout << "time per switch: "; 46 | std::chrono::steady_clock::duration per_iteration = elapsed / iterations; 47 | std::cout << std::chrono::duration_cast(per_iteration).count(); 48 | std::cout << " nanoseconds\n"; 49 | 50 | std::cout << "switches per second: "; 51 | std::cout << (std::chrono::seconds(1) / per_iteration) << "\n"; 52 | } 53 | -------------------------------------------------------------------------------- /src/tests/performance/yield_context_switch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std::experimental; 7 | 8 | const int chains = 4; 9 | const int iterations = 1000000; 10 | 11 | int main() 12 | { 13 | loop_scheduler s(1); 14 | auto ex = s.get_executor(); 15 | 16 | for (int c = 0; c < chains; ++c) 17 | { 18 | dispatch( 19 | wrap(ex, 20 | [](basic_yield_context yield) 21 | { 22 | for (int i = 0; i < iterations; ++i) 23 | { 24 | post(yield); 25 | } 26 | })); 27 | } 28 | 29 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 30 | s.run(); 31 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 32 | 33 | std::cout << "time per switch: "; 34 | std::chrono::steady_clock::duration per_iteration = elapsed / iterations / chains; 35 | std::cout << std::chrono::duration_cast(per_iteration).count(); 36 | std::cout << " nanoseconds\n"; 37 | 38 | std::cout << "switches per second: "; 39 | std::cout << (std::chrono::seconds(1) / per_iteration) << "\n"; 40 | } 41 | -------------------------------------------------------------------------------- /src/tests/strand/.gitignore: -------------------------------------------------------------------------------- 1 | dispatch_int 2 | dispatch_void 3 | nested_dispatch 4 | post_int 5 | post_void 6 | sequential 7 | wrap_dispatch_int 8 | wrap_dispatch_void 9 | wrap_post_int 10 | wrap_post_void 11 | -------------------------------------------------------------------------------- /src/tests/strand/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | dispatch_int \ 3 | dispatch_void \ 4 | nested_dispatch \ 5 | post_int \ 6 | post_void \ 7 | sequential \ 8 | wrap_dispatch_int \ 9 | wrap_dispatch_void \ 10 | wrap_post_int \ 11 | wrap_post_void 12 | 13 | TESTS = \ 14 | dispatch_int \ 15 | dispatch_void \ 16 | nested_dispatch \ 17 | post_int \ 18 | post_void \ 19 | sequential \ 20 | wrap_dispatch_int \ 21 | wrap_dispatch_void \ 22 | wrap_post_int \ 23 | wrap_post_void 24 | 25 | AM_CXXFLAGS = -I$(srcdir)/../../../include 26 | 27 | dispatch_int_SOURCES = dispatch_int.cpp 28 | dispatch_void_SOURCES = dispatch_void.cpp 29 | nested_dispatch_SOURCES = nested_dispatch.cpp 30 | post_int_SOURCES = post_int.cpp 31 | post_void_SOURCES = post_void.cpp 32 | sequential_SOURCES = sequential.cpp 33 | wrap_dispatch_int_SOURCES = wrap_dispatch_int.cpp 34 | wrap_dispatch_void_SOURCES = wrap_dispatch_void.cpp 35 | wrap_post_int_SOURCES = wrap_post_int.cpp 36 | wrap_post_void_SOURCES = wrap_post_void.cpp 37 | 38 | MAINTAINERCLEANFILES = \ 39 | $(srcdir)/Makefile.in 40 | -------------------------------------------------------------------------------- /src/tests/strand/nested_dispatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::experimental::loop_scheduler scheduler; 9 | auto ex = make_strand(scheduler.get_executor()); 10 | 11 | int count = 0; 12 | 13 | std::experimental::post(ex, 14 | [&]() 15 | { 16 | int count_before_dispatch = count; 17 | std::experimental::dispatch(ex, [&](){ ++count; }); 18 | assert(count == count_before_dispatch + 1); 19 | }); 20 | 21 | int count_before_dispatch = count; 22 | std::experimental::dispatch(ex, [&](){ ++count; }); 23 | assert(count == count_before_dispatch); 24 | 25 | scheduler.run(); 26 | assert(count == 2); 27 | } 28 | -------------------------------------------------------------------------------- /src/tests/strand/sequential.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int count = 0; 9 | 10 | int main() 11 | { 12 | std::experimental::loop_scheduler scheduler; 13 | auto ex = make_strand(scheduler.get_executor()); 14 | 15 | for (int i = 0; i < 10; ++i) 16 | { 17 | std::experimental::post(ex, [] 18 | { 19 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 20 | ++count; 21 | }); 22 | } 23 | 24 | std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); 25 | 26 | std::thread thread([&]{ scheduler.run(); }); 27 | scheduler.run(); 28 | thread.join(); 29 | 30 | std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; 31 | 32 | assert(count == 10); 33 | assert(elapsed >= std::chrono::seconds(1)); 34 | } 35 | -------------------------------------------------------------------------------- /src/tests/system_executor/.gitignore: -------------------------------------------------------------------------------- 1 | dispatch_int 2 | dispatch_void 3 | post_int 4 | post_void 5 | wrap_dispatch_int 6 | wrap_dispatch_void 7 | wrap_post_int 8 | wrap_post_void 9 | -------------------------------------------------------------------------------- /src/tests/system_executor/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | dispatch_int \ 3 | dispatch_void \ 4 | post_int \ 5 | post_void \ 6 | wrap_dispatch_int \ 7 | wrap_dispatch_void \ 8 | wrap_post_int \ 9 | wrap_post_void 10 | 11 | TESTS = \ 12 | dispatch_int \ 13 | dispatch_void \ 14 | post_int \ 15 | post_void \ 16 | wrap_dispatch_int \ 17 | wrap_dispatch_void \ 18 | wrap_post_int \ 19 | wrap_post_void 20 | 21 | AM_CXXFLAGS = -I$(srcdir)/../../../include 22 | 23 | dispatch_int_SOURCES = dispatch_int.cpp 24 | dispatch_void_SOURCES = dispatch_void.cpp 25 | post_int_SOURCES = post_int.cpp 26 | post_void_SOURCES = post_void.cpp 27 | wrap_dispatch_int_SOURCES = wrap_dispatch_int.cpp 28 | wrap_dispatch_void_SOURCES = wrap_dispatch_void.cpp 29 | wrap_post_int_SOURCES = wrap_post_int.cpp 30 | wrap_post_void_SOURCES = wrap_post_void.cpp 31 | 32 | MAINTAINERCLEANFILES = \ 33 | $(srcdir)/Makefile.in 34 | -------------------------------------------------------------------------------- /src/tests/thread_pool/.gitignore: -------------------------------------------------------------------------------- 1 | dispatch_int 2 | dispatch_void 3 | dispatch_after_int 4 | dispatch_after_void 5 | dispatch_at_int 6 | dispatch_at_void 7 | get_associated_executor 8 | make_work 9 | nested_dispatch 10 | post_int 11 | post_void 12 | wrap_dispatch_int 13 | wrap_dispatch_void 14 | wrap_post_int 15 | wrap_post_void 16 | -------------------------------------------------------------------------------- /src/tests/thread_pool/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | dispatch_int \ 3 | dispatch_void \ 4 | dispatch_after_int \ 5 | dispatch_after_void \ 6 | dispatch_at_int \ 7 | dispatch_at_void \ 8 | get_associated_executor \ 9 | make_work \ 10 | nested_dispatch \ 11 | post_int \ 12 | post_void \ 13 | wrap_dispatch_int \ 14 | wrap_dispatch_void \ 15 | wrap_post_int \ 16 | wrap_post_void 17 | 18 | TESTS = \ 19 | dispatch_int \ 20 | dispatch_void \ 21 | dispatch_after_int \ 22 | dispatch_after_void \ 23 | dispatch_at_int \ 24 | dispatch_at_void \ 25 | get_associated_executor \ 26 | make_work \ 27 | nested_dispatch \ 28 | post_int \ 29 | post_void \ 30 | wrap_dispatch_int \ 31 | wrap_dispatch_void \ 32 | wrap_post_int \ 33 | wrap_post_void 34 | 35 | AM_CXXFLAGS = -I$(srcdir)/../../../include 36 | 37 | dispatch_int_SOURCES = dispatch_int.cpp 38 | dispatch_void_SOURCES = dispatch_void.cpp 39 | dispatch_after_int_SOURCES = dispatch_after_int.cpp 40 | dispatch_after_void_SOURCES = dispatch_after_void.cpp 41 | dispatch_at_int_SOURCES = dispatch_at_int.cpp 42 | dispatch_at_void_SOURCES = dispatch_at_void.cpp 43 | get_associated_executor_SOURCES = get_associated_executor.cpp 44 | make_work_SOURCES = make_work.cpp 45 | nested_dispatch_SOURCES = nested_dispatch.cpp 46 | post_int_SOURCES = post_int.cpp 47 | post_void_SOURCES = post_void.cpp 48 | wrap_dispatch_int_SOURCES = wrap_dispatch_int.cpp 49 | wrap_dispatch_void_SOURCES = wrap_dispatch_void.cpp 50 | wrap_post_int_SOURCES = wrap_post_int.cpp 51 | wrap_post_void_SOURCES = wrap_post_void.cpp 52 | 53 | MAINTAINERCLEANFILES = \ 54 | $(srcdir)/Makefile.in 55 | -------------------------------------------------------------------------------- /src/tests/thread_pool/get_associated_executor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::experimental::thread_pool pool; 7 | typedef std::experimental::thread_pool::executor_type executor; 8 | 9 | executor e1 = std::experimental::get_associated_executor(std::experimental::wrap(pool, []{})); 10 | executor e2 = std::experimental::get_associated_executor([]{}, pool.get_executor()); 11 | executor e3 = std::experimental::get_associated_executor([]{}, pool); 12 | 13 | (void)e1; 14 | (void)e2; 15 | (void)e3; 16 | } 17 | -------------------------------------------------------------------------------- /src/tests/thread_pool/make_work.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::experimental::thread_pool pool; 7 | typedef std::experimental::executor_work work; 8 | 9 | work w1 = std::experimental::make_work(pool.get_executor()); 10 | work w2 = std::experimental::make_work(pool); 11 | work w3 = std::experimental::make_work(std::experimental::wrap(pool, []{})); 12 | work w4 = std::experimental::make_work([]{}, pool.get_executor()); 13 | work w5 = std::experimental::make_work([]{}, pool); 14 | 15 | w1.reset(); 16 | w2.reset(); 17 | w3.reset(); 18 | w4.reset(); 19 | w5.reset(); 20 | 21 | pool.join(); 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/thread_pool/nested_dispatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::experimental::thread_pool pool(1); 8 | auto ex = pool.get_executor(); 9 | 10 | int count = 0; 11 | std::experimental::post(ex, 12 | [&]() 13 | { 14 | int count_before_dispatch = count; 15 | std::experimental::dispatch(ex, [&](){ ++count; }); 16 | assert(count == count_before_dispatch + 1); 17 | }); 18 | 19 | pool.join(); 20 | assert(count == 1); 21 | } 22 | -------------------------------------------------------------------------------- /src/tests/timer/.gitignore: -------------------------------------------------------------------------------- 1 | async_wait 2 | cancel 3 | wait 4 | -------------------------------------------------------------------------------- /src/tests/timer/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | async_wait \ 3 | cancel \ 4 | wait 5 | 6 | TESTS = \ 7 | async_wait \ 8 | cancel \ 9 | wait 10 | 11 | AM_CXXFLAGS = -I$(srcdir)/../../../include 12 | 13 | async_wait_SOURCES = async_wait.cpp 14 | cancel_SOURCES = cancel.cpp 15 | wait_SOURCES = wait.cpp 16 | 17 | MAINTAINERCLEANFILES = \ 18 | $(srcdir)/Makefile.in 19 | -------------------------------------------------------------------------------- /src/tests/timer/async_wait.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::atomic success_count; 6 | 7 | void handler1(std::error_code ec) 8 | { 9 | if (!ec) ++success_count; 10 | } 11 | 12 | struct handler2 13 | { 14 | handler2() {} 15 | void operator()(std::error_code ec) { if (!ec) ++success_count; } 16 | }; 17 | 18 | struct handler3 19 | { 20 | handler3() {} 21 | handler3(const handler3&) = delete; 22 | handler3(handler3&&) {} 23 | void operator()(std::error_code ec) && { if (!ec) ++success_count; } 24 | }; 25 | 26 | int main() 27 | { 28 | handler2 h2; 29 | const handler2 ch2; 30 | handler3 h3; 31 | 32 | std::experimental::steady_timer t1(std::chrono::milliseconds(100)); 33 | t1.wait(handler1); 34 | 35 | std::experimental::steady_timer t2(std::chrono::milliseconds(100)); 36 | t2.wait(&handler1); 37 | 38 | std::experimental::steady_timer t3(std::chrono::milliseconds(100)); 39 | t3.wait(handler2()); 40 | 41 | std::experimental::steady_timer t4(std::chrono::milliseconds(100)); 42 | t4.wait(h2); 43 | 44 | std::experimental::steady_timer t5(std::chrono::milliseconds(100)); 45 | t5.wait(ch2); 46 | 47 | std::experimental::steady_timer t6(std::chrono::milliseconds(100)); 48 | t6.wait(handler3()); 49 | 50 | std::experimental::steady_timer t7(std::chrono::milliseconds(100)); 51 | t7.wait(std::move(h3)); 52 | 53 | std::experimental::steady_timer t8(std::chrono::milliseconds(100)); 54 | std::future fut1 = t8.wait(std::experimental::use_future); 55 | fut1.get(); 56 | 57 | std::experimental::steady_timer t9(std::chrono::milliseconds(100)); 58 | t9.wait(handler1); 59 | std::experimental::steady_timer t10(std::move(t9)); 60 | 61 | std::experimental::steady_timer t11(std::chrono::milliseconds(100)); 62 | t11.wait(&handler1); 63 | std::experimental::steady_timer t12(std::move(t10)); 64 | 65 | std::experimental::steady_timer t13(std::chrono::milliseconds(100)); 66 | t13.wait(handler2()); 67 | std::experimental::steady_timer t14(std::move(t13)); 68 | 69 | std::experimental::steady_timer t15(std::chrono::milliseconds(100)); 70 | t15.wait(h2); 71 | std::experimental::steady_timer t16(std::move(t15)); 72 | 73 | std::experimental::steady_timer t17(std::chrono::milliseconds(100)); 74 | t17.wait(ch2); 75 | std::experimental::steady_timer t18(std::move(t17)); 76 | 77 | std::experimental::steady_timer t19(std::chrono::milliseconds(100)); 78 | t19.wait(handler3()); 79 | std::experimental::steady_timer t20(std::move(t19)); 80 | 81 | std::experimental::steady_timer t21(std::chrono::milliseconds(100)); 82 | t21.wait(std::move(h3)); 83 | std::experimental::steady_timer t22(std::move(t21)); 84 | 85 | std::experimental::steady_timer t23(std::chrono::milliseconds(100)); 86 | std::future fut2 = t23.wait(std::experimental::use_future); 87 | std::experimental::steady_timer t24(std::move(t23)); 88 | fut2.get(); 89 | 90 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 91 | assert(success_count == 14); 92 | } 93 | -------------------------------------------------------------------------------- /src/tests/timer/cancel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::atomic success_count; 5 | std::atomic failure_count; 6 | 7 | void handler1(std::error_code ec) 8 | { 9 | if (!ec) ++success_count; else ++failure_count; 10 | } 11 | 12 | int main() 13 | { 14 | std::experimental::steady_timer t1(std::chrono::seconds(1)); 15 | 16 | t1.wait(handler1); 17 | t1.wait(handler1); 18 | t1.wait(handler1); 19 | t1.wait(handler1); 20 | t1.wait(handler1); 21 | t1.wait(handler1); 22 | t1.wait(handler1); 23 | t1.wait(handler1); 24 | 25 | assert(success_count == 0); 26 | assert(failure_count == 0); 27 | 28 | t1.cancel_one(); 29 | 30 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 31 | assert(success_count == 0); 32 | assert(failure_count == 1); 33 | 34 | t1.cancel_one(); 35 | 36 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 37 | assert(success_count == 0); 38 | assert(failure_count == 2); 39 | 40 | t1.cancel(); 41 | 42 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 43 | assert(success_count == 0); 44 | assert(failure_count == 8); 45 | } 46 | -------------------------------------------------------------------------------- /src/tests/timer/wait.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | { 6 | std::experimental::steady_timer t1; 7 | t1.expires_after(std::chrono::milliseconds(100)); 8 | t1.wait(); 9 | } 10 | 11 | { 12 | std::experimental::steady_timer t1; 13 | t1.expires_at(std::chrono::steady_clock::now() + std::chrono::milliseconds(100)); 14 | t1.wait(); 15 | } 16 | 17 | { 18 | std::experimental::steady_timer t1(std::chrono::milliseconds(100)); 19 | t1.wait(); 20 | } 21 | 22 | { 23 | std::experimental::steady_timer t1(std::chrono::steady_clock::now() + std::chrono::milliseconds(100)); 24 | t1.wait(); 25 | } 26 | 27 | { 28 | std::experimental::steady_timer t1; 29 | t1.expires_after(std::chrono::milliseconds(100)); 30 | std::experimental::steady_timer t2(std::move(t1)); 31 | t2.wait(); 32 | } 33 | 34 | { 35 | std::experimental::steady_timer t1; 36 | t1.expires_at(std::chrono::steady_clock::now() + std::chrono::milliseconds(100)); 37 | std::experimental::steady_timer t2(std::move(t1)); 38 | t2.wait(); 39 | } 40 | 41 | { 42 | std::experimental::steady_timer t1(std::chrono::milliseconds(100)); 43 | std::experimental::steady_timer t2(std::move(t1)); 44 | t2.wait(); 45 | } 46 | 47 | { 48 | std::experimental::steady_timer t1(std::chrono::steady_clock::now() + std::chrono::milliseconds(100)); 49 | std::experimental::steady_timer t2(std::move(t1)); 50 | t2.wait(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/tests/traits/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = \ 2 | void \ 3 | ec \ 4 | ep \ 5 | int \ 6 | ec_int \ 7 | ep_int \ 8 | int_int \ 9 | ec_int_int \ 10 | ep_int_int 11 | 12 | TESTS = \ 13 | void \ 14 | ec \ 15 | ep \ 16 | int \ 17 | ec_int \ 18 | ep_int \ 19 | int_int \ 20 | ec_int_int \ 21 | ep_int_int 22 | 23 | AM_CXXFLAGS = -I$(srcdir)/../../../include 24 | 25 | void_SOURCES = void.cpp 26 | ec_SOURCES = ec.cpp 27 | ep_SOURCES = ep.cpp 28 | int_SOURCES = int.cpp 29 | ec_int_SOURCES = ec_int.cpp 30 | ep_int_SOURCES = ep_int.cpp 31 | int_int_SOURCES = int_int.cpp 32 | ec_int_int_SOURCES = ec_int_int.cpp 33 | ep_int_int_SOURCES = ep_int_int.cpp 34 | 35 | MAINTAINERCLEANFILES = \ 36 | $(srcdir)/Makefile.in 37 | -------------------------------------------------------------------------------- /src/tests/traits/ec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | auto async_foo(bool fail, CompletionToken&& tok) 8 | { 9 | std::experimental::async_completion completion(tok); 10 | 11 | if (fail) 12 | std::move(completion.handler)(make_error_code(std::errc::invalid_argument)); 13 | else 14 | std::move(completion.handler)(std::error_code()); 15 | 16 | return completion.result.get(); 17 | } 18 | 19 | int success_count = 0; 20 | int fail_count = 0; 21 | 22 | void handler1(const std::error_code& e) 23 | { 24 | e ? ++fail_count : ++success_count; 25 | } 26 | 27 | struct handler2 28 | { 29 | handler2() {} 30 | void operator()(const std::error_code& e) 31 | { 32 | e ? ++fail_count : ++success_count; 33 | } 34 | }; 35 | 36 | struct handler3 37 | { 38 | handler3() {} 39 | handler3(const handler3&) = delete; 40 | handler3(handler3&&) {} 41 | void operator()(const std::error_code& e) && 42 | { 43 | e ? ++fail_count : ++success_count; 44 | } 45 | }; 46 | 47 | int main() 48 | { 49 | async_foo(false, handler1); 50 | async_foo(true, handler1); 51 | 52 | async_foo(false, &handler1); 53 | async_foo(true, &handler1); 54 | 55 | async_foo(false, handler2()); 56 | async_foo(true, handler2()); 57 | 58 | handler2 h1; 59 | async_foo(false, h1); 60 | async_foo(true, h1); 61 | 62 | const handler2 h2; 63 | async_foo(false, h2); 64 | async_foo(true, h2); 65 | 66 | async_foo(false, handler3()); 67 | async_foo(true, handler3()); 68 | 69 | handler3 h3, h4; 70 | async_foo(false, std::move(h3)); 71 | async_foo(true, std::move(h4)); 72 | 73 | async_foo(false, [](std::error_code e){ e ? ++fail_count : ++success_count; }); 74 | async_foo(true, [](std::error_code e){ e ? ++fail_count : ++success_count; }); 75 | 76 | std::future f1 = async_foo(false, std::experimental::use_future); 77 | try 78 | { 79 | f1.get(); 80 | ++success_count; 81 | } 82 | catch (...) 83 | { 84 | ++fail_count; 85 | } 86 | 87 | std::future f2 = async_foo(true, std::experimental::use_future); 88 | try 89 | { 90 | f2.get(); 91 | ++success_count; 92 | } 93 | catch (...) 94 | { 95 | ++fail_count; 96 | } 97 | 98 | assert(success_count == 9); 99 | assert(fail_count == 9); 100 | } 101 | -------------------------------------------------------------------------------- /src/tests/traits/ec_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | auto async_foo(bool fail, CompletionToken&& tok) 8 | { 9 | std::experimental::async_completion completion(tok); 10 | 11 | if (fail) 12 | std::move(completion.handler)(make_error_code(std::errc::invalid_argument), 1); 13 | else 14 | std::move(completion.handler)(std::error_code(), 1); 15 | 16 | return completion.result.get(); 17 | } 18 | 19 | int success_count = 0; 20 | int fail_count = 0; 21 | 22 | void handler1(const std::error_code& e, int) 23 | { 24 | e ? ++fail_count : ++success_count; 25 | } 26 | 27 | struct handler2 28 | { 29 | handler2() {} 30 | void operator()(const std::error_code& e, int) 31 | { 32 | e ? ++fail_count : ++success_count; 33 | } 34 | }; 35 | 36 | struct handler3 37 | { 38 | handler3() {} 39 | handler3(const handler3&) = delete; 40 | handler3(handler3&&) {} 41 | void operator()(const std::error_code& e, int) && 42 | { 43 | e ? ++fail_count : ++success_count; 44 | } 45 | }; 46 | 47 | int main() 48 | { 49 | async_foo(false, handler1); 50 | async_foo(true, handler1); 51 | 52 | async_foo(false, &handler1); 53 | async_foo(true, &handler1); 54 | 55 | async_foo(false, handler2()); 56 | async_foo(true, handler2()); 57 | 58 | handler2 h1; 59 | async_foo(false, h1); 60 | async_foo(true, h1); 61 | 62 | const handler2 h2; 63 | async_foo(false, h2); 64 | async_foo(true, h2); 65 | 66 | async_foo(false, handler3()); 67 | async_foo(true, handler3()); 68 | 69 | handler3 h3, h4; 70 | async_foo(false, std::move(h3)); 71 | async_foo(true, std::move(h4)); 72 | 73 | async_foo(false, [](std::error_code e, int){ e ? ++fail_count : ++success_count; }); 74 | async_foo(true, [](std::error_code e, int){ e ? ++fail_count : ++success_count; }); 75 | 76 | std::future f1 = async_foo(false, std::experimental::use_future); 77 | try 78 | { 79 | int v = f1.get(); 80 | assert(v == 1); 81 | ++success_count; 82 | } 83 | catch (...) 84 | { 85 | ++fail_count; 86 | } 87 | 88 | std::future f2 = async_foo(true, std::experimental::use_future); 89 | try 90 | { 91 | f2.get(); 92 | ++success_count; 93 | } 94 | catch (...) 95 | { 96 | ++fail_count; 97 | } 98 | 99 | assert(success_count == 9); 100 | assert(fail_count == 9); 101 | } 102 | -------------------------------------------------------------------------------- /src/tests/traits/ec_int_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | auto async_foo(bool fail, CompletionToken&& tok) 8 | { 9 | std::experimental::async_completion completion(tok); 10 | 11 | if (fail) 12 | std::move(completion.handler)(make_error_code(std::errc::invalid_argument), 1, 2); 13 | else 14 | std::move(completion.handler)(std::error_code(), 1, 2); 15 | 16 | return completion.result.get(); 17 | } 18 | 19 | int success_count = 0; 20 | int fail_count = 0; 21 | 22 | void handler1(const std::error_code& e, int, int) 23 | { 24 | e ? ++fail_count : ++success_count; 25 | } 26 | 27 | struct handler2 28 | { 29 | handler2() {} 30 | void operator()(const std::error_code& e, int, int) 31 | { 32 | e ? ++fail_count : ++success_count; 33 | } 34 | }; 35 | 36 | struct handler3 37 | { 38 | handler3() {} 39 | handler3(const handler3&) = delete; 40 | handler3(handler3&&) {} 41 | void operator()(const std::error_code& e, int, int) && 42 | { 43 | e ? ++fail_count : ++success_count; 44 | } 45 | }; 46 | 47 | int main() 48 | { 49 | async_foo(false, handler1); 50 | async_foo(true, handler1); 51 | 52 | async_foo(false, &handler1); 53 | async_foo(true, &handler1); 54 | 55 | async_foo(false, handler2()); 56 | async_foo(true, handler2()); 57 | 58 | handler2 h1; 59 | async_foo(false, h1); 60 | async_foo(true, h1); 61 | 62 | const handler2 h2; 63 | async_foo(false, h2); 64 | async_foo(true, h2); 65 | 66 | async_foo(false, handler3()); 67 | async_foo(true, handler3()); 68 | 69 | handler3 h3, h4; 70 | async_foo(false, std::move(h3)); 71 | async_foo(true, std::move(h4)); 72 | 73 | async_foo(false, [](std::error_code e, int, int){ e ? ++fail_count : ++success_count; }); 74 | async_foo(true, [](std::error_code e, int, int){ e ? ++fail_count : ++success_count; }); 75 | 76 | std::future> f1 = async_foo(false, std::experimental::use_future); 77 | try 78 | { 79 | f1.get(); 80 | ++success_count; 81 | } 82 | catch (...) 83 | { 84 | ++fail_count; 85 | } 86 | 87 | std::future> f2 = async_foo(true, std::experimental::use_future); 88 | try 89 | { 90 | f2.get(); 91 | ++success_count; 92 | } 93 | catch (...) 94 | { 95 | ++fail_count; 96 | } 97 | 98 | assert(success_count == 9); 99 | assert(fail_count == 9); 100 | } 101 | -------------------------------------------------------------------------------- /src/tests/traits/ep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | auto async_foo(bool fail, CompletionToken&& tok) 8 | { 9 | std::experimental::async_completion completion(tok); 10 | 11 | try 12 | { 13 | if (fail) 14 | throw std::runtime_error("fail"); 15 | 16 | std::move(completion.handler)(std::exception_ptr()); 17 | } 18 | catch (...) 19 | { 20 | std::move(completion.handler)(std::current_exception()); 21 | } 22 | 23 | return completion.result.get(); 24 | } 25 | 26 | int success_count = 0; 27 | int fail_count = 0; 28 | 29 | void handler1(const std::exception_ptr& e) 30 | { 31 | e ? ++fail_count : ++success_count; 32 | } 33 | 34 | struct handler2 35 | { 36 | handler2() {} 37 | void operator()(const std::exception_ptr& e) 38 | { 39 | e ? ++fail_count : ++success_count; 40 | } 41 | }; 42 | 43 | struct handler3 44 | { 45 | handler3() {} 46 | handler3(const handler3&) = delete; 47 | handler3(handler3&&) {} 48 | void operator()(const std::exception_ptr& e) && 49 | { 50 | e ? ++fail_count : ++success_count; 51 | } 52 | }; 53 | 54 | int main() 55 | { 56 | async_foo(false, handler1); 57 | async_foo(true, handler1); 58 | 59 | async_foo(false, &handler1); 60 | async_foo(true, &handler1); 61 | 62 | async_foo(false, handler2()); 63 | async_foo(true, handler2()); 64 | 65 | handler2 h1; 66 | async_foo(false, h1); 67 | async_foo(true, h1); 68 | 69 | const handler2 h2; 70 | async_foo(false, h2); 71 | async_foo(true, h2); 72 | 73 | async_foo(false, handler3()); 74 | async_foo(true, handler3()); 75 | 76 | handler3 h3, h4; 77 | async_foo(false, std::move(h3)); 78 | async_foo(true, std::move(h4)); 79 | 80 | async_foo(false, [](std::exception_ptr e){ e ? ++fail_count : ++success_count; }); 81 | async_foo(true, [](std::exception_ptr e){ e ? ++fail_count : ++success_count; }); 82 | 83 | std::future f1 = async_foo(false, std::experimental::use_future); 84 | try 85 | { 86 | f1.get(); 87 | ++success_count; 88 | } 89 | catch (...) 90 | { 91 | ++fail_count; 92 | } 93 | 94 | std::future f2 = async_foo(true, std::experimental::use_future); 95 | try 96 | { 97 | f2.get(); 98 | ++success_count; 99 | } 100 | catch (...) 101 | { 102 | ++fail_count; 103 | } 104 | 105 | assert(success_count == 9); 106 | assert(fail_count == 9); 107 | } 108 | -------------------------------------------------------------------------------- /src/tests/traits/ep_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | auto async_foo(bool fail, CompletionToken&& tok) 8 | { 9 | std::experimental::async_completion completion(tok); 10 | 11 | try 12 | { 13 | if (fail) 14 | throw std::runtime_error("fail"); 15 | 16 | std::move(completion.handler)(std::exception_ptr(), 1); 17 | } 18 | catch (...) 19 | { 20 | std::move(completion.handler)(std::current_exception(), 1); 21 | } 22 | 23 | return completion.result.get(); 24 | } 25 | 26 | int success_count = 0; 27 | int fail_count = 0; 28 | 29 | void handler1(const std::exception_ptr& e, int) 30 | { 31 | e ? ++fail_count : ++success_count; 32 | } 33 | 34 | struct handler2 35 | { 36 | handler2() {} 37 | void operator()(const std::exception_ptr& e, int) 38 | { 39 | e ? ++fail_count : ++success_count; 40 | } 41 | }; 42 | 43 | struct handler3 44 | { 45 | handler3() {} 46 | handler3(const handler3&) = delete; 47 | handler3(handler3&&) {} 48 | void operator()(const std::exception_ptr& e, int) && 49 | { 50 | e ? ++fail_count : ++success_count; 51 | } 52 | }; 53 | 54 | int main() 55 | { 56 | async_foo(false, handler1); 57 | async_foo(true, handler1); 58 | 59 | async_foo(false, &handler1); 60 | async_foo(true, &handler1); 61 | 62 | async_foo(false, handler2()); 63 | async_foo(true, handler2()); 64 | 65 | handler2 h1; 66 | async_foo(false, h1); 67 | async_foo(true, h1); 68 | 69 | const handler2 h2; 70 | async_foo(false, h2); 71 | async_foo(true, h2); 72 | 73 | async_foo(false, handler3()); 74 | async_foo(true, handler3()); 75 | 76 | handler3 h3, h4; 77 | async_foo(false, std::move(h3)); 78 | async_foo(true, std::move(h4)); 79 | 80 | async_foo(false, [](std::exception_ptr e, int){ e ? ++fail_count : ++success_count; }); 81 | async_foo(true, [](std::exception_ptr e, int){ e ? ++fail_count : ++success_count; }); 82 | 83 | std::future f1 = async_foo(false, std::experimental::use_future); 84 | try 85 | { 86 | f1.get(); 87 | ++success_count; 88 | } 89 | catch (...) 90 | { 91 | ++fail_count; 92 | } 93 | 94 | std::future f2 = async_foo(true, std::experimental::use_future); 95 | try 96 | { 97 | f2.get(); 98 | ++success_count; 99 | } 100 | catch (...) 101 | { 102 | ++fail_count; 103 | } 104 | 105 | assert(success_count == 9); 106 | assert(fail_count == 9); 107 | } 108 | -------------------------------------------------------------------------------- /src/tests/traits/ep_int_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | auto async_foo(bool fail, CompletionToken&& tok) 8 | { 9 | std::experimental::async_completion completion(tok); 10 | 11 | try 12 | { 13 | if (fail) 14 | throw std::runtime_error("fail"); 15 | 16 | std::move(completion.handler)(std::exception_ptr(), 1, 2); 17 | } 18 | catch (...) 19 | { 20 | std::move(completion.handler)(std::current_exception(), 1, 2); 21 | } 22 | 23 | return completion.result.get(); 24 | } 25 | 26 | int success_count = 0; 27 | int fail_count = 0; 28 | 29 | void handler1(const std::exception_ptr& e, int, int) 30 | { 31 | e ? ++fail_count : ++success_count; 32 | } 33 | 34 | struct handler2 35 | { 36 | handler2() {} 37 | void operator()(const std::exception_ptr& e, int, int) 38 | { 39 | e ? ++fail_count : ++success_count; 40 | } 41 | }; 42 | 43 | struct handler3 44 | { 45 | handler3() {} 46 | handler3(const handler3&) = delete; 47 | handler3(handler3&&) {} 48 | void operator()(const std::exception_ptr& e, int, int) && 49 | { 50 | e ? ++fail_count : ++success_count; 51 | } 52 | }; 53 | 54 | int main() 55 | { 56 | async_foo(false, handler1); 57 | async_foo(true, handler1); 58 | 59 | async_foo(false, &handler1); 60 | async_foo(true, &handler1); 61 | 62 | async_foo(false, handler2()); 63 | async_foo(true, handler2()); 64 | 65 | handler2 h1; 66 | async_foo(false, h1); 67 | async_foo(true, h1); 68 | 69 | const handler2 h2; 70 | async_foo(false, h2); 71 | async_foo(true, h2); 72 | 73 | async_foo(false, handler3()); 74 | async_foo(true, handler3()); 75 | 76 | handler3 h3, h4; 77 | async_foo(false, std::move(h3)); 78 | async_foo(true, std::move(h4)); 79 | 80 | async_foo(false, [](std::exception_ptr e, int, int){ e ? ++fail_count : ++success_count; }); 81 | async_foo(true, [](std::exception_ptr e, int, int){ e ? ++fail_count : ++success_count; }); 82 | 83 | std::future> f1 = async_foo(false, std::experimental::use_future); 84 | try 85 | { 86 | f1.get(); 87 | ++success_count; 88 | } 89 | catch (...) 90 | { 91 | ++fail_count; 92 | } 93 | 94 | std::future> f2 = async_foo(true, std::experimental::use_future); 95 | try 96 | { 97 | f2.get(); 98 | ++success_count; 99 | } 100 | catch (...) 101 | { 102 | ++fail_count; 103 | } 104 | 105 | assert(success_count == 9); 106 | assert(fail_count == 9); 107 | } 108 | -------------------------------------------------------------------------------- /src/tests/traits/int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | auto async_foo(CompletionToken&& tok) 7 | { 8 | std::experimental::async_completion completion(tok); 9 | 10 | std::move(completion.handler)(1); 11 | 12 | return completion.result.get(); 13 | } 14 | 15 | int success_count = 0; 16 | 17 | void handler1(int) 18 | { 19 | ++success_count; 20 | } 21 | 22 | struct handler2 23 | { 24 | handler2() {} 25 | void operator()(int) { ++success_count; } 26 | }; 27 | 28 | struct handler3 29 | { 30 | handler3() {} 31 | handler3(const handler3&) = delete; 32 | handler3(handler3&&) {} 33 | void operator()(int) && { ++success_count; } 34 | }; 35 | 36 | int main() 37 | { 38 | async_foo(handler1); 39 | 40 | async_foo(&handler1); 41 | 42 | async_foo(handler2()); 43 | 44 | handler2 h1; 45 | async_foo(h1); 46 | 47 | const handler2 h2; 48 | async_foo(h2); 49 | 50 | async_foo(handler3()); 51 | 52 | handler3 h3; 53 | async_foo(std::move(h3)); 54 | 55 | async_foo([](int){ ++success_count; }); 56 | 57 | std::future f = async_foo(std::experimental::use_future); 58 | int v = f.get(); 59 | assert(v == 1); 60 | ++success_count; 61 | 62 | assert(success_count == 9); 63 | } 64 | -------------------------------------------------------------------------------- /src/tests/traits/int_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | auto async_foo(CompletionToken&& tok) 7 | { 8 | std::experimental::async_completion completion(tok); 9 | 10 | std::move(completion.handler)(1, 2); 11 | 12 | return completion.result.get(); 13 | } 14 | 15 | int success_count = 0; 16 | 17 | void handler1(int, int) 18 | { 19 | ++success_count; 20 | } 21 | 22 | struct handler2 23 | { 24 | handler2() {} 25 | void operator()(int, int) { ++success_count; } 26 | }; 27 | 28 | struct handler3 29 | { 30 | handler3() {} 31 | handler3(const handler3&) = delete; 32 | handler3(handler3&&) {} 33 | void operator()(int, int) && { ++success_count; } 34 | }; 35 | 36 | int main() 37 | { 38 | async_foo(handler1); 39 | 40 | async_foo(&handler1); 41 | 42 | async_foo(handler2()); 43 | 44 | handler2 h1; 45 | async_foo(h1); 46 | 47 | const handler2 h2; 48 | async_foo(h2); 49 | 50 | async_foo(handler3()); 51 | 52 | handler3 h3; 53 | async_foo(std::move(h3)); 54 | 55 | async_foo([](int, int){ ++success_count; }); 56 | 57 | std::future> f = async_foo(std::experimental::use_future); 58 | f.get(); 59 | ++success_count; 60 | 61 | assert(success_count == 9); 62 | } 63 | -------------------------------------------------------------------------------- /src/tests/traits/void.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | auto async_foo(CompletionToken&& tok) 7 | { 8 | std::experimental::async_completion completion(tok); 9 | 10 | std::move(completion.handler)(); 11 | 12 | return completion.result.get(); 13 | } 14 | 15 | int success_count = 0; 16 | 17 | void handler1() 18 | { 19 | ++success_count; 20 | } 21 | 22 | struct handler2 23 | { 24 | handler2() {} 25 | void operator()() { ++success_count; } 26 | }; 27 | 28 | struct handler3 29 | { 30 | handler3() {} 31 | handler3(const handler3&) = delete; 32 | handler3(handler3&&) {} 33 | void operator()() && { ++success_count; } 34 | }; 35 | 36 | int main() 37 | { 38 | async_foo(handler1); 39 | 40 | async_foo(&handler1); 41 | 42 | async_foo(handler2()); 43 | 44 | handler2 h1; 45 | async_foo(h1); 46 | 47 | const handler2 h2; 48 | async_foo(h2); 49 | 50 | async_foo(handler3()); 51 | 52 | handler3 h3; 53 | async_foo(std::move(h3)); 54 | 55 | async_foo([](){ ++success_count; }); 56 | 57 | std::future f = async_foo(std::experimental::use_future); 58 | f.get(); 59 | ++success_count; 60 | 61 | assert(success_count == 9); 62 | } 63 | --------------------------------------------------------------------------------