diff options
Diffstat (limited to '3rdparty/asio/src/examples/cpp20')
31 files changed, 5244 insertions, 0 deletions
diff --git a/3rdparty/asio/src/examples/cpp20/Makefile.am b/3rdparty/asio/src/examples/cpp20/Makefile.am new file mode 100644 index 00000000000..619893c208e --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/Makefile.am @@ -0,0 +1,79 @@ +AUTOMAKE_OPTIONS = subdir-objects + +if SEPARATE_COMPILATION +noinst_LIBRARIES = libasio.a +libasio_a_SOURCES = ../../asio.cpp +if HAVE_OPENSSL +libasio_a_SOURCES += ../../asio_ssl.cpp +endif +LDADD = libasio.a +endif + +noinst_PROGRAMS = \ + invocation/completion_executor \ + operations/c_callback_wrapper \ + operations/callback_wrapper \ + operations/composed_1 \ + operations/composed_1 \ + operations/composed_2 \ + operations/composed_3 \ + operations/composed_4 \ + operations/composed_5 \ + operations/composed_6 \ + operations/composed_7 \ + operations/composed_8 + +if HAVE_COROUTINES +noinst_PROGRAMS += \ + channels/mutual_exclusion_1 \ + channels/mutual_exclusion_2 \ + channels/throttling_proxy \ + coroutines/chat_server \ + coroutines/echo_server \ + coroutines/echo_server_with_default \ + coroutines/echo_server_with_deferred \ + coroutines/echo_server_with_deferred_default \ + coroutines/echo_server_with_as_single_default \ + coroutines/echo_server_with_as_tuple_default \ + coroutines/refactored_echo_server \ + coroutines/timeout \ + type_erasure/type_erasure +endif + +AM_CXXFLAGS = -I$(srcdir)/../../../include + +invocation_completion_executor_SOURCES = invocation/completion_executor.cpp +operations_c_callback_wrapper_SOURCES = operations/c_callback_wrapper.cpp +operations_callback_wrapper_SOURCES = operations/callback_wrapper.cpp +operations_composed_1_SOURCES = operations/composed_1.cpp +operations_composed_2_SOURCES = operations/composed_2.cpp +operations_composed_3_SOURCES = operations/composed_3.cpp +operations_composed_4_SOURCES = operations/composed_4.cpp +operations_composed_5_SOURCES = operations/composed_5.cpp +operations_composed_6_SOURCES = operations/composed_6.cpp +operations_composed_7_SOURCES = operations/composed_7.cpp +operations_composed_8_SOURCES = operations/composed_8.cpp + +if HAVE_COROUTINES +channels_mutual_exclusion_1_SOURCES = channels/mutual_exclusion_1.cpp +channels_mutual_exclusion_2_SOURCES = channels/mutual_exclusion_2.cpp +channels_throttling_proxy_SOURCES = channels/throttling_proxy.cpp +coroutines_chat_server_SOURCES = coroutines/chat_server.cpp +coroutines_echo_server_SOURCES = coroutines/echo_server.cpp +coroutines_echo_server_with_default_SOURCES = coroutines/echo_server_with_default.cpp +coroutines_echo_server_with_deferred_SOURCES = coroutines/echo_server_with_deferred.cpp +coroutines_echo_server_with_deferred_default_SOURCES = coroutines/echo_server_with_deferred_default.cpp +coroutines_echo_server_with_as_single_default_SOURCES = coroutines/echo_server_with_as_single_default.cpp +coroutines_echo_server_with_as_tuple_default_SOURCES = coroutines/echo_server_with_as_tuple_default.cpp +coroutines_refactored_echo_server_SOURCES = coroutines/refactored_echo_server.cpp +coroutines_timeout_SOURCES = coroutines/timeout.cpp +type_erasure_type_erasure_SOURCES = type_erasure/main.cpp type_erasure/stdin_line_reader.cpp type_erasure/sleep.cpp +endif + +EXTRA_DIST = \ + type_erasure/line_reader.hpp \ + type_erasure/stdin_line_reader.hpp \ + type_erasure/sleep.hpp + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in diff --git a/3rdparty/asio/src/examples/cpp20/Makefile.in b/3rdparty/asio/src/examples/cpp20/Makefile.in new file mode 100644 index 00000000000..87311465ece --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/Makefile.in @@ -0,0 +1,1173 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@HAVE_OPENSSL_TRUE@@SEPARATE_COMPILATION_TRUE@am__append_1 = ../../asio_ssl.cpp +noinst_PROGRAMS = invocation/completion_executor$(EXEEXT) \ + operations/c_callback_wrapper$(EXEEXT) \ + operations/callback_wrapper$(EXEEXT) \ + operations/composed_1$(EXEEXT) operations/composed_1$(EXEEXT) \ + operations/composed_2$(EXEEXT) operations/composed_3$(EXEEXT) \ + operations/composed_4$(EXEEXT) operations/composed_5$(EXEEXT) \ + operations/composed_6$(EXEEXT) operations/composed_7$(EXEEXT) \ + operations/composed_8$(EXEEXT) $(am__EXEEXT_1) +@HAVE_COROUTINES_TRUE@am__append_2 = \ +@HAVE_COROUTINES_TRUE@ channels/mutual_exclusion_1 \ +@HAVE_COROUTINES_TRUE@ channels/mutual_exclusion_2 \ +@HAVE_COROUTINES_TRUE@ channels/throttling_proxy \ +@HAVE_COROUTINES_TRUE@ coroutines/chat_server \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_default \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_deferred \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_deferred_default \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_as_single_default \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_as_tuple_default \ +@HAVE_COROUTINES_TRUE@ coroutines/refactored_echo_server \ +@HAVE_COROUTINES_TRUE@ coroutines/timeout \ +@HAVE_COROUTINES_TRUE@ type_erasure/type_erasure + +subdir = src/examples/cpp20 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_COROUTINES_TRUE@am__EXEEXT_1 = \ +@HAVE_COROUTINES_TRUE@ channels/mutual_exclusion_1$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ channels/mutual_exclusion_2$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ channels/throttling_proxy$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/chat_server$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_default$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_deferred$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_deferred_default$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_as_single_default$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server_with_as_tuple_default$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/refactored_echo_server$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ coroutines/timeout$(EXEEXT) \ +@HAVE_COROUTINES_TRUE@ type_erasure/type_erasure$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libasio_a_AR = $(AR) $(ARFLAGS) +libasio_a_LIBADD = +am__libasio_a_SOURCES_DIST = ../../asio.cpp ../../asio_ssl.cpp +am__dirstamp = $(am__leading_dot)dirstamp +@HAVE_OPENSSL_TRUE@@SEPARATE_COMPILATION_TRUE@am__objects_1 = ../../asio_ssl.$(OBJEXT) +@SEPARATE_COMPILATION_TRUE@am_libasio_a_OBJECTS = \ +@SEPARATE_COMPILATION_TRUE@ ../../asio.$(OBJEXT) \ +@SEPARATE_COMPILATION_TRUE@ $(am__objects_1) +libasio_a_OBJECTS = $(am_libasio_a_OBJECTS) +am__channels_mutual_exclusion_1_SOURCES_DIST = \ + channels/mutual_exclusion_1.cpp +@HAVE_COROUTINES_TRUE@am_channels_mutual_exclusion_1_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ channels/mutual_exclusion_1.$(OBJEXT) +channels_mutual_exclusion_1_OBJECTS = \ + $(am_channels_mutual_exclusion_1_OBJECTS) +channels_mutual_exclusion_1_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@channels_mutual_exclusion_1_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__channels_mutual_exclusion_2_SOURCES_DIST = \ + channels/mutual_exclusion_2.cpp +@HAVE_COROUTINES_TRUE@am_channels_mutual_exclusion_2_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ channels/mutual_exclusion_2.$(OBJEXT) +channels_mutual_exclusion_2_OBJECTS = \ + $(am_channels_mutual_exclusion_2_OBJECTS) +channels_mutual_exclusion_2_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@channels_mutual_exclusion_2_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__channels_throttling_proxy_SOURCES_DIST = \ + channels/throttling_proxy.cpp +@HAVE_COROUTINES_TRUE@am_channels_throttling_proxy_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ channels/throttling_proxy.$(OBJEXT) +channels_throttling_proxy_OBJECTS = \ + $(am_channels_throttling_proxy_OBJECTS) +channels_throttling_proxy_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@channels_throttling_proxy_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_chat_server_SOURCES_DIST = coroutines/chat_server.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_chat_server_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ coroutines/chat_server.$(OBJEXT) +coroutines_chat_server_OBJECTS = $(am_coroutines_chat_server_OBJECTS) +coroutines_chat_server_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_chat_server_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_echo_server_SOURCES_DIST = coroutines/echo_server.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_echo_server_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ coroutines/echo_server.$(OBJEXT) +coroutines_echo_server_OBJECTS = $(am_coroutines_echo_server_OBJECTS) +coroutines_echo_server_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_echo_server_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_echo_server_with_as_single_default_SOURCES_DIST = \ + coroutines/echo_server_with_as_single_default.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_echo_server_with_as_single_default_OBJECTS = coroutines/echo_server_with_as_single_default.$(OBJEXT) +coroutines_echo_server_with_as_single_default_OBJECTS = \ + $(am_coroutines_echo_server_with_as_single_default_OBJECTS) +coroutines_echo_server_with_as_single_default_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_echo_server_with_as_single_default_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_echo_server_with_as_tuple_default_SOURCES_DIST = \ + coroutines/echo_server_with_as_tuple_default.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_echo_server_with_as_tuple_default_OBJECTS = coroutines/echo_server_with_as_tuple_default.$(OBJEXT) +coroutines_echo_server_with_as_tuple_default_OBJECTS = \ + $(am_coroutines_echo_server_with_as_tuple_default_OBJECTS) +coroutines_echo_server_with_as_tuple_default_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_echo_server_with_as_tuple_default_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_echo_server_with_default_SOURCES_DIST = \ + coroutines/echo_server_with_default.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_echo_server_with_default_OBJECTS = coroutines/echo_server_with_default.$(OBJEXT) +coroutines_echo_server_with_default_OBJECTS = \ + $(am_coroutines_echo_server_with_default_OBJECTS) +coroutines_echo_server_with_default_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_echo_server_with_default_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_echo_server_with_deferred_SOURCES_DIST = \ + coroutines/echo_server_with_deferred.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_echo_server_with_deferred_OBJECTS = coroutines/echo_server_with_deferred.$(OBJEXT) +coroutines_echo_server_with_deferred_OBJECTS = \ + $(am_coroutines_echo_server_with_deferred_OBJECTS) +coroutines_echo_server_with_deferred_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_echo_server_with_deferred_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_echo_server_with_deferred_default_SOURCES_DIST = \ + coroutines/echo_server_with_deferred_default.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_echo_server_with_deferred_default_OBJECTS = coroutines/echo_server_with_deferred_default.$(OBJEXT) +coroutines_echo_server_with_deferred_default_OBJECTS = \ + $(am_coroutines_echo_server_with_deferred_default_OBJECTS) +coroutines_echo_server_with_deferred_default_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_echo_server_with_deferred_default_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_refactored_echo_server_SOURCES_DIST = \ + coroutines/refactored_echo_server.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_refactored_echo_server_OBJECTS = coroutines/refactored_echo_server.$(OBJEXT) +coroutines_refactored_echo_server_OBJECTS = \ + $(am_coroutines_refactored_echo_server_OBJECTS) +coroutines_refactored_echo_server_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_refactored_echo_server_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__coroutines_timeout_SOURCES_DIST = coroutines/timeout.cpp +@HAVE_COROUTINES_TRUE@am_coroutines_timeout_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ coroutines/timeout.$(OBJEXT) +coroutines_timeout_OBJECTS = $(am_coroutines_timeout_OBJECTS) +coroutines_timeout_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@coroutines_timeout_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_invocation_completion_executor_OBJECTS = \ + invocation/completion_executor.$(OBJEXT) +invocation_completion_executor_OBJECTS = \ + $(am_invocation_completion_executor_OBJECTS) +invocation_completion_executor_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@invocation_completion_executor_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_c_callback_wrapper_OBJECTS = \ + operations/c_callback_wrapper.$(OBJEXT) +operations_c_callback_wrapper_OBJECTS = \ + $(am_operations_c_callback_wrapper_OBJECTS) +operations_c_callback_wrapper_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_c_callback_wrapper_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_callback_wrapper_OBJECTS = \ + operations/callback_wrapper.$(OBJEXT) +operations_callback_wrapper_OBJECTS = \ + $(am_operations_callback_wrapper_OBJECTS) +operations_callback_wrapper_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_callback_wrapper_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_1_OBJECTS = operations/composed_1.$(OBJEXT) +operations_composed_1_OBJECTS = $(am_operations_composed_1_OBJECTS) +operations_composed_1_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_1_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_2_OBJECTS = operations/composed_2.$(OBJEXT) +operations_composed_2_OBJECTS = $(am_operations_composed_2_OBJECTS) +operations_composed_2_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_2_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_3_OBJECTS = operations/composed_3.$(OBJEXT) +operations_composed_3_OBJECTS = $(am_operations_composed_3_OBJECTS) +operations_composed_3_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_3_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_4_OBJECTS = operations/composed_4.$(OBJEXT) +operations_composed_4_OBJECTS = $(am_operations_composed_4_OBJECTS) +operations_composed_4_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_4_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_5_OBJECTS = operations/composed_5.$(OBJEXT) +operations_composed_5_OBJECTS = $(am_operations_composed_5_OBJECTS) +operations_composed_5_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_5_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_6_OBJECTS = operations/composed_6.$(OBJEXT) +operations_composed_6_OBJECTS = $(am_operations_composed_6_OBJECTS) +operations_composed_6_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_6_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_7_OBJECTS = operations/composed_7.$(OBJEXT) +operations_composed_7_OBJECTS = $(am_operations_composed_7_OBJECTS) +operations_composed_7_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_7_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am_operations_composed_8_OBJECTS = operations/composed_8.$(OBJEXT) +operations_composed_8_OBJECTS = $(am_operations_composed_8_OBJECTS) +operations_composed_8_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@operations_composed_8_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +am__type_erasure_type_erasure_SOURCES_DIST = type_erasure/main.cpp \ + type_erasure/stdin_line_reader.cpp type_erasure/sleep.cpp +@HAVE_COROUTINES_TRUE@am_type_erasure_type_erasure_OBJECTS = \ +@HAVE_COROUTINES_TRUE@ type_erasure/main.$(OBJEXT) \ +@HAVE_COROUTINES_TRUE@ type_erasure/stdin_line_reader.$(OBJEXT) \ +@HAVE_COROUTINES_TRUE@ type_erasure/sleep.$(OBJEXT) +type_erasure_type_erasure_OBJECTS = \ + $(am_type_erasure_type_erasure_OBJECTS) +type_erasure_type_erasure_LDADD = $(LDADD) +@SEPARATE_COMPILATION_TRUE@type_erasure_type_erasure_DEPENDENCIES = \ +@SEPARATE_COMPILATION_TRUE@ libasio.a +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ../../$(DEPDIR)/asio.Po \ + ../../$(DEPDIR)/asio_ssl.Po \ + channels/$(DEPDIR)/mutual_exclusion_1.Po \ + channels/$(DEPDIR)/mutual_exclusion_2.Po \ + channels/$(DEPDIR)/throttling_proxy.Po \ + coroutines/$(DEPDIR)/chat_server.Po \ + coroutines/$(DEPDIR)/echo_server.Po \ + coroutines/$(DEPDIR)/echo_server_with_as_single_default.Po \ + coroutines/$(DEPDIR)/echo_server_with_as_tuple_default.Po \ + coroutines/$(DEPDIR)/echo_server_with_default.Po \ + coroutines/$(DEPDIR)/echo_server_with_deferred.Po \ + coroutines/$(DEPDIR)/echo_server_with_deferred_default.Po \ + coroutines/$(DEPDIR)/refactored_echo_server.Po \ + coroutines/$(DEPDIR)/timeout.Po \ + invocation/$(DEPDIR)/completion_executor.Po \ + operations/$(DEPDIR)/c_callback_wrapper.Po \ + operations/$(DEPDIR)/callback_wrapper.Po \ + operations/$(DEPDIR)/composed_1.Po \ + operations/$(DEPDIR)/composed_2.Po \ + operations/$(DEPDIR)/composed_3.Po \ + operations/$(DEPDIR)/composed_4.Po \ + operations/$(DEPDIR)/composed_5.Po \ + operations/$(DEPDIR)/composed_6.Po \ + operations/$(DEPDIR)/composed_7.Po \ + operations/$(DEPDIR)/composed_8.Po \ + type_erasure/$(DEPDIR)/main.Po type_erasure/$(DEPDIR)/sleep.Po \ + type_erasure/$(DEPDIR)/stdin_line_reader.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libasio_a_SOURCES) $(channels_mutual_exclusion_1_SOURCES) \ + $(channels_mutual_exclusion_2_SOURCES) \ + $(channels_throttling_proxy_SOURCES) \ + $(coroutines_chat_server_SOURCES) \ + $(coroutines_echo_server_SOURCES) \ + $(coroutines_echo_server_with_as_single_default_SOURCES) \ + $(coroutines_echo_server_with_as_tuple_default_SOURCES) \ + $(coroutines_echo_server_with_default_SOURCES) \ + $(coroutines_echo_server_with_deferred_SOURCES) \ + $(coroutines_echo_server_with_deferred_default_SOURCES) \ + $(coroutines_refactored_echo_server_SOURCES) \ + $(coroutines_timeout_SOURCES) \ + $(invocation_completion_executor_SOURCES) \ + $(operations_c_callback_wrapper_SOURCES) \ + $(operations_callback_wrapper_SOURCES) \ + $(operations_composed_1_SOURCES) \ + $(operations_composed_2_SOURCES) \ + $(operations_composed_3_SOURCES) \ + $(operations_composed_4_SOURCES) \ + $(operations_composed_5_SOURCES) \ + $(operations_composed_6_SOURCES) \ + $(operations_composed_7_SOURCES) \ + $(operations_composed_8_SOURCES) \ + $(type_erasure_type_erasure_SOURCES) +DIST_SOURCES = $(am__libasio_a_SOURCES_DIST) \ + $(am__channels_mutual_exclusion_1_SOURCES_DIST) \ + $(am__channels_mutual_exclusion_2_SOURCES_DIST) \ + $(am__channels_throttling_proxy_SOURCES_DIST) \ + $(am__coroutines_chat_server_SOURCES_DIST) \ + $(am__coroutines_echo_server_SOURCES_DIST) \ + $(am__coroutines_echo_server_with_as_single_default_SOURCES_DIST) \ + $(am__coroutines_echo_server_with_as_tuple_default_SOURCES_DIST) \ + $(am__coroutines_echo_server_with_default_SOURCES_DIST) \ + $(am__coroutines_echo_server_with_deferred_SOURCES_DIST) \ + $(am__coroutines_echo_server_with_deferred_default_SOURCES_DIST) \ + $(am__coroutines_refactored_echo_server_SOURCES_DIST) \ + $(am__coroutines_timeout_SOURCES_DIST) \ + $(invocation_completion_executor_SOURCES) \ + $(operations_c_callback_wrapper_SOURCES) \ + $(operations_callback_wrapper_SOURCES) \ + $(operations_composed_1_SOURCES) \ + $(operations_composed_2_SOURCES) \ + $(operations_composed_3_SOURCES) \ + $(operations_composed_4_SOURCES) \ + $(operations_composed_5_SOURCES) \ + $(operations_composed_6_SOURCES) \ + $(operations_composed_7_SOURCES) \ + $(operations_composed_8_SOURCES) \ + $(am__type_erasure_type_erasure_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = subdir-objects +@SEPARATE_COMPILATION_TRUE@noinst_LIBRARIES = libasio.a +@SEPARATE_COMPILATION_TRUE@libasio_a_SOURCES = ../../asio.cpp \ +@SEPARATE_COMPILATION_TRUE@ $(am__append_1) +@SEPARATE_COMPILATION_TRUE@LDADD = libasio.a +AM_CXXFLAGS = -I$(srcdir)/../../../include +invocation_completion_executor_SOURCES = invocation/completion_executor.cpp +operations_c_callback_wrapper_SOURCES = operations/c_callback_wrapper.cpp +operations_callback_wrapper_SOURCES = operations/callback_wrapper.cpp +operations_composed_1_SOURCES = operations/composed_1.cpp +operations_composed_2_SOURCES = operations/composed_2.cpp +operations_composed_3_SOURCES = operations/composed_3.cpp +operations_composed_4_SOURCES = operations/composed_4.cpp +operations_composed_5_SOURCES = operations/composed_5.cpp +operations_composed_6_SOURCES = operations/composed_6.cpp +operations_composed_7_SOURCES = operations/composed_7.cpp +operations_composed_8_SOURCES = operations/composed_8.cpp +@HAVE_COROUTINES_TRUE@channels_mutual_exclusion_1_SOURCES = channels/mutual_exclusion_1.cpp +@HAVE_COROUTINES_TRUE@channels_mutual_exclusion_2_SOURCES = channels/mutual_exclusion_2.cpp +@HAVE_COROUTINES_TRUE@channels_throttling_proxy_SOURCES = channels/throttling_proxy.cpp +@HAVE_COROUTINES_TRUE@coroutines_chat_server_SOURCES = coroutines/chat_server.cpp +@HAVE_COROUTINES_TRUE@coroutines_echo_server_SOURCES = coroutines/echo_server.cpp +@HAVE_COROUTINES_TRUE@coroutines_echo_server_with_default_SOURCES = coroutines/echo_server_with_default.cpp +@HAVE_COROUTINES_TRUE@coroutines_echo_server_with_deferred_SOURCES = coroutines/echo_server_with_deferred.cpp +@HAVE_COROUTINES_TRUE@coroutines_echo_server_with_deferred_default_SOURCES = coroutines/echo_server_with_deferred_default.cpp +@HAVE_COROUTINES_TRUE@coroutines_echo_server_with_as_single_default_SOURCES = coroutines/echo_server_with_as_single_default.cpp +@HAVE_COROUTINES_TRUE@coroutines_echo_server_with_as_tuple_default_SOURCES = coroutines/echo_server_with_as_tuple_default.cpp +@HAVE_COROUTINES_TRUE@coroutines_refactored_echo_server_SOURCES = coroutines/refactored_echo_server.cpp +@HAVE_COROUTINES_TRUE@coroutines_timeout_SOURCES = coroutines/timeout.cpp +@HAVE_COROUTINES_TRUE@type_erasure_type_erasure_SOURCES = type_erasure/main.cpp type_erasure/stdin_line_reader.cpp type_erasure/sleep.cpp +EXTRA_DIST = \ + type_erasure/line_reader.hpp \ + type_erasure/stdin_line_reader.hpp \ + type_erasure/sleep.hpp + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/examples/cpp20/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/examples/cpp20/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +../../$(am__dirstamp): + @$(MKDIR_P) ../.. + @: > ../../$(am__dirstamp) +../../$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) ../../$(DEPDIR) + @: > ../../$(DEPDIR)/$(am__dirstamp) +../../asio.$(OBJEXT): ../../$(am__dirstamp) \ + ../../$(DEPDIR)/$(am__dirstamp) +../../asio_ssl.$(OBJEXT): ../../$(am__dirstamp) \ + ../../$(DEPDIR)/$(am__dirstamp) + +libasio.a: $(libasio_a_OBJECTS) $(libasio_a_DEPENDENCIES) $(EXTRA_libasio_a_DEPENDENCIES) + $(AM_V_at)-rm -f libasio.a + $(AM_V_AR)$(libasio_a_AR) libasio.a $(libasio_a_OBJECTS) $(libasio_a_LIBADD) + $(AM_V_at)$(RANLIB) libasio.a +channels/$(am__dirstamp): + @$(MKDIR_P) channels + @: > channels/$(am__dirstamp) +channels/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) channels/$(DEPDIR) + @: > channels/$(DEPDIR)/$(am__dirstamp) +channels/mutual_exclusion_1.$(OBJEXT): channels/$(am__dirstamp) \ + channels/$(DEPDIR)/$(am__dirstamp) + +channels/mutual_exclusion_1$(EXEEXT): $(channels_mutual_exclusion_1_OBJECTS) $(channels_mutual_exclusion_1_DEPENDENCIES) $(EXTRA_channels_mutual_exclusion_1_DEPENDENCIES) channels/$(am__dirstamp) + @rm -f channels/mutual_exclusion_1$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(channels_mutual_exclusion_1_OBJECTS) $(channels_mutual_exclusion_1_LDADD) $(LIBS) +channels/mutual_exclusion_2.$(OBJEXT): channels/$(am__dirstamp) \ + channels/$(DEPDIR)/$(am__dirstamp) + +channels/mutual_exclusion_2$(EXEEXT): $(channels_mutual_exclusion_2_OBJECTS) $(channels_mutual_exclusion_2_DEPENDENCIES) $(EXTRA_channels_mutual_exclusion_2_DEPENDENCIES) channels/$(am__dirstamp) + @rm -f channels/mutual_exclusion_2$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(channels_mutual_exclusion_2_OBJECTS) $(channels_mutual_exclusion_2_LDADD) $(LIBS) +channels/throttling_proxy.$(OBJEXT): channels/$(am__dirstamp) \ + channels/$(DEPDIR)/$(am__dirstamp) + +channels/throttling_proxy$(EXEEXT): $(channels_throttling_proxy_OBJECTS) $(channels_throttling_proxy_DEPENDENCIES) $(EXTRA_channels_throttling_proxy_DEPENDENCIES) channels/$(am__dirstamp) + @rm -f channels/throttling_proxy$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(channels_throttling_proxy_OBJECTS) $(channels_throttling_proxy_LDADD) $(LIBS) +coroutines/$(am__dirstamp): + @$(MKDIR_P) coroutines + @: > coroutines/$(am__dirstamp) +coroutines/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) coroutines/$(DEPDIR) + @: > coroutines/$(DEPDIR)/$(am__dirstamp) +coroutines/chat_server.$(OBJEXT): coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/chat_server$(EXEEXT): $(coroutines_chat_server_OBJECTS) $(coroutines_chat_server_DEPENDENCIES) $(EXTRA_coroutines_chat_server_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/chat_server$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_chat_server_OBJECTS) $(coroutines_chat_server_LDADD) $(LIBS) +coroutines/echo_server.$(OBJEXT): coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/echo_server$(EXEEXT): $(coroutines_echo_server_OBJECTS) $(coroutines_echo_server_DEPENDENCIES) $(EXTRA_coroutines_echo_server_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/echo_server$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_echo_server_OBJECTS) $(coroutines_echo_server_LDADD) $(LIBS) +coroutines/echo_server_with_as_single_default.$(OBJEXT): \ + coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/echo_server_with_as_single_default$(EXEEXT): $(coroutines_echo_server_with_as_single_default_OBJECTS) $(coroutines_echo_server_with_as_single_default_DEPENDENCIES) $(EXTRA_coroutines_echo_server_with_as_single_default_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/echo_server_with_as_single_default$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_echo_server_with_as_single_default_OBJECTS) $(coroutines_echo_server_with_as_single_default_LDADD) $(LIBS) +coroutines/echo_server_with_as_tuple_default.$(OBJEXT): \ + coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/echo_server_with_as_tuple_default$(EXEEXT): $(coroutines_echo_server_with_as_tuple_default_OBJECTS) $(coroutines_echo_server_with_as_tuple_default_DEPENDENCIES) $(EXTRA_coroutines_echo_server_with_as_tuple_default_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/echo_server_with_as_tuple_default$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_echo_server_with_as_tuple_default_OBJECTS) $(coroutines_echo_server_with_as_tuple_default_LDADD) $(LIBS) +coroutines/echo_server_with_default.$(OBJEXT): \ + coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/echo_server_with_default$(EXEEXT): $(coroutines_echo_server_with_default_OBJECTS) $(coroutines_echo_server_with_default_DEPENDENCIES) $(EXTRA_coroutines_echo_server_with_default_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/echo_server_with_default$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_echo_server_with_default_OBJECTS) $(coroutines_echo_server_with_default_LDADD) $(LIBS) +coroutines/echo_server_with_deferred.$(OBJEXT): \ + coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/echo_server_with_deferred$(EXEEXT): $(coroutines_echo_server_with_deferred_OBJECTS) $(coroutines_echo_server_with_deferred_DEPENDENCIES) $(EXTRA_coroutines_echo_server_with_deferred_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/echo_server_with_deferred$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_echo_server_with_deferred_OBJECTS) $(coroutines_echo_server_with_deferred_LDADD) $(LIBS) +coroutines/echo_server_with_deferred_default.$(OBJEXT): \ + coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/echo_server_with_deferred_default$(EXEEXT): $(coroutines_echo_server_with_deferred_default_OBJECTS) $(coroutines_echo_server_with_deferred_default_DEPENDENCIES) $(EXTRA_coroutines_echo_server_with_deferred_default_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/echo_server_with_deferred_default$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_echo_server_with_deferred_default_OBJECTS) $(coroutines_echo_server_with_deferred_default_LDADD) $(LIBS) +coroutines/refactored_echo_server.$(OBJEXT): \ + coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/refactored_echo_server$(EXEEXT): $(coroutines_refactored_echo_server_OBJECTS) $(coroutines_refactored_echo_server_DEPENDENCIES) $(EXTRA_coroutines_refactored_echo_server_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/refactored_echo_server$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_refactored_echo_server_OBJECTS) $(coroutines_refactored_echo_server_LDADD) $(LIBS) +coroutines/timeout.$(OBJEXT): coroutines/$(am__dirstamp) \ + coroutines/$(DEPDIR)/$(am__dirstamp) + +coroutines/timeout$(EXEEXT): $(coroutines_timeout_OBJECTS) $(coroutines_timeout_DEPENDENCIES) $(EXTRA_coroutines_timeout_DEPENDENCIES) coroutines/$(am__dirstamp) + @rm -f coroutines/timeout$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(coroutines_timeout_OBJECTS) $(coroutines_timeout_LDADD) $(LIBS) +invocation/$(am__dirstamp): + @$(MKDIR_P) invocation + @: > invocation/$(am__dirstamp) +invocation/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) invocation/$(DEPDIR) + @: > invocation/$(DEPDIR)/$(am__dirstamp) +invocation/completion_executor.$(OBJEXT): invocation/$(am__dirstamp) \ + invocation/$(DEPDIR)/$(am__dirstamp) + +invocation/completion_executor$(EXEEXT): $(invocation_completion_executor_OBJECTS) $(invocation_completion_executor_DEPENDENCIES) $(EXTRA_invocation_completion_executor_DEPENDENCIES) invocation/$(am__dirstamp) + @rm -f invocation/completion_executor$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(invocation_completion_executor_OBJECTS) $(invocation_completion_executor_LDADD) $(LIBS) +operations/$(am__dirstamp): + @$(MKDIR_P) operations + @: > operations/$(am__dirstamp) +operations/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) operations/$(DEPDIR) + @: > operations/$(DEPDIR)/$(am__dirstamp) +operations/c_callback_wrapper.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/c_callback_wrapper$(EXEEXT): $(operations_c_callback_wrapper_OBJECTS) $(operations_c_callback_wrapper_DEPENDENCIES) $(EXTRA_operations_c_callback_wrapper_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/c_callback_wrapper$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_c_callback_wrapper_OBJECTS) $(operations_c_callback_wrapper_LDADD) $(LIBS) +operations/callback_wrapper.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/callback_wrapper$(EXEEXT): $(operations_callback_wrapper_OBJECTS) $(operations_callback_wrapper_DEPENDENCIES) $(EXTRA_operations_callback_wrapper_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/callback_wrapper$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_callback_wrapper_OBJECTS) $(operations_callback_wrapper_LDADD) $(LIBS) +operations/composed_1.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_1$(EXEEXT): $(operations_composed_1_OBJECTS) $(operations_composed_1_DEPENDENCIES) $(EXTRA_operations_composed_1_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_1$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_1_OBJECTS) $(operations_composed_1_LDADD) $(LIBS) +operations/composed_2.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_2$(EXEEXT): $(operations_composed_2_OBJECTS) $(operations_composed_2_DEPENDENCIES) $(EXTRA_operations_composed_2_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_2$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_2_OBJECTS) $(operations_composed_2_LDADD) $(LIBS) +operations/composed_3.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_3$(EXEEXT): $(operations_composed_3_OBJECTS) $(operations_composed_3_DEPENDENCIES) $(EXTRA_operations_composed_3_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_3$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_3_OBJECTS) $(operations_composed_3_LDADD) $(LIBS) +operations/composed_4.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_4$(EXEEXT): $(operations_composed_4_OBJECTS) $(operations_composed_4_DEPENDENCIES) $(EXTRA_operations_composed_4_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_4$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_4_OBJECTS) $(operations_composed_4_LDADD) $(LIBS) +operations/composed_5.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_5$(EXEEXT): $(operations_composed_5_OBJECTS) $(operations_composed_5_DEPENDENCIES) $(EXTRA_operations_composed_5_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_5$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_5_OBJECTS) $(operations_composed_5_LDADD) $(LIBS) +operations/composed_6.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_6$(EXEEXT): $(operations_composed_6_OBJECTS) $(operations_composed_6_DEPENDENCIES) $(EXTRA_operations_composed_6_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_6$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_6_OBJECTS) $(operations_composed_6_LDADD) $(LIBS) +operations/composed_7.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_7$(EXEEXT): $(operations_composed_7_OBJECTS) $(operations_composed_7_DEPENDENCIES) $(EXTRA_operations_composed_7_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_7$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_7_OBJECTS) $(operations_composed_7_LDADD) $(LIBS) +operations/composed_8.$(OBJEXT): operations/$(am__dirstamp) \ + operations/$(DEPDIR)/$(am__dirstamp) + +operations/composed_8$(EXEEXT): $(operations_composed_8_OBJECTS) $(operations_composed_8_DEPENDENCIES) $(EXTRA_operations_composed_8_DEPENDENCIES) operations/$(am__dirstamp) + @rm -f operations/composed_8$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(operations_composed_8_OBJECTS) $(operations_composed_8_LDADD) $(LIBS) +type_erasure/$(am__dirstamp): + @$(MKDIR_P) type_erasure + @: > type_erasure/$(am__dirstamp) +type_erasure/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) type_erasure/$(DEPDIR) + @: > type_erasure/$(DEPDIR)/$(am__dirstamp) +type_erasure/main.$(OBJEXT): type_erasure/$(am__dirstamp) \ + type_erasure/$(DEPDIR)/$(am__dirstamp) +type_erasure/stdin_line_reader.$(OBJEXT): \ + type_erasure/$(am__dirstamp) \ + type_erasure/$(DEPDIR)/$(am__dirstamp) +type_erasure/sleep.$(OBJEXT): type_erasure/$(am__dirstamp) \ + type_erasure/$(DEPDIR)/$(am__dirstamp) + +type_erasure/type_erasure$(EXEEXT): $(type_erasure_type_erasure_OBJECTS) $(type_erasure_type_erasure_DEPENDENCIES) $(EXTRA_type_erasure_type_erasure_DEPENDENCIES) type_erasure/$(am__dirstamp) + @rm -f type_erasure/type_erasure$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(type_erasure_type_erasure_OBJECTS) $(type_erasure_type_erasure_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f ../../*.$(OBJEXT) + -rm -f channels/*.$(OBJEXT) + -rm -f coroutines/*.$(OBJEXT) + -rm -f invocation/*.$(OBJEXT) + -rm -f operations/*.$(OBJEXT) + -rm -f type_erasure/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@../../$(DEPDIR)/asio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@../../$(DEPDIR)/asio_ssl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@channels/$(DEPDIR)/mutual_exclusion_1.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@channels/$(DEPDIR)/mutual_exclusion_2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@channels/$(DEPDIR)/throttling_proxy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/chat_server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/echo_server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/echo_server_with_as_single_default.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/echo_server_with_as_tuple_default.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/echo_server_with_default.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/echo_server_with_deferred.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/echo_server_with_deferred_default.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/refactored_echo_server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@coroutines/$(DEPDIR)/timeout.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@invocation/$(DEPDIR)/completion_executor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/c_callback_wrapper.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/callback_wrapper.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_1.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_3.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_4.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_5.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_6.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_7.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@operations/$(DEPDIR)/composed_8.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@type_erasure/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@type_erasure/$(DEPDIR)/sleep.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@type_erasure/$(DEPDIR)/stdin_line_reader.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../../$(DEPDIR)/$(am__dirstamp) + -rm -f ../../$(am__dirstamp) + -rm -f channels/$(DEPDIR)/$(am__dirstamp) + -rm -f channels/$(am__dirstamp) + -rm -f coroutines/$(DEPDIR)/$(am__dirstamp) + -rm -f coroutines/$(am__dirstamp) + -rm -f invocation/$(DEPDIR)/$(am__dirstamp) + -rm -f invocation/$(am__dirstamp) + -rm -f operations/$(DEPDIR)/$(am__dirstamp) + -rm -f operations/$(am__dirstamp) + -rm -f type_erasure/$(DEPDIR)/$(am__dirstamp) + -rm -f type_erasure/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ../../$(DEPDIR)/asio.Po + -rm -f ../../$(DEPDIR)/asio_ssl.Po + -rm -f channels/$(DEPDIR)/mutual_exclusion_1.Po + -rm -f channels/$(DEPDIR)/mutual_exclusion_2.Po + -rm -f channels/$(DEPDIR)/throttling_proxy.Po + -rm -f coroutines/$(DEPDIR)/chat_server.Po + -rm -f coroutines/$(DEPDIR)/echo_server.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_as_single_default.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_as_tuple_default.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_default.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_deferred.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_deferred_default.Po + -rm -f coroutines/$(DEPDIR)/refactored_echo_server.Po + -rm -f coroutines/$(DEPDIR)/timeout.Po + -rm -f invocation/$(DEPDIR)/completion_executor.Po + -rm -f operations/$(DEPDIR)/c_callback_wrapper.Po + -rm -f operations/$(DEPDIR)/callback_wrapper.Po + -rm -f operations/$(DEPDIR)/composed_1.Po + -rm -f operations/$(DEPDIR)/composed_2.Po + -rm -f operations/$(DEPDIR)/composed_3.Po + -rm -f operations/$(DEPDIR)/composed_4.Po + -rm -f operations/$(DEPDIR)/composed_5.Po + -rm -f operations/$(DEPDIR)/composed_6.Po + -rm -f operations/$(DEPDIR)/composed_7.Po + -rm -f operations/$(DEPDIR)/composed_8.Po + -rm -f type_erasure/$(DEPDIR)/main.Po + -rm -f type_erasure/$(DEPDIR)/sleep.Po + -rm -f type_erasure/$(DEPDIR)/stdin_line_reader.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ../../$(DEPDIR)/asio.Po + -rm -f ../../$(DEPDIR)/asio_ssl.Po + -rm -f channels/$(DEPDIR)/mutual_exclusion_1.Po + -rm -f channels/$(DEPDIR)/mutual_exclusion_2.Po + -rm -f channels/$(DEPDIR)/throttling_proxy.Po + -rm -f coroutines/$(DEPDIR)/chat_server.Po + -rm -f coroutines/$(DEPDIR)/echo_server.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_as_single_default.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_as_tuple_default.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_default.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_deferred.Po + -rm -f coroutines/$(DEPDIR)/echo_server_with_deferred_default.Po + -rm -f coroutines/$(DEPDIR)/refactored_echo_server.Po + -rm -f coroutines/$(DEPDIR)/timeout.Po + -rm -f invocation/$(DEPDIR)/completion_executor.Po + -rm -f operations/$(DEPDIR)/c_callback_wrapper.Po + -rm -f operations/$(DEPDIR)/callback_wrapper.Po + -rm -f operations/$(DEPDIR)/composed_1.Po + -rm -f operations/$(DEPDIR)/composed_2.Po + -rm -f operations/$(DEPDIR)/composed_3.Po + -rm -f operations/$(DEPDIR)/composed_4.Po + -rm -f operations/$(DEPDIR)/composed_5.Po + -rm -f operations/$(DEPDIR)/composed_6.Po + -rm -f operations/$(DEPDIR)/composed_7.Po + -rm -f operations/$(DEPDIR)/composed_8.Po + -rm -f type_erasure/$(DEPDIR)/main.Po + -rm -f type_erasure/$(DEPDIR)/sleep.Po + -rm -f type_erasure/$(DEPDIR)/stdin_line_reader.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/3rdparty/asio/src/examples/cpp20/channels/mutual_exclusion_1.cpp b/3rdparty/asio/src/examples/cpp20/channels/mutual_exclusion_1.cpp new file mode 100644 index 00000000000..79654f1e8f1 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/channels/mutual_exclusion_1.cpp @@ -0,0 +1,182 @@ +// +// mutual_exclusion_1.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio.hpp> +#include <asio/experimental/channel.hpp> +#include <iostream> +#include <memory> + +using asio::as_tuple; +using asio::awaitable; +using asio::dynamic_buffer; +using asio::co_spawn; +using asio::deferred; +using asio::detached; +using asio::experimental::channel; +using asio::io_context; +using asio::ip::tcp; +using asio::steady_timer; +using namespace asio::buffer_literals; +using namespace std::literals::chrono_literals; + +// This class implements a simple line-based protocol: +// +// * For event line that is received from the client, the session sends a +// message header followed by the content of the line as the message body. +// +// * The session generates heartbeat messages once a second. +// +// This protocol is implemented using two actors, handle_messages() and +// send_heartbeats(), each written as a coroutine. +class line_based_echo_session : + public std::enable_shared_from_this<line_based_echo_session> +{ + // The socket used to read from and write to the client. This socket is a + // data member as it is shared between the two actors. + tcp::socket socket_; + + // As both of the actors will write to the socket, we need a lock to prevent + // these writes from overlapping. To achieve this, we use a channel with a + // buffer size of one. The lock is claimed by sending a message to the + // channel, and then released by receiving this message back again. If the + // lock is not held then the channel's buffer is empty, and the send will + // complete without delay. Otherwise, if the lock is held by the other actor, + // then the send operation will not complete until the lock is released. + channel<void()> write_lock_{socket_.get_executor(), 1}; + +public: + line_based_echo_session(tcp::socket socket) + : socket_{std::move(socket)} + { + socket_.set_option(tcp::no_delay(true)); + } + + void start() + { + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->handle_messages(); }, + detached); + + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->send_heartbeats(); }, + detached); + } + +private: + void stop() + { + socket_.close(); + write_lock_.cancel(); + } + + awaitable<void> handle_messages() + { + try + { + constexpr std::size_t max_line_length = 1024; + std::string data; + for (;;) + { + // Read an entire line from the client. + std::size_t length = co_await async_read_until(socket_, + dynamic_buffer(data, max_line_length), '\n', deferred); + + // Claim the write lock by sending a message to the channel. Since the + // channel signature is void(), there are no arguments to send in the + // message itself. + co_await write_lock_.async_send(deferred); + + // Respond to the client with a message, echoing the line they sent. + co_await async_write(socket_, "<line>"_buf, deferred); + co_await async_write(socket_, dynamic_buffer(data, length), deferred); + + // Release the lock by receiving the message back again. + write_lock_.try_receive([](auto...){}); + } + } + catch (const std::exception&) + { + stop(); + } + } + + awaitable<void> send_heartbeats() + { + steady_timer timer{socket_.get_executor()}; + try + { + for (;;) + { + // Wait one second before trying to send the next heartbeat. + timer.expires_after(1s); + co_await timer.async_wait(deferred); + + // Claim the write lock by sending a message to the channel. Since the + // channel signature is void(), there are no arguments to send in the + // message itself. + co_await write_lock_.async_send(deferred); + + // Send a heartbeat to the client. As the content of the heartbeat + // message never varies, a buffer literal can be used to specify the + // bytes of the message. The memory associated with a buffer literal is + // valid for the lifetime of the program, which mean that the buffer + // can be safely passed as-is to the asynchronous operation. + co_await async_write(socket_, "<heartbeat>\n"_buf, deferred); + + // Release the lock by receiving the message back again. + write_lock_.try_receive([](auto...){}); + } + } + catch (const std::exception&) + { + stop(); + } + } + +}; + +awaitable<void> listen(tcp::acceptor& acceptor) +{ + for (;;) + { + auto [e, socket] = co_await acceptor.async_accept(as_tuple(deferred)); + if (!e) + { + std::make_shared<line_based_echo_session>(std::move(socket))->start(); + } + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: mutual_exclusion_1"; + std::cerr << " <listen_address> <listen_port>\n"; + return 1; + } + + io_context ctx; + + auto listen_endpoint = + *tcp::resolver(ctx).resolve(argv[1], argv[2], + tcp::resolver::passive).begin(); + + tcp::acceptor acceptor(ctx, listen_endpoint); + co_spawn(ctx, listen(acceptor), detached); + ctx.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } +} diff --git a/3rdparty/asio/src/examples/cpp20/channels/mutual_exclusion_2.cpp b/3rdparty/asio/src/examples/cpp20/channels/mutual_exclusion_2.cpp new file mode 100644 index 00000000000..46cfeb647a2 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/channels/mutual_exclusion_2.cpp @@ -0,0 +1,192 @@ +// +// mutual_exclusion_2.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio.hpp> +#include <asio/experimental/channel.hpp> +#include <iostream> +#include <memory> + +using asio::as_tuple; +using asio::awaitable; +using asio::dynamic_buffer; +using asio::co_spawn; +using asio::deferred; +using asio::detached; +using asio::experimental::channel; +using asio::io_context; +using asio::ip::tcp; +using asio::steady_timer; +using namespace asio::buffer_literals; +using namespace std::literals::chrono_literals; + +// This class implements a simple line-based protocol: +// +// * For event line that is received from the client, the session sends a +// message header followed by the content of the line as the message body. +// +// * The session generates heartbeat messages once a second. +// +// This protocol is implemented using two actors, handle_messages() and +// send_heartbeats(), each written as a coroutine. +class line_based_echo_session : + public std::enable_shared_from_this<line_based_echo_session> +{ + // The socket used to read from and write to the client. This socket is a + // data member as it is shared between the two actors. + tcp::socket socket_; + + // As both of the actors will write to the socket, we need a lock to prevent + // these writes from overlapping. To achieve this, we use a channel with a + // buffer size of one. The lock is claimed by sending a message to the + // channel, and then released by receiving this message back again. If the + // lock is not held then the channel's buffer is empty, and the send will + // complete without delay. Otherwise, if the lock is held by the other actor, + // then the send operation will not complete until the lock is released. + channel<void()> write_lock_{socket_.get_executor(), 1}; + +public: + line_based_echo_session(tcp::socket socket) + : socket_{std::move(socket)} + { + socket_.set_option(tcp::no_delay(true)); + } + + void start() + { + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->handle_messages(); }, + detached); + + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->send_heartbeats(); }, + detached); + } + +private: + void stop() + { + socket_.close(); + write_lock_.cancel(); + } + + awaitable<void> handle_messages() + { + try + { + constexpr std::size_t max_line_length = 1024; + std::string data; + for (;;) + { + // Read an entire line from the client. + std::size_t length = co_await async_read_until(socket_, + dynamic_buffer(data, max_line_length), '\n', deferred); + + // Claim the write lock by sending a message to the channel. Since the + // channel signature is void(), there are no arguments to send in the + // message itself. In this example we optimise for the common case, + // where the lock is not held by the other actor, by first trying a + // non-blocking send. + if (!write_lock_.try_send()) + { + co_await write_lock_.async_send(deferred); + } + + // Respond to the client with a message, echoing the line they sent. + co_await async_write(socket_, "<line>"_buf, deferred); + co_await async_write(socket_, dynamic_buffer(data, length), deferred); + + // Release the lock by receiving the message back again. + write_lock_.try_receive([](auto...){}); + } + } + catch (const std::exception&) + { + stop(); + } + } + + awaitable<void> send_heartbeats() + { + steady_timer timer{socket_.get_executor()}; + try + { + for (;;) + { + // Wait one second before trying to send the next heartbeat. + timer.expires_after(1s); + co_await timer.async_wait(deferred); + + // Claim the write lock by sending a message to the channel. Since the + // channel signature is void(), there are no arguments to send in the + // message itself. In this example we optimise for the common case, + // where the lock is not held by the other actor, by first trying a + // non-blocking send. + if (!write_lock_.try_send()) + { + co_await write_lock_.async_send(deferred); + } + + // Send a heartbeat to the client. As the content of the heartbeat + // message never varies, a buffer literal can be used to specify the + // bytes of the message. The memory associated with a buffer literal is + // valid for the lifetime of the program, which mean that the buffer + // can be safely passed as-is to the asynchronous operation. + co_await async_write(socket_, "<heartbeat>\n"_buf, deferred); + + // Release the lock by receiving the message back again. + write_lock_.try_receive([](auto...){}); + } + } + catch (const std::exception&) + { + stop(); + } + } + +}; + +awaitable<void> listen(tcp::acceptor& acceptor) +{ + for (;;) + { + auto [e, socket] = co_await acceptor.async_accept(as_tuple(deferred)); + if (!e) + { + std::make_shared<line_based_echo_session>(std::move(socket))->start(); + } + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: mutual_exclusion_1"; + std::cerr << " <listen_address> <listen_port>\n"; + return 1; + } + + io_context ctx; + + auto listen_endpoint = + *tcp::resolver(ctx).resolve(argv[1], argv[2], + tcp::resolver::passive).begin(); + + tcp::acceptor acceptor(ctx, listen_endpoint); + co_spawn(ctx, listen(acceptor), detached); + ctx.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } +} diff --git a/3rdparty/asio/src/examples/cpp20/channels/throttling_proxy.cpp b/3rdparty/asio/src/examples/cpp20/channels/throttling_proxy.cpp new file mode 100644 index 00000000000..c54d2986af7 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/channels/throttling_proxy.cpp @@ -0,0 +1,135 @@ +// +// throttling_proxy.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio.hpp> +#include <asio/experimental/awaitable_operators.hpp> +#include <asio/experimental/channel.hpp> +#include <iostream> + +using asio::as_tuple; +using asio::awaitable; +using asio::buffer; +using asio::co_spawn; +using asio::detached; +using asio::experimental::channel; +using asio::io_context; +using asio::ip::tcp; +using asio::steady_timer; +using asio::use_awaitable; +namespace this_coro = asio::this_coro; +using namespace asio::experimental::awaitable_operators; +using namespace std::literals::chrono_literals; + +using token_channel = channel<void(asio::error_code, std::size_t)>; + +awaitable<void> produce_tokens(std::size_t bytes_per_token, + steady_timer::duration token_interval, token_channel& tokens) +{ + steady_timer timer(co_await this_coro::executor); + for (;;) + { + co_await tokens.async_send( + asio::error_code{}, bytes_per_token, + use_awaitable); + + timer.expires_after(token_interval); + co_await timer.async_wait(use_awaitable); + } +} + +awaitable<void> transfer(tcp::socket& from, + tcp::socket& to, token_channel& tokens) +{ + std::array<unsigned char, 4096> data; + for (;;) + { + std::size_t bytes_available = co_await tokens.async_receive(use_awaitable); + while (bytes_available > 0) + { + std::size_t n = co_await from.async_read_some( + buffer(data, bytes_available), use_awaitable); + + co_await async_write(to, buffer(data, n), use_awaitable); + + bytes_available -= n; + } + } +} + +awaitable<void> proxy(tcp::socket client, tcp::endpoint target) +{ + constexpr std::size_t number_of_tokens = 100; + constexpr size_t bytes_per_token = 20 * 1024; + constexpr steady_timer::duration token_interval = 100ms; + + auto ex = client.get_executor(); + tcp::socket server(ex); + token_channel client_tokens(ex, number_of_tokens); + token_channel server_tokens(ex, number_of_tokens); + + co_await server.async_connect(target, use_awaitable); + co_await ( + produce_tokens(bytes_per_token, token_interval, client_tokens) && + transfer(client, server, client_tokens) && + produce_tokens(bytes_per_token, token_interval, server_tokens) && + transfer(server, client, server_tokens) + ); +} + +awaitable<void> listen(tcp::acceptor& acceptor, tcp::endpoint target) +{ + for (;;) + { + auto [e, client] = co_await acceptor.async_accept(as_tuple(use_awaitable)); + if (!e) + { + auto ex = client.get_executor(); + co_spawn(ex, proxy(std::move(client), target), detached); + } + else + { + std::cerr << "Accept failed: " << e.message() << "\n"; + steady_timer timer(co_await this_coro::executor); + timer.expires_after(100ms); + co_await timer.async_wait(use_awaitable); + } + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 5) + { + std::cerr << "Usage: throttling_proxy"; + std::cerr << " <listen_address> <listen_port>"; + std::cerr << " <target_address> <target_port>\n"; + return 1; + } + + io_context ctx; + + auto listen_endpoint = + *tcp::resolver(ctx).resolve(argv[1], argv[2], + tcp::resolver::passive).begin(); + + auto target_endpoint = + *tcp::resolver(ctx).resolve(argv[3], argv[4]).begin(); + + tcp::acceptor acceptor(ctx, listen_endpoint); + co_spawn(ctx, listen(acceptor, target_endpoint), detached); + ctx.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/chat_server.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/chat_server.cpp new file mode 100644 index 00000000000..cd5fba32486 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/chat_server.cpp @@ -0,0 +1,222 @@ +// +// chat_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <deque> +#include <iostream> +#include <list> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <asio/awaitable.hpp> +#include <asio/detached.hpp> +#include <asio/co_spawn.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/read_until.hpp> +#include <asio/redirect_error.hpp> +#include <asio/signal_set.hpp> +#include <asio/steady_timer.hpp> +#include <asio/use_awaitable.hpp> +#include <asio/write.hpp> + +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using asio::redirect_error; +using asio::use_awaitable; + +//---------------------------------------------------------------------- + +class chat_participant +{ +public: + virtual ~chat_participant() {} + virtual void deliver(const std::string& msg) = 0; +}; + +typedef std::shared_ptr<chat_participant> chat_participant_ptr; + +//---------------------------------------------------------------------- + +class chat_room +{ +public: + void join(chat_participant_ptr participant) + { + participants_.insert(participant); + for (auto msg: recent_msgs_) + participant->deliver(msg); + } + + void leave(chat_participant_ptr participant) + { + participants_.erase(participant); + } + + void deliver(const std::string& msg) + { + recent_msgs_.push_back(msg); + while (recent_msgs_.size() > max_recent_msgs) + recent_msgs_.pop_front(); + + for (auto participant: participants_) + participant->deliver(msg); + } + +private: + std::set<chat_participant_ptr> participants_; + enum { max_recent_msgs = 100 }; + std::deque<std::string> recent_msgs_; +}; + +//---------------------------------------------------------------------- + +class chat_session + : public chat_participant, + public std::enable_shared_from_this<chat_session> +{ +public: + chat_session(tcp::socket socket, chat_room& room) + : socket_(std::move(socket)), + timer_(socket_.get_executor()), + room_(room) + { + timer_.expires_at(std::chrono::steady_clock::time_point::max()); + } + + void start() + { + room_.join(shared_from_this()); + + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->reader(); }, + detached); + + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->writer(); }, + detached); + } + + void deliver(const std::string& msg) + { + write_msgs_.push_back(msg); + timer_.cancel_one(); + } + +private: + awaitable<void> reader() + { + try + { + for (std::string read_msg;;) + { + std::size_t n = co_await asio::async_read_until(socket_, + asio::dynamic_buffer(read_msg, 1024), "\n", use_awaitable); + + room_.deliver(read_msg.substr(0, n)); + read_msg.erase(0, n); + } + } + catch (std::exception&) + { + stop(); + } + } + + awaitable<void> writer() + { + try + { + while (socket_.is_open()) + { + if (write_msgs_.empty()) + { + asio::error_code ec; + co_await timer_.async_wait(redirect_error(use_awaitable, ec)); + } + else + { + co_await asio::async_write(socket_, + asio::buffer(write_msgs_.front()), use_awaitable); + write_msgs_.pop_front(); + } + } + } + catch (std::exception&) + { + stop(); + } + } + + void stop() + { + room_.leave(shared_from_this()); + socket_.close(); + timer_.cancel(); + } + + tcp::socket socket_; + asio::steady_timer timer_; + chat_room& room_; + std::deque<std::string> write_msgs_; +}; + +//---------------------------------------------------------------------- + +awaitable<void> listener(tcp::acceptor acceptor) +{ + chat_room room; + + for (;;) + { + std::make_shared<chat_session>( + co_await acceptor.async_accept(use_awaitable), + room + )->start(); + } +} + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc < 2) + { + std::cerr << "Usage: chat_server <port> [<port> ...]\n"; + return 1; + } + + asio::io_context io_context(1); + + for (int i = 1; i < argc; ++i) + { + unsigned short port = std::atoi(argv[i]); + co_spawn(io_context, + listener(tcp::acceptor(io_context, {tcp::v4(), port})), + detached); + } + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/echo_server.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server.cpp new file mode 100644 index 00000000000..a9532459f77 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server.cpp @@ -0,0 +1,76 @@ +// +// echo_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/co_spawn.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using asio::use_awaitable; +namespace this_coro = asio::this_coro; + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# define use_awaitable \ + asio::use_awaitable_t(__FILE__, __LINE__, __PRETTY_FUNCTION__) +#endif + +awaitable<void> echo(tcp::socket socket) +{ + try + { + char data[1024]; + for (;;) + { + std::size_t n = co_await socket.async_read_some(asio::buffer(data), use_awaitable); + co_await async_write(socket, asio::buffer(data, n), use_awaitable); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp::acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + tcp::socket socket = co_await acceptor.async_accept(use_awaitable); + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_as_single_default.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_as_single_default.cpp new file mode 100644 index 00000000000..4a692acc872 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_as_single_default.cpp @@ -0,0 +1,71 @@ +// +// echo_server_with_as_single_default.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/experimental/as_single.hpp> +#include <asio/co_spawn.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::experimental::as_single_t; +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using asio::use_awaitable_t; +using default_token = as_single_t<use_awaitable_t<>>; +using tcp_acceptor = default_token::as_default_on_t<tcp::acceptor>; +using tcp_socket = default_token::as_default_on_t<tcp::socket>; +namespace this_coro = asio::this_coro; + +awaitable<void> echo(tcp_socket socket) +{ + char data[1024]; + for (;;) + { + auto [e1, nread] = co_await socket.async_read_some(asio::buffer(data)); + if (nread == 0) break; + auto [e2, nwritten] = co_await async_write(socket, asio::buffer(data, nread)); + if (nwritten != nread) break; + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp_acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + if (auto [e, socket] = co_await acceptor.async_accept(); socket.is_open()) + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_as_tuple_default.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_as_tuple_default.cpp new file mode 100644 index 00000000000..de162cad78e --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_as_tuple_default.cpp @@ -0,0 +1,71 @@ +// +// echo_server_with_as_tuple_default.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/as_tuple.hpp> +#include <asio/co_spawn.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::as_tuple_t; +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using asio::use_awaitable_t; +using default_token = as_tuple_t<use_awaitable_t<>>; +using tcp_acceptor = default_token::as_default_on_t<tcp::acceptor>; +using tcp_socket = default_token::as_default_on_t<tcp::socket>; +namespace this_coro = asio::this_coro; + +awaitable<void> echo(tcp_socket socket) +{ + char data[1024]; + for (;;) + { + auto [e1, nread] = co_await socket.async_read_some(asio::buffer(data)); + if (nread == 0) break; + auto [e2, nwritten] = co_await async_write(socket, asio::buffer(data, nread)); + if (nwritten != nread) break; + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp_acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + if (auto [e, socket] = co_await acceptor.async_accept(); socket.is_open()) + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_default.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_default.cpp new file mode 100644 index 00000000000..54344d94d56 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_default.cpp @@ -0,0 +1,73 @@ +// +// echo_server_with_default.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/co_spawn.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using asio::use_awaitable_t; +using tcp_acceptor = use_awaitable_t<>::as_default_on_t<tcp::acceptor>; +using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>; +namespace this_coro = asio::this_coro; + +awaitable<void> echo(tcp_socket socket) +{ + try + { + char data[1024]; + for (;;) + { + std::size_t n = co_await socket.async_read_some(asio::buffer(data)); + co_await async_write(socket, asio::buffer(data, n)); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp_acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + auto socket = co_await acceptor.async_accept(); + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_deferred.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_deferred.cpp new file mode 100644 index 00000000000..54469ba7aba --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_deferred.cpp @@ -0,0 +1,72 @@ +// +// echo_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/co_spawn.hpp> +#include <asio/deferred.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::deferred; +using asio::detached; +namespace this_coro = asio::this_coro; + +awaitable<void> echo(tcp::socket socket) +{ + try + { + char data[1024]; + for (;;) + { + std::size_t n = co_await socket.async_read_some(asio::buffer(data), deferred); + co_await async_write(socket, asio::buffer(data, n), deferred); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp::acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + tcp::socket socket = co_await acceptor.async_accept(deferred); + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_deferred_default.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_deferred_default.cpp new file mode 100644 index 00000000000..33c383311d2 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/echo_server_with_deferred_default.cpp @@ -0,0 +1,74 @@ +// +// echo_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/co_spawn.hpp> +#include <asio/deferred.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using default_token = asio::deferred_t; +using tcp_acceptor = default_token::as_default_on_t<tcp::acceptor>; +using tcp_socket = default_token::as_default_on_t<tcp::socket>; +namespace this_coro = asio::this_coro; + +awaitable<void> echo(tcp_socket socket) +{ + try + { + char data[1024]; + for (;;) + { + std::size_t n = co_await socket.async_read_some(asio::buffer(data)); + co_await async_write(socket, asio::buffer(data, n)); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp_acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + tcp::socket socket = co_await acceptor.async_accept(); + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/refactored_echo_server.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/refactored_echo_server.cpp new file mode 100644 index 00000000000..dc7b03d86e2 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/refactored_echo_server.cpp @@ -0,0 +1,80 @@ +// +// refactored_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/co_spawn.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/signal_set.hpp> +#include <asio/write.hpp> +#include <cstdio> + +using asio::ip::tcp; +using asio::awaitable; +using asio::co_spawn; +using asio::detached; +using asio::use_awaitable; +namespace this_coro = asio::this_coro; + +awaitable<void> echo_once(tcp::socket& socket) +{ + char data[128]; + std::size_t n = co_await socket.async_read_some(asio::buffer(data), use_awaitable); + co_await async_write(socket, asio::buffer(data, n), use_awaitable); +} + +awaitable<void> echo(tcp::socket socket) +{ + try + { + for (;;) + { + // The asynchronous operations to echo a single chunk of data have been + // refactored into a separate function. When this function is called, the + // operations are still performed in the context of the current + // coroutine, and the behaviour is functionally equivalent. + co_await echo_once(socket); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp::acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + tcp::socket socket = co_await acceptor.async_accept(use_awaitable); + co_spawn(executor, echo(std::move(socket)), detached); + } +} + +int main() +{ + try + { + asio::io_context io_context(1); + + asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener(), detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/3rdparty/asio/src/examples/cpp20/coroutines/timeout.cpp b/3rdparty/asio/src/examples/cpp20/coroutines/timeout.cpp new file mode 100644 index 00000000000..2ffcab7ad35 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/coroutines/timeout.cpp @@ -0,0 +1,66 @@ +// +// timeout.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio.hpp> +#include <asio/experimental/awaitable_operators.hpp> + +using namespace asio; +using namespace asio::experimental::awaitable_operators; +using time_point = std::chrono::steady_clock::time_point; +using ip::tcp; + +awaitable<void> echo(tcp::socket& sock, time_point& deadline) +{ + char data[4196]; + for (;;) + { + deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); + auto n = co_await sock.async_read_some(buffer(data), use_awaitable); + co_await async_write(sock, buffer(data, n), use_awaitable); + } +} + +awaitable<void> watchdog(time_point& deadline) +{ + steady_timer timer(co_await this_coro::executor); + auto now = std::chrono::steady_clock::now(); + while (deadline > now) + { + timer.expires_at(deadline); + co_await timer.async_wait(use_awaitable); + now = std::chrono::steady_clock::now(); + } + throw std::system_error(std::make_error_code(std::errc::timed_out)); +} + +awaitable<void> handle_connection(tcp::socket sock) +{ + time_point deadline{}; + co_await (echo(sock, deadline) && watchdog(deadline)); +} + +awaitable<void> listen(tcp::acceptor& acceptor) +{ + for (;;) + { + co_spawn( + acceptor.get_executor(), + handle_connection(co_await acceptor.async_accept(use_awaitable)), + detached); + } +} + +int main() +{ + io_context ctx; + tcp::acceptor acceptor(ctx, {tcp::v4(), 54321}); + co_spawn(ctx, listen(acceptor), detached); + ctx.run(); +} diff --git a/3rdparty/asio/src/examples/cpp20/invocation/completion_executor.cpp b/3rdparty/asio/src/examples/cpp20/invocation/completion_executor.cpp new file mode 100644 index 00000000000..409be96d0f4 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/invocation/completion_executor.cpp @@ -0,0 +1,83 @@ +// +// completion_executor.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "asio.hpp" +#include <concepts> +#include <iostream> + +using asio::ip::tcp; + +//---------------------------------------------------------------------- + +// The logging_executor class implements a minimal executor that satisfies the +// requirements for use as a completion executor. This means it may be bound to +// a handler using bind_executor. +class logging_executor +{ +public: + // All executors must be no-throw equality comparable. + bool operator==(const logging_executor&) const noexcept = default; + + // All executors must provide a const member function execute(). + void execute(std::invocable auto handler) const + { + try + { + std::cout << "handler invocation starting\n"; + std::move(handler)(); + std::cout << "handler invocation complete\n"; + } + catch (...) + { + std::cout << "handler invocation completed with exception\n"; + throw; + } + } +}; + +// Confirm that a logging_executor satisfies the executor requirements. +static_assert(asio::execution::executor<logging_executor>); + +// Confirm that a logging_executor can be used as a completion executor. +static_assert(std::convertible_to< + logging_executor, asio::any_completion_executor>); + +//---------------------------------------------------------------------- + +int main() +{ + asio::io_context io_context(1); + + // Post a completion handler to be run immediately. + asio::post(io_context, + asio::bind_executor(logging_executor{}, + []{ std::cout << "post complete\n"; })); + + // Start an asynchronous accept that will complete immediately. + tcp::endpoint endpoint(asio::ip::address_v4::loopback(), 0); + tcp::acceptor acceptor(io_context, endpoint); + tcp::socket server_socket(io_context); + acceptor.async_accept( + asio::bind_executor(logging_executor{}, + [](auto...){ std::cout << "async_accept complete\n"; })); + tcp::socket client_socket(io_context); + client_socket.connect(acceptor.local_endpoint()); + + // Set a timer to expire immediately. + asio::steady_timer timer(io_context); + timer.expires_at(asio::steady_timer::clock_type::time_point::min()); + timer.async_wait( + asio::bind_executor(logging_executor{}, + [](auto){ std::cout << "async_wait complete\n"; })); + + io_context.run(); + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/c_callback_wrapper.cpp b/3rdparty/asio/src/examples/cpp20/operations/c_callback_wrapper.cpp new file mode 100644 index 00000000000..f4fbe2617ea --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/c_callback_wrapper.cpp @@ -0,0 +1,232 @@ +// +// c_callback_wrapper.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio.hpp> +#include <iostream> +#include <memory> +#include <new> + +//------------------------------------------------------------------------------ + +// This is a mock implementation of a C-based API that uses the function pointer +// plus void* context idiom for exposing a callback. + +void read_input(const char* prompt, void (*cb)(void*, const char*), void* arg) +{ + std::thread( + [prompt = std::string(prompt), cb, arg] + { + std::cout << prompt << ": "; + std::cout.flush(); + std::string line; + std::getline(std::cin, line); + cb(arg, line.c_str()); + }).detach(); +} + +//------------------------------------------------------------------------------ + +// This is an asynchronous operation that wraps the C-based API. + +// To map our completion handler into a function pointer / void* callback, we +// need to allocate some state that will live for the duration of the +// operation. A pointer to this state will be passed to the C-based API. +template <asio::completion_handler_for<void(std::string)> Handler> +class read_input_state +{ +public: + read_input_state(Handler&& handler) + : handler_(std::move(handler)), + work_(asio::make_work_guard(handler_)) + { + } + + // Create the state using the handler's associated allocator. + static read_input_state* create(Handler&& handler) + { + // A unique_ptr deleter that is used to destroy uninitialised objects. + struct deleter + { + // Get the handler's associated allocator type. If the handler does not + // specify an associated allocator, we will use a recycling allocator as + // the default. As the associated allocator is a proto-allocator, we must + // rebind it to the correct type before we can use it to allocate objects. + typename std::allocator_traits< + asio::associated_allocator_t<Handler, + asio::recycling_allocator<void>>>::template + rebind_alloc<read_input_state> alloc; + + void operator()(read_input_state* ptr) + { + std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1); + } + } d{asio::get_associated_allocator(handler, + asio::recycling_allocator<void>())}; + + // Allocate memory for the state. + std::unique_ptr<read_input_state, deleter> uninit_ptr( + std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d); + + // Construct the state into the newly allocated memory. This might throw. + read_input_state* ptr = + new (uninit_ptr.get()) read_input_state(std::move(handler)); + + // Release ownership of the memory and return the newly allocated state. + uninit_ptr.release(); + return ptr; + } + + static void callback(void* arg, const char* result) + { + read_input_state* self = static_cast<read_input_state*>(arg); + + // A unique_ptr deleter that is used to destroy initialised objects. + struct deleter + { + // Get the handler's associated allocator type. If the handler does not + // specify an associated allocator, we will use a recycling allocator as + // the default. As the associated allocator is a proto-allocator, we must + // rebind it to the correct type before we can use it to allocate objects. + typename std::allocator_traits< + asio::associated_allocator_t<Handler, + asio::recycling_allocator<void>>>::template + rebind_alloc<read_input_state> alloc; + + void operator()(read_input_state* ptr) + { + std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr); + std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1); + } + } d{asio::get_associated_allocator(self->handler_, + asio::recycling_allocator<void>())}; + + // To conform to the rules regarding asynchronous operations and memory + // allocation, we must make a copy of the state and deallocate the memory + // before dispatching the completion handler. + std::unique_ptr<read_input_state, deleter> state_ptr(self, d); + read_input_state state(std::move(*self)); + state_ptr.reset(); + + // Dispatch the completion handler through the handler's associated + // executor, using the handler's associated allocator. + asio::dispatch(state.work_.get_executor(), + asio::bind_allocator(d.alloc, + [ + handler = std::move(state.handler_), + result = std::string(result) + ]() mutable + { + std::move(handler)(result); + })); + } + +private: + Handler handler_; + + // According to the rules for asynchronous operations, we need to track + // outstanding work against the handler's associated executor until the + // asynchronous operation is complete. + asio::executor_work_guard< + asio::associated_executor_t<Handler>> work_; +}; + +// The initiating function for the asynchronous operation. +template <asio::completion_token_for<void(std::string)> CompletionToken> +auto async_read_input(const std::string& prompt, CompletionToken&& token) +{ + // Define a function object that contains the code to launch the asynchronous + // operation. This is passed the concrete completion handler, followed by any + // additional arguments that were passed through the call to async_initiate. + auto init = []( + asio::completion_handler_for<void(std::string)> auto handler, + const std::string& prompt) + { + // The body of the initiation function object creates the long-lived state + // and passes it to the C-based API, along with the function pointer. + using state_type = read_input_state<decltype(handler)>; + read_input(prompt.c_str(), &state_type::callback, + state_type::create(std::move(handler))); + }; + + // The async_initiate function is used to transform the supplied completion + // token to the completion handler. When calling this function we explicitly + // specify the completion signature of the operation. We must also return the + // result of the call since the completion token may produce a return value, + // such as a future. + return asio::async_initiate<CompletionToken, void(std::string)>( + init, // First, pass the function object that launches the operation, + token, // then the completion token that will be transformed to a handler, + prompt); // and, finally, any additional arguments to the function object. +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + // Test our asynchronous operation using a lambda as a callback. We will use + // an io_context to obtain an associated executor. + async_read_input("Enter your name", + asio::bind_executor(io_context, + [](const std::string& result) + { + std::cout << "Hello " << result << "\n"; + })); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_read_input("Enter your name", asio::deferred); + + // Launch our asynchronous operation using a lambda as a callback. We will use + // an io_context to obtain an associated executor. + std::move(op)( + asio::bind_executor(io_context, + [](const std::string& result) + { + std::cout << "Hello " << result << "\n"; + })); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::string> f = + async_read_input("Enter your name", asio::use_future); + + std::string result = f.get(); + std::cout << "Hello " << result << "\n"; +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/callback_wrapper.cpp b/3rdparty/asio/src/examples/cpp20/operations/callback_wrapper.cpp new file mode 100644 index 00000000000..f8f37b48944 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/callback_wrapper.cpp @@ -0,0 +1,154 @@ +// +// callback_wrapper.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio.hpp> +#include <iostream> + +//------------------------------------------------------------------------------ + +// This is a mock implementation of an API that uses a move-only function object +// for exposing a callback. The callback has the signature void(std::string). + +template <typename Callback> +void read_input(const std::string& prompt, Callback cb) +{ + std::thread( + [prompt, cb = std::move(cb)]() mutable + { + std::cout << prompt << ": "; + std::cout.flush(); + std::string line; + std::getline(std::cin, line); + std::move(cb)(std::move(line)); + }).detach(); +} + +//------------------------------------------------------------------------------ + +// This is an asynchronous operation that wraps the callback-based API. + +// The initiating function for the asynchronous operation. +template <asio::completion_token_for<void(std::string)> CompletionToken> +auto async_read_input(const std::string& prompt, CompletionToken&& token) +{ + // Define a function object that contains the code to launch the asynchronous + // operation. This is passed the concrete completion handler, followed by any + // additional arguments that were passed through the call to async_initiate. + auto init = []( + asio::completion_handler_for<void(std::string)> auto handler, + const std::string& prompt) + { + // According to the rules for asynchronous operations, we need to track + // outstanding work against the handler's associated executor until the + // asynchronous operation is complete. + auto work = asio::make_work_guard(handler); + + // Launch the operation with a callback that will receive the result and + // pass it through to the asynchronous operation's completion handler. + read_input(prompt, + [ + handler = std::move(handler), + work = std::move(work) + ](std::string result) mutable + { + // Get the handler's associated allocator. If the handler does not + // specify an allocator, use the recycling allocator as the default. + auto alloc = asio::get_associated_allocator( + handler, asio::recycling_allocator<void>()); + + // Dispatch the completion handler through the handler's associated + // executor, using the handler's associated allocator. + asio::dispatch(work.get_executor(), + asio::bind_allocator(alloc, + [ + handler = std::move(handler), + result = std::string(result) + ]() mutable + { + std::move(handler)(result); + })); + }); + }; + + // The async_initiate function is used to transform the supplied completion + // token to the completion handler. When calling this function we explicitly + // specify the completion signature of the operation. We must also return the + // result of the call since the completion token may produce a return value, + // such as a future. + return asio::async_initiate<CompletionToken, void(std::string)>( + init, // First, pass the function object that launches the operation, + token, // then the completion token that will be transformed to a handler, + prompt); // and, finally, any additional arguments to the function object. +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + // Test our asynchronous operation using a lambda as a callback. We will use + // an io_context to specify an associated executor. + async_read_input("Enter your name", + asio::bind_executor(io_context, + [](const std::string& result) + { + std::cout << "Hello " << result << "\n"; + })); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + auto op = async_read_input("Enter your name", asio::deferred); + + // Launch our asynchronous operation using a lambda as a callback. We will use + // an io_context to obtain an associated executor. + std::move(op)( + asio::bind_executor(io_context, + [](const std::string& result) + { + std::cout << "Hello " << result << "\n"; + })); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::string> f = + async_read_input("Enter your name", asio::use_future); + + std::string result = f.get(); + std::cout << "Hello " << result << "\n"; +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_1.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_1.cpp new file mode 100644 index 00000000000..e7f795e1756 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_1.cpp @@ -0,0 +1,157 @@ +// +// composed_1.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <cstring> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +//------------------------------------------------------------------------------ + +// This is the simplest example of a composed asynchronous operation, where we +// simply repackage an existing operation. The asynchronous operation +// requirements are met by delegating responsibility to the underlying +// operation. + +template < + asio::completion_token_for<void(std::error_code, std::size_t)> + CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is void. + // However, when the completion token is asio::yield_context (used for + // stackful coroutines) the return type would be std::size_t, and when the + // completion token is asio::use_future it would be std::future<std::size_t>. + // When the completion token is asio::deferred, the return type differs for + // each asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of our underlying asynchronous operation. +{ + // When delegating to the underlying operation we must take care to perfectly + // forward the completion token. This ensures that our operation works + // correctly with move-only function objects as callbacks, as well as other + // completion token types. + return asio::async_write(socket, + asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", + [](const std::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_message( + socket, "Testing deferred\r\n", asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::size_t> f = async_write_message( + socket, "Testing future\r\n", asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + std::size_t n = f.get(); + std::cout << n << " bytes transferred\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_2.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_2.cpp new file mode 100644 index 00000000000..ada029d38f0 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_2.cpp @@ -0,0 +1,225 @@ +// +// composed_2.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <cstring> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This next simplest example of a composed asynchronous operation involves +// repackaging multiple operations but choosing to invoke just one of them. All +// of these underlying operations have the same completion signature. The +// asynchronous operation requirements are met by delegating responsibility to +// the underlying operations. + +template < + asio::completion_token_for<void(std::error_code, std::size_t)> + CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, bool allow_partial_write, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is void. + // However, when the completion token is asio::yield_context (used for + // stackful coroutines) the return type would be std::size_t, and when the + // completion token is asio::use_future it would be std::future<std::size_t>. + // When the completion token is asio::deferred, the return type differs for + // each asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(std::error_code error, std::size_t) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = []( + asio::completion_handler_for<void(std::error_code, std::size_t)> + auto&& completion_handler, + tcp::socket& socket, + const char* message, + bool allow_partial_write) + { + if (allow_partial_write) + { + // When delegating to an underlying operation we must take care to + // perfectly forward the completion handler. This ensures that our + // operation works correctly with move-only function objects as + // callbacks. + return socket.async_write_some( + asio::buffer(message, std::strlen(message)), + std::forward<decltype(completion_handler)>(completion_handler)); + } + else + { + // As above, we must perfectly forward the completion handler when calling + // the alternate underlying operation. + return asio::async_write(socket, + asio::buffer(message, std::strlen(message)), + std::forward<decltype(completion_handler)>(completion_handler)); + } + }; + + // The asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return asio::async_initiate< + CompletionToken, void(std::error_code, std::size_t)>( + initiation, token, std::ref(socket), message, allow_partial_write); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", false, + [](const std::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_message( + socket, "Testing deferred\r\n", false, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::size_t> f = async_write_message( + socket, "Testing future\r\n", false, asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + std::size_t n = f.get(); + std::cout << n << " bytes transferred\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_3.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_3.cpp new file mode 100644 index 00000000000..46436a68e28 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_3.cpp @@ -0,0 +1,232 @@ +// +// composed_3.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/bind_executor.hpp> +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <cstring> +#include <functional> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// In this composed operation we repackage an existing operation, but with a +// different completion handler signature. The asynchronous operation +// requirements are met by delegating responsibility to the underlying +// operation. + +template < + asio::completion_token_for<void(std::error_code)> CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(std::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = []( + asio::completion_handler_for<void(std::error_code)> + auto&& completion_handler, + tcp::socket& socket, + const char* message) + { + // The async_write operation has a completion handler signature of: + // + // void(std::error_code error, std::size n) + // + // This differs from our operation's signature in that it is also passed + // the number of bytes transferred as an argument of type std::size_t. We + // will adapt our completion handler to async_write's completion handler + // signature by using std::bind, which drops the additional argument. + // + // However, it is essential to the correctness of our composed operation + // that we preserve the executor of the user-supplied completion handler. + // The std::bind function will not do this for us, so we must do this by + // first obtaining the completion handler's associated executor (defaulting + // to the I/O executor - in this case the executor of the socket - if the + // completion handler does not have its own) ... + auto executor = asio::get_associated_executor( + completion_handler, socket.get_executor()); + + // ... and then binding this executor to our adapted completion handler + // using the asio::bind_executor function. + asio::async_write(socket, + asio::buffer(message, std::strlen(message)), + asio::bind_executor(executor, + std::bind(std::forward<decltype(completion_handler)>( + completion_handler), std::placeholders::_1))); + }; + + // The asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return asio::async_initiate< + CompletionToken, void(std::error_code)>( + initiation, token, std::ref(socket), message); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_message( + socket, "Testing deferred\r\n", asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, "Testing future\r\n", asio::use_future); + + io_context.run(); + + // Get the result of the operation. + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_4.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_4.cpp new file mode 100644 index 00000000000..069f57ce1ac --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_4.cpp @@ -0,0 +1,247 @@ +// +// composed_4.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/bind_executor.hpp> +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <cstring> +#include <functional> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// In this composed operation we repackage an existing operation, but with a +// different completion handler signature. We will also intercept an empty +// message as an invalid argument, and propagate the corresponding error to the +// user. The asynchronous operation requirements are met by delegating +// responsibility to the underlying operation. + +template < + asio::completion_token_for<void(std::error_code)> CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(std::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = []( + asio::completion_handler_for<void(std::error_code)> + auto&& completion_handler, + tcp::socket& socket, + const char* message) + { + // The post operation has a completion handler signature of: + // + // void() + // + // and the async_write operation has a completion handler signature of: + // + // void(std::error_code error, std::size n) + // + // Both of these operations' completion handler signatures differ from our + // operation's completion handler signature. We will adapt our completion + // handler to these signatures by using std::bind, which drops the + // additional arguments. + // + // However, it is essential to the correctness of our composed operation + // that we preserve the executor of the user-supplied completion handler. + // The std::bind function will not do this for us, so we must do this by + // first obtaining the completion handler's associated executor (defaulting + // to the I/O executor - in this case the executor of the socket - if the + // completion handler does not have its own) ... + auto executor = asio::get_associated_executor( + completion_handler, socket.get_executor()); + + // ... and then binding this executor to our adapted completion handler + // using the asio::bind_executor function. + std::size_t length = std::strlen(message); + if (length == 0) + { + asio::post( + asio::bind_executor(executor, + std::bind(std::forward<decltype(completion_handler)>( + completion_handler), asio::error::invalid_argument))); + } + else + { + asio::async_write(socket, + asio::buffer(message, length), + asio::bind_executor(executor, + std::bind(std::forward<decltype(completion_handler)>( + completion_handler), std::placeholders::_1))); + } + }; + + // The asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return asio::async_initiate< + CompletionToken, void(std::error_code)>( + initiation, token, std::ref(socket), message); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "", + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = + async_write_message(socket, "", asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, "", asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_5.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_5.cpp new file mode 100644 index 00000000000..bec83ec3a59 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_5.cpp @@ -0,0 +1,284 @@ +// +// composed_5.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation automatically serialises a message, using its I/O +// streams insertion operator, before sending it on the socket. To do this, it +// must allocate a buffer for the encoded message and ensure this buffer's +// validity until the underlying async_write operation completes. + +template <typename T, + asio::completion_token_for<void(std::error_code)> CompletionToken> +auto async_write_message(tcp::socket& socket, + const T& message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(std::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = []( + asio::completion_handler_for<void(std::error_code)> + auto&& completion_handler, + tcp::socket& socket, + std::unique_ptr<std::string> encoded_message) + { + // In this example, the composed operation's intermediate completion + // handler is implemented as a hand-crafted function object, rather than + // using a lambda or std::bind. + struct intermediate_completion_handler + { + // The intermediate completion handler holds a reference to the socket so + // that it can obtain the I/O executor (see get_executor below). + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our intermediate + // completion handler is also move-only. + std::unique_ptr<std::string> encoded_message_; + + // The user-supplied completion handler. + typename std::decay<decltype(completion_handler)>::type handler_; + + // The function call operator matches the completion signature of the + // async_write operation. + void operator()(const std::error_code& error, std::size_t /*n*/) + { + // Deallocate the encoded message before calling the user-supplied + // completion handler. + encoded_message_.reset(); + + // Call the user-supplied handler with the result of the operation. + // The arguments must match the completion signature of our composed + // operation. + handler_(error); + } + + // It is essential to the correctness of our composed operation that we + // preserve the executor of the user-supplied completion handler. With a + // hand-crafted function object we can do this by defining a nested type + // executor_type and member function get_executor. These obtain the + // completion handler's associated executor, and default to the I/O + // executor - in this case the executor of the socket - if the completion + // handler does not have its own. + using executor_type = asio::associated_executor_t< + typename std::decay<decltype(completion_handler)>::type, + tcp::socket::executor_type>; + + executor_type get_executor() const noexcept + { + return asio::get_associated_executor( + handler_, socket_.get_executor()); + } + + // Although not necessary for correctness, we may also preserve the + // allocator of the user-supplied completion handler. This is achieved by + // defining a nested type allocator_type and member function + // get_allocator. These obtain the completion handler's associated + // allocator, and default to std::allocator<void> if the completion + // handler does not have its own. + using allocator_type = asio::associated_allocator_t< + typename std::decay<decltype(completion_handler)>::type, + std::allocator<void>>; + + allocator_type get_allocator() const noexcept + { + return asio::get_associated_allocator( + handler_, std::allocator<void>{}); + } + }; + + // Initiate the underlying async_write operation using our intermediate + // completion handler. + auto encoded_message_buffer = asio::buffer(*encoded_message); + asio::async_write(socket, encoded_message_buffer, + intermediate_completion_handler{socket, std::move(encoded_message), + std::forward<decltype(completion_handler)>(completion_handler)}); + }; + + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // The asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return asio::async_initiate< + CompletionToken, void(std::error_code)>( + initiation, token, std::ref(socket), + std::move(encoded_message)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, 123456, + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_message( + socket, std::string("abcdef"), asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, 654.321, asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_6.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_6.cpp new file mode 100644 index 00000000000..77e2f50f93e --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_6.cpp @@ -0,0 +1,345 @@ +// +// composed_6.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/deferred.hpp> +#include <asio/executor_work_guard.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/steady_timer.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations. +// It automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +template <typename T, + asio::completion_token_for<void(std::error_code)> CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(std::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = []( + asio::completion_handler_for<void(std::error_code)> + auto&& completion_handler, + tcp::socket& socket, + std::unique_ptr<std::string> encoded_message, + std::size_t repeat_count, + std::unique_ptr<asio::steady_timer> delay_timer) + { + // In this example, the composed operation's intermediate completion + // handler is implemented as a hand-crafted function object. + struct intermediate_completion_handler + { + // The intermediate completion handler holds a reference to the socket as + // it is used for multiple async_write operations, as well as for + // obtaining the I/O executor (see get_executor below). + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our intermediate + // completion handler is also move-only. + std::unique_ptr<std::string> encoded_message_; + + // The repeat count remaining. + std::size_t repeat_count_; + + // A steady timer used for introducing a delay. + std::unique_ptr<asio::steady_timer> delay_timer_; + + // To manage the cycle between the multiple underlying asychronous + // operations, our intermediate completion handler is implemented as a + // state machine. + enum { starting, waiting, writing } state_; + + // As our composed operation performs multiple underlying I/O operations, + // we should maintain a work object against the I/O executor. This tells + // the I/O executor that there is still more work to come in the future. + asio::executor_work_guard<tcp::socket::executor_type> io_work_; + + // The user-supplied completion handler, called once only on completion + // of the entire composed operation. + typename std::decay<decltype(completion_handler)>::type handler_; + + // By having a default value for the second argument, this function call + // operator matches the completion signature of both the async_write and + // steady_timer::async_wait operations. + void operator()(const std::error_code& error, std::size_t = 0) + { + if (!error) + { + switch (state_) + { + case starting: + case writing: + if (repeat_count_ > 0) + { + --repeat_count_; + state_ = waiting; + delay_timer_->expires_after(std::chrono::seconds(1)); + delay_timer_->async_wait(std::move(*this)); + return; // Composed operation not yet complete. + } + break; // Composed operation complete, continue below. + case waiting: + state_ = writing; + asio::async_write(socket_, + asio::buffer(*encoded_message_), std::move(*this)); + return; // Composed operation not yet complete. + } + } + + // This point is reached only on completion of the entire composed + // operation. + + // We no longer have any future work coming for the I/O executor. + io_work_.reset(); + + // Deallocate the encoded message before calling the user-supplied + // completion handler. + encoded_message_.reset(); + + // Call the user-supplied handler with the result of the operation. + handler_(error); + } + + // It is essential to the correctness of our composed operation that we + // preserve the executor of the user-supplied completion handler. With a + // hand-crafted function object we can do this by defining a nested type + // executor_type and member function get_executor. These obtain the + // completion handler's associated executor, and default to the I/O + // executor - in this case the executor of the socket - if the completion + // handler does not have its own. + using executor_type = asio::associated_executor_t< + typename std::decay<decltype(completion_handler)>::type, + tcp::socket::executor_type>; + + executor_type get_executor() const noexcept + { + return asio::get_associated_executor( + handler_, socket_.get_executor()); + } + + // Although not necessary for correctness, we may also preserve the + // allocator of the user-supplied completion handler. This is achieved by + // defining a nested type allocator_type and member function + // get_allocator. These obtain the completion handler's associated + // allocator, and default to std::allocator<void> if the completion + // handler does not have its own. + using allocator_type = asio::associated_allocator_t< + typename std::decay<decltype(completion_handler)>::type, + std::allocator<void>>; + + allocator_type get_allocator() const noexcept + { + return asio::get_associated_allocator( + handler_, std::allocator<void>{}); + } + }; + + // Initiate the underlying async_write operation using our intermediate + // completion handler. + auto encoded_message_buffer = asio::buffer(*encoded_message); + asio::async_write(socket, encoded_message_buffer, + intermediate_completion_handler{ + socket, std::move(encoded_message), + repeat_count, std::move(delay_timer), + intermediate_completion_handler::starting, + asio::make_work_guard(socket.get_executor()), + std::forward<decltype(completion_handler)>(completion_handler)}); + }; + + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<asio::steady_timer> delay_timer( + new asio::steady_timer(socket.get_executor())); + + // The asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return asio::async_initiate< + CompletionToken, void(std::error_code)>( + initiation, token, std::ref(socket), + std::move(encoded_message), repeat_count, + std::move(delay_timer)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_messages( + socket, "Testing deferred\r\n", 5, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_7.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_7.cpp new file mode 100644 index 00000000000..9ae44c797fb --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_7.cpp @@ -0,0 +1,262 @@ +// +// composed_7.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/compose.hpp> +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/steady_timer.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_compose function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations. +// It automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +template <typename T, + asio::completion_token_for<void(std::error_code)> CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_compose. +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<asio::steady_timer> delay_timer( + new asio::steady_timer(socket.get_executor())); + + // To manage the cycle between the multiple underlying asychronous + // operations, our implementation is a state machine. + enum { starting, waiting, writing }; + + // The asio::async_compose function takes: + // + // - our asynchronous operation implementation, + // - the completion token, + // - the completion handler signature, and + // - any I/O objects (or executors) used by the operation + // + // It then wraps our implementation, which is implemented here as a state + // machine in a lambda, in an intermediate completion handler that meets the + // requirements of a conforming asynchronous operation. This includes + // tracking outstanding work against the I/O executors associated with the + // operation (in this example, this is the socket's executor). + // + // The first argument to our lambda is a reference to the enclosing + // intermediate completion handler. This intermediate completion handler is + // provided for us by the asio::async_compose function, and takes care + // of all the details required to implement a conforming asynchronous + // operation. When calling an underlying asynchronous operation, we pass it + // this enclosing intermediate completion handler as the completion token. + // + // All arguments to our lambda after the first must be defaulted to allow the + // state machine to be started, as well as to allow the completion handler to + // match the completion signature of both the async_write and + // steady_timer::async_wait operations. + return asio::async_compose< + CompletionToken, void(std::error_code)>( + [ + // The implementation holds a reference to the socket as it is used for + // multiple async_write operations. + &socket, + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our lambda + // implementation is also move-only. + encoded_message = std::move(encoded_message), + + // The repeat count remaining. + repeat_count, + + // A steady timer used for introducing a delay. + delay_timer = std::move(delay_timer), + + // To manage the cycle between the multiple underlying asychronous + // operations, our implementation is a state machine. + state = starting + ] + ( + auto& self, + const std::error_code& error = {}, + std::size_t = 0 + ) mutable + { + if (!error) + { + switch (state) + { + case starting: + case writing: + if (repeat_count > 0) + { + --repeat_count; + state = waiting; + delay_timer->expires_after(std::chrono::seconds(1)); + delay_timer->async_wait(std::move(self)); + return; // Composed operation not yet complete. + } + break; // Composed operation complete, continue below. + case waiting: + state = writing; + asio::async_write(socket, + asio::buffer(*encoded_message), std::move(self)); + return; // Composed operation not yet complete. + } + } + + // This point is reached only on completion of the entire composed + // operation. + + // Deallocate the encoded message and delay timer before calling the + // user-supplied completion handler. + encoded_message.reset(); + delay_timer.reset(); + + // Call the user-supplied handler with the result of the operation. + self.complete(error); + }, + token, socket); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_messages( + socket, "Testing deferred\r\n", 5, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/operations/composed_8.cpp b/3rdparty/asio/src/examples/cpp20/operations/composed_8.cpp new file mode 100644 index 00000000000..2735d74d047 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/operations/composed_8.cpp @@ -0,0 +1,255 @@ +// +// composed_8.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <asio/compose.hpp> +#include <asio/coroutine.hpp> +#include <asio/deferred.hpp> +#include <asio/io_context.hpp> +#include <asio/ip/tcp.hpp> +#include <asio/steady_timer.hpp> +#include <asio/use_future.hpp> +#include <asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using asio::ip::tcp; + +// NOTE: This example requires the new asio::async_compose function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations, +// using asio's stackless coroutines support to express the flow of control. It +// automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +#include <asio/yield.hpp> + +template <typename T, + asio::completion_token_for<void(std::error_code)> CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of: + // + // - the CompletionToken type, + // - the completion handler signature, and + // - the asynchronous operation's initiation function object. + // + // When the completion token is a simple callback, the return type is always + // void. In this example, when the completion token is asio::yield_context + // (used for stackful coroutines) the return type would also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is asio::use_future it would be std::future<void>. When + // the completion token is asio::deferred, the return type differs for each + // asynchronous operation. + // + // In C++20 we can omit the return type as it is automatically deduced from + // the return type of asio::async_compose. +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<asio::steady_timer> delay_timer( + new asio::steady_timer(socket.get_executor())); + + // The asio::async_compose function takes: + // + // - our asynchronous operation implementation, + // - the completion token, + // - the completion handler signature, and + // - any I/O objects (or executors) used by the operation + // + // It then wraps our implementation, which is implemented here as a stackless + // coroutine in a lambda, in an intermediate completion handler that meets the + // requirements of a conforming asynchronous operation. This includes + // tracking outstanding work against the I/O executors associated with the + // operation (in this example, this is the socket's executor). + // + // The first argument to our lambda is a reference to the enclosing + // intermediate completion handler. This intermediate completion handler is + // provided for us by the asio::async_compose function, and takes care + // of all the details required to implement a conforming asynchronous + // operation. When calling an underlying asynchronous operation, we pass it + // this enclosing intermediate completion handler as the completion token. + // + // All arguments to our lambda after the first must be defaulted to allow the + // state machine to be started, as well as to allow the completion handler to + // match the completion signature of both the async_write and + // steady_timer::async_wait operations. + return asio::async_compose< + CompletionToken, void(std::error_code)>( + [ + // The implementation holds a reference to the socket as it is used for + // multiple async_write operations. + &socket, + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our lambda + // implementation is also move-only. + encoded_message = std::move(encoded_message), + + // The repeat count remaining. + repeat_count, + + // A steady timer used for introducing a delay. + delay_timer = std::move(delay_timer), + + // The coroutine state. + coro = asio::coroutine() + ] + ( + auto& self, + const std::error_code& error = {}, + std::size_t = 0 + ) mutable + { + reenter (coro) + { + while (repeat_count > 0) + { + --repeat_count; + + delay_timer->expires_after(std::chrono::seconds(1)); + yield delay_timer->async_wait(std::move(self)); + if (error) + break; + + yield asio::async_write(socket, + asio::buffer(*encoded_message), std::move(self)); + if (error) + break; + } + + // Deallocate the encoded message and delay timer before calling the + // user-supplied completion handler. + encoded_message.reset(); + delay_timer.reset(); + + // Call the user-supplied handler with the result of the operation. + self.complete(error); + } + }, + token, socket); +} + +#include <asio/unyield.hpp> + +//------------------------------------------------------------------------------ + +void test_callback() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_deferred() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the deferred completion token. This + // token causes the operation's initiating function to package up the + // operation with its arguments to return a function object, which may then be + // used to launch the asynchronous operation. + asio::async_operation auto op = async_write_messages( + socket, "Testing deferred\r\n", 5, asio::deferred); + + // Launch the operation using a lambda as a callback. + std::move(op)( + [](const std::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_deferred(); + test_future(); +} diff --git a/3rdparty/asio/src/examples/cpp20/type_erasure/line_reader.hpp b/3rdparty/asio/src/examples/cpp20/type_erasure/line_reader.hpp new file mode 100644 index 00000000000..fa19aec6b13 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/type_erasure/line_reader.hpp @@ -0,0 +1,39 @@ +// +// line_reader.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef LINE_READER_HPP +#define LINE_READER_HPP + +#include <asio/any_completion_handler.hpp> +#include <asio/async_result.hpp> +#include <asio/error.hpp> +#include <string> + +class line_reader +{ +public: + virtual ~line_reader() {} + + template <typename CompletionToken> + auto async_read_line(std::string prompt, CompletionToken&& token) + { + return asio::async_initiate<CompletionToken, void(asio::error_code, std::string)>( + [](auto handler, line_reader* self, std::string prompt) + { + self->async_read_line_impl(std::move(prompt), std::move(handler)); + }, token, this, prompt); + } + +private: + virtual void async_read_line_impl(std::string prompt, + asio::any_completion_handler<void(asio::error_code, std::string)> handler) = 0; +}; + +#endif // LINE_READER_HPP diff --git a/3rdparty/asio/src/examples/cpp20/type_erasure/main.cpp b/3rdparty/asio/src/examples/cpp20/type_erasure/main.cpp new file mode 100644 index 00000000000..1b80dcd23ee --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/type_erasure/main.cpp @@ -0,0 +1,35 @@ +// +// main.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "line_reader.hpp" +#include "sleep.hpp" +#include "stdin_line_reader.hpp" +#include <asio/co_spawn.hpp> +#include <asio/detached.hpp> +#include <asio/io_context.hpp> +#include <asio/use_awaitable.hpp> +#include <iostream> + +asio::awaitable<void> do_read(line_reader& reader) +{ + for (int i = 0; i < 10; ++i) + { + std::cout << co_await reader.async_read_line("Enter something: ", asio::use_awaitable); + co_await async_sleep(co_await asio::this_coro::executor, std::chrono::seconds(1), asio::use_awaitable); + } +} + +int main() +{ + asio::io_context ctx{1}; + stdin_line_reader reader{ctx.get_executor()}; + co_spawn(ctx, do_read(reader), asio::detached); + ctx.run(); +} diff --git a/3rdparty/asio/src/examples/cpp20/type_erasure/sleep.cpp b/3rdparty/asio/src/examples/cpp20/type_erasure/sleep.cpp new file mode 100644 index 00000000000..b605866ebd7 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/type_erasure/sleep.cpp @@ -0,0 +1,22 @@ +// +// sleep.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "sleep.hpp" +#include <asio/consign.hpp> +#include <asio/steady_timer.hpp> +#include <memory> + +void async_sleep_impl( + asio::any_completion_handler<void(std::error_code)> handler, + asio::any_io_executor ex, std::chrono::nanoseconds duration) +{ + auto timer = std::make_shared<asio::steady_timer>(ex, duration); + timer->async_wait(asio::consign(std::move(handler), timer)); +} diff --git a/3rdparty/asio/src/examples/cpp20/type_erasure/sleep.hpp b/3rdparty/asio/src/examples/cpp20/type_erasure/sleep.hpp new file mode 100644 index 00000000000..7e057fc5862 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/type_erasure/sleep.hpp @@ -0,0 +1,32 @@ +// +// sleep.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SLEEP_HPP +#define SLEEP_HPP + +#include <asio/any_completion_handler.hpp> +#include <asio/any_io_executor.hpp> +#include <asio/async_result.hpp> +#include <asio/error.hpp> +#include <chrono> + +void async_sleep_impl( + asio::any_completion_handler<void(std::error_code)> handler, + asio::any_io_executor ex, std::chrono::nanoseconds duration); + +template <typename CompletionToken> +inline auto async_sleep(asio::any_io_executor ex, + std::chrono::nanoseconds duration, CompletionToken&& token) +{ + return asio::async_initiate<CompletionToken, void(std::error_code)>( + async_sleep_impl, token, std::move(ex), duration); +} + +#endif // SLEEP_HPP diff --git a/3rdparty/asio/src/examples/cpp20/type_erasure/stdin_line_reader.cpp b/3rdparty/asio/src/examples/cpp20/type_erasure/stdin_line_reader.cpp new file mode 100644 index 00000000000..7467e820e7a --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/type_erasure/stdin_line_reader.cpp @@ -0,0 +1,44 @@ +// +// stdin_line_reader.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "stdin_line_reader.hpp" +#include <asio/deferred.hpp> +#include <asio/read_until.hpp> +#include <iostream> + +stdin_line_reader::stdin_line_reader(asio::any_io_executor ex) + : stdin_(ex, ::dup(STDIN_FILENO)) +{ +} + +void stdin_line_reader::async_read_line_impl(std::string prompt, + asio::any_completion_handler<void(asio::error_code, std::string)> handler) +{ + std::cout << prompt; + std::cout.flush(); + + asio::async_read_until(stdin_, asio::dynamic_buffer(buffer_), '\n', + asio::deferred( + [this](asio::error_code ec, std::size_t n) + { + if (!ec) + { + std::string result = buffer_.substr(0, n); + buffer_.erase(0, n); + return asio::deferred.values(ec, std::move(result)); + } + else + { + return asio::deferred.values(ec, std::string{}); + } + } + ) + )(std::move(handler)); +} diff --git a/3rdparty/asio/src/examples/cpp20/type_erasure/stdin_line_reader.hpp b/3rdparty/asio/src/examples/cpp20/type_erasure/stdin_line_reader.hpp new file mode 100644 index 00000000000..fd54f707da0 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp20/type_erasure/stdin_line_reader.hpp @@ -0,0 +1,30 @@ +// +// stdin_line_reader.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef STDIN_LINE_READER_HPP +#define STDIN_LINE_READER_HPP + +#include "line_reader.hpp" +#include <asio/posix/stream_descriptor.hpp> + +class stdin_line_reader : public line_reader +{ +public: + explicit stdin_line_reader(asio::any_io_executor ex); + +private: + void async_read_line_impl(std::string prompt, + asio::any_completion_handler<void(asio::error_code, std::string)> handler) override; + + asio::posix::stream_descriptor stdin_; + std::string buffer_; +}; + +#endif |